kscale 0.0.11__py3-none-any.whl → 0.1.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- kscale/__init__.py +2 -2
- kscale/api.py +3 -6
- kscale/cli.py +32 -0
- kscale/conf.py +6 -3
- kscale/requirements.txt +17 -1
- kscale/utils/checksum.py +41 -0
- kscale/utils/cli.py +28 -0
- kscale/web/api.py +14 -0
- kscale/web/cli/robot.py +100 -0
- kscale/web/cli/robot_class.py +113 -0
- kscale/web/cli/token.py +33 -0
- kscale/web/cli/user.py +33 -0
- kscale/web/clients/__init__.py +0 -0
- kscale/web/clients/base.py +314 -0
- kscale/web/clients/client.py +11 -0
- kscale/web/clients/robot.py +39 -0
- kscale/web/clients/robot_class.py +114 -0
- kscale/web/clients/user.py +10 -0
- kscale/web/gen/__init__.py +0 -0
- kscale/web/gen/api.py +73 -0
- kscale/web/utils.py +31 -0
- {kscale-0.0.11.dist-info → kscale-0.1.0.dist-info}/METADATA +29 -48
- kscale-0.1.0.dist-info/RECORD +36 -0
- {kscale-0.0.11.dist-info → kscale-0.1.0.dist-info}/WHEEL +1 -1
- kscale-0.1.0.dist-info/entry_points.txt +3 -0
- kscale/store/api.py +0 -64
- kscale/store/cli.py +0 -35
- kscale/store/client.py +0 -82
- kscale/store/gen/api.py +0 -397
- kscale/store/pybullet.py +0 -180
- kscale/store/urdf.py +0 -193
- kscale/store/utils.py +0 -33
- kscale-0.0.11.dist-info/RECORD +0 -26
- kscale-0.0.11.dist-info/entry_points.txt +0 -2
- /kscale/{store → web}/__init__.py +0 -0
- /kscale/{store/gen → web/cli}/__init__.py +0 -0
- {kscale-0.0.11.dist-info → kscale-0.1.0.dist-info}/LICENSE +0 -0
- {kscale-0.0.11.dist-info → kscale-0.1.0.dist-info}/top_level.txt +0 -0
kscale/store/gen/api.py
DELETED
@@ -1,397 +0,0 @@
|
|
1
|
-
"""Auto-generated by generate.sh script."""
|
2
|
-
|
3
|
-
# generated by datamodel-codegen:
|
4
|
-
# filename: openapi.json
|
5
|
-
# timestamp: 2024-10-23T08:09:02+00:00
|
6
|
-
|
7
|
-
from __future__ import annotations
|
8
|
-
|
9
|
-
from enum import Enum
|
10
|
-
from typing import Dict, List, Optional, Union
|
11
|
-
|
12
|
-
from pydantic import BaseModel, EmailStr, Field
|
13
|
-
|
14
|
-
|
15
|
-
class ArtifactUrls(BaseModel):
|
16
|
-
small: Optional[str] = Field(None, title="Small")
|
17
|
-
large: str = Field(..., title="Large")
|
18
|
-
|
19
|
-
|
20
|
-
class AuthResponse(BaseModel):
|
21
|
-
api_key: str = Field(..., title="Api Key")
|
22
|
-
|
23
|
-
|
24
|
-
class BodyPullOnshapeDocumentOnshapePullListingIdGet(BaseModel):
|
25
|
-
suffix_to_joint_effort: Optional[Dict[str, float]] = Field(None, title="Suffix To Joint Effort")
|
26
|
-
suffix_to_joint_velocity: Optional[Dict[str, float]] = Field(None, title="Suffix To Joint Velocity")
|
27
|
-
|
28
|
-
|
29
|
-
class BodyUploadArtifactsUploadListingIdPost(BaseModel):
|
30
|
-
files: List[bytes] = Field(..., title="Files")
|
31
|
-
|
32
|
-
|
33
|
-
class ClientIdResponse(BaseModel):
|
34
|
-
client_id: str = Field(..., title="Client Id")
|
35
|
-
|
36
|
-
|
37
|
-
class CreateCheckoutSessionRequest(BaseModel):
|
38
|
-
product_id: str = Field(..., title="Product Id")
|
39
|
-
cancel_url: str = Field(..., title="Cancel Url")
|
40
|
-
|
41
|
-
|
42
|
-
class CreateCheckoutSessionResponse(BaseModel):
|
43
|
-
session_id: str = Field(..., title="Session Id")
|
44
|
-
|
45
|
-
|
46
|
-
class DeleteTokenResponse(BaseModel):
|
47
|
-
message: str = Field(..., title="Message")
|
48
|
-
|
49
|
-
|
50
|
-
class EmailSignUpRequest(BaseModel):
|
51
|
-
email: EmailStr = Field(..., title="Email")
|
52
|
-
|
53
|
-
|
54
|
-
class EmailSignUpResponse(BaseModel):
|
55
|
-
message: str = Field(..., title="Message")
|
56
|
-
|
57
|
-
|
58
|
-
class GetListingResponse(BaseModel):
|
59
|
-
id: str = Field(..., title="Id")
|
60
|
-
name: str = Field(..., title="Name")
|
61
|
-
description: Optional[str] = Field(..., title="Description")
|
62
|
-
child_ids: List[str] = Field(..., title="Child Ids")
|
63
|
-
tags: List[str] = Field(..., title="Tags")
|
64
|
-
onshape_url: Optional[str] = Field(..., title="Onshape Url")
|
65
|
-
can_edit: bool = Field(..., title="Can Edit")
|
66
|
-
created_at: int = Field(..., title="Created At")
|
67
|
-
views: int = Field(..., title="Views")
|
68
|
-
score: int = Field(..., title="Score")
|
69
|
-
user_vote: Optional[bool] = Field(..., title="User Vote")
|
70
|
-
creator_id: str = Field(..., title="Creator Id")
|
71
|
-
creator_name: Optional[str] = Field(..., title="Creator Name")
|
72
|
-
|
73
|
-
|
74
|
-
class GetTokenResponse(BaseModel):
|
75
|
-
id: str = Field(..., title="Id")
|
76
|
-
email: str = Field(..., title="Email")
|
77
|
-
|
78
|
-
|
79
|
-
class GithubAuthRequest(BaseModel):
|
80
|
-
code: str = Field(..., title="Code")
|
81
|
-
|
82
|
-
|
83
|
-
class GithubAuthResponse(BaseModel):
|
84
|
-
api_key: str = Field(..., title="Api Key")
|
85
|
-
|
86
|
-
|
87
|
-
class GoogleLogin(BaseModel):
|
88
|
-
token: str = Field(..., title="Token")
|
89
|
-
|
90
|
-
|
91
|
-
class KernelImageResponse(BaseModel):
|
92
|
-
id: str = Field(..., title="Id")
|
93
|
-
user_id: str = Field(..., title="User Id")
|
94
|
-
name: str = Field(..., title="Name")
|
95
|
-
description: Optional[str] = Field(..., title="Description")
|
96
|
-
size: int = Field(..., title="Size")
|
97
|
-
timestamp: int = Field(..., title="Timestamp")
|
98
|
-
is_public: bool = Field(..., title="Is Public")
|
99
|
-
is_official: bool = Field(..., title="Is Official")
|
100
|
-
downloads: int = Field(..., title="Downloads")
|
101
|
-
|
102
|
-
|
103
|
-
class KernelImageUploadRequest(BaseModel):
|
104
|
-
name: str = Field(..., title="Name")
|
105
|
-
file: str = Field(..., title="File")
|
106
|
-
is_public: bool = Field(..., title="Is Public")
|
107
|
-
is_official: bool = Field(..., title="Is Official")
|
108
|
-
description: Optional[str] = Field(None, title="Description")
|
109
|
-
|
110
|
-
|
111
|
-
class Permission(Enum):
|
112
|
-
read = "read"
|
113
|
-
write = "write"
|
114
|
-
admin = "admin"
|
115
|
-
|
116
|
-
|
117
|
-
class KeysResponseItem(BaseModel):
|
118
|
-
token: str = Field(..., title="Token")
|
119
|
-
permissions: Optional[List[Permission]] = Field(..., title="Permissions")
|
120
|
-
|
121
|
-
|
122
|
-
class ListKeysResponse(BaseModel):
|
123
|
-
keys: List[KeysResponseItem] = Field(..., title="Keys")
|
124
|
-
|
125
|
-
|
126
|
-
class ListListingsResponse(BaseModel):
|
127
|
-
listing_ids: List[str] = Field(..., title="Listing Ids")
|
128
|
-
has_next: Optional[bool] = Field(False, title="Has Next")
|
129
|
-
|
130
|
-
|
131
|
-
class Listing(BaseModel):
|
132
|
-
id: str = Field(..., title="Id")
|
133
|
-
user_id: str = Field(..., title="User Id")
|
134
|
-
created_at: int = Field(..., title="Created At")
|
135
|
-
updated_at: int = Field(..., title="Updated At")
|
136
|
-
name: str = Field(..., title="Name")
|
137
|
-
child_ids: List[str] = Field(..., title="Child Ids")
|
138
|
-
description: Optional[str] = Field(None, title="Description")
|
139
|
-
onshape_url: Optional[str] = Field(None, title="Onshape Url")
|
140
|
-
views: Optional[int] = Field(0, title="Views")
|
141
|
-
upvotes: Optional[int] = Field(0, title="Upvotes")
|
142
|
-
downvotes: Optional[int] = Field(0, title="Downvotes")
|
143
|
-
score: Optional[int] = Field(0, title="Score")
|
144
|
-
|
145
|
-
|
146
|
-
class ListingInfoResponse(BaseModel):
|
147
|
-
id: str = Field(..., title="Id")
|
148
|
-
name: str = Field(..., title="Name")
|
149
|
-
description: Optional[str] = Field(..., title="Description")
|
150
|
-
child_ids: List[str] = Field(..., title="Child Ids")
|
151
|
-
image_url: Optional[str] = Field(..., title="Image Url")
|
152
|
-
onshape_url: Optional[str] = Field(..., title="Onshape Url")
|
153
|
-
created_at: int = Field(..., title="Created At")
|
154
|
-
views: int = Field(..., title="Views")
|
155
|
-
score: int = Field(..., title="Score")
|
156
|
-
user_vote: Optional[bool] = Field(..., title="User Vote")
|
157
|
-
|
158
|
-
|
159
|
-
class LoginRequest(BaseModel):
|
160
|
-
email: EmailStr = Field(..., title="Email")
|
161
|
-
password: str = Field(..., title="Password")
|
162
|
-
|
163
|
-
|
164
|
-
class LoginResponse(BaseModel):
|
165
|
-
user_id: str = Field(..., title="User Id")
|
166
|
-
token: str = Field(..., title="Token")
|
167
|
-
|
168
|
-
|
169
|
-
class Permission1(Enum):
|
170
|
-
is_admin = "is_admin"
|
171
|
-
is_mod = "is_mod"
|
172
|
-
|
173
|
-
|
174
|
-
class MyUserInfoResponse(BaseModel):
|
175
|
-
user_id: str = Field(..., title="User Id")
|
176
|
-
email: str = Field(..., title="Email")
|
177
|
-
github_id: Optional[str] = Field(..., title="Github Id")
|
178
|
-
google_id: Optional[str] = Field(..., title="Google Id")
|
179
|
-
permissions: Optional[List[Permission1]] = Field(..., title="Permissions")
|
180
|
-
first_name: Optional[str] = Field(..., title="First Name")
|
181
|
-
last_name: Optional[str] = Field(..., title="Last Name")
|
182
|
-
name: Optional[str] = Field(..., title="Name")
|
183
|
-
bio: Optional[str] = Field(..., title="Bio")
|
184
|
-
|
185
|
-
|
186
|
-
class NewKeyRequest(BaseModel):
|
187
|
-
readonly: Optional[bool] = Field(True, title="Readonly")
|
188
|
-
|
189
|
-
|
190
|
-
class NewKeyResponse(BaseModel):
|
191
|
-
user_id: str = Field(..., title="User Id")
|
192
|
-
key: KeysResponseItem
|
193
|
-
|
194
|
-
|
195
|
-
class NewListingRequest(BaseModel):
|
196
|
-
name: str = Field(..., title="Name")
|
197
|
-
child_ids: List[str] = Field(..., title="Child Ids")
|
198
|
-
description: Optional[str] = Field(..., title="Description")
|
199
|
-
|
200
|
-
|
201
|
-
class NewListingResponse(BaseModel):
|
202
|
-
listing_id: str = Field(..., title="Listing Id")
|
203
|
-
|
204
|
-
|
205
|
-
class Status(Enum):
|
206
|
-
processing = "processing"
|
207
|
-
in_development = "in_development"
|
208
|
-
being_assembled = "being_assembled"
|
209
|
-
shipped = "shipped"
|
210
|
-
delivered = "delivered"
|
211
|
-
cancelled = "cancelled"
|
212
|
-
refunded = "refunded"
|
213
|
-
failed = "failed"
|
214
|
-
|
215
|
-
|
216
|
-
class Order(BaseModel):
|
217
|
-
id: str = Field(..., title="Id")
|
218
|
-
user_id: str = Field(..., title="User Id")
|
219
|
-
user_email: str = Field(..., title="User Email")
|
220
|
-
stripe_checkout_session_id: str = Field(..., title="Stripe Checkout Session Id")
|
221
|
-
stripe_payment_intent_id: str = Field(..., title="Stripe Payment Intent Id")
|
222
|
-
created_at: int = Field(..., title="Created At")
|
223
|
-
updated_at: int = Field(..., title="Updated At")
|
224
|
-
status: Status = Field(..., title="Status")
|
225
|
-
amount: int = Field(..., title="Amount")
|
226
|
-
currency: str = Field(..., title="Currency")
|
227
|
-
quantity: int = Field(..., title="Quantity")
|
228
|
-
product_id: Optional[str] = Field(None, title="Product Id")
|
229
|
-
shipping_name: Optional[str] = Field(None, title="Shipping Name")
|
230
|
-
shipping_address_line1: Optional[str] = Field(None, title="Shipping Address Line1")
|
231
|
-
shipping_address_line2: Optional[str] = Field(None, title="Shipping Address Line2")
|
232
|
-
shipping_city: Optional[str] = Field(None, title="Shipping City")
|
233
|
-
shipping_state: Optional[str] = Field(None, title="Shipping State")
|
234
|
-
shipping_postal_code: Optional[str] = Field(None, title="Shipping Postal Code")
|
235
|
-
shipping_country: Optional[str] = Field(None, title="Shipping Country")
|
236
|
-
|
237
|
-
|
238
|
-
class ProductInfo(BaseModel):
|
239
|
-
id: str = Field(..., title="Id")
|
240
|
-
name: str = Field(..., title="Name")
|
241
|
-
description: Optional[str] = Field(..., title="Description")
|
242
|
-
images: List[str] = Field(..., title="Images")
|
243
|
-
metadata: Dict[str, str] = Field(..., title="Metadata")
|
244
|
-
|
245
|
-
|
246
|
-
class PublicUserInfoResponseItem(BaseModel):
|
247
|
-
id: str = Field(..., title="Id")
|
248
|
-
email: str = Field(..., title="Email")
|
249
|
-
permissions: Optional[List[Permission1]] = Field(None, title="Permissions")
|
250
|
-
created_at: Optional[int] = Field(None, title="Created At")
|
251
|
-
updated_at: Optional[int] = Field(None, title="Updated At")
|
252
|
-
first_name: Optional[str] = Field(None, title="First Name")
|
253
|
-
last_name: Optional[str] = Field(None, title="Last Name")
|
254
|
-
name: Optional[str] = Field(None, title="Name")
|
255
|
-
bio: Optional[str] = Field(None, title="Bio")
|
256
|
-
|
257
|
-
|
258
|
-
class PublicUsersInfoResponse(BaseModel):
|
259
|
-
users: List[PublicUserInfoResponseItem] = Field(..., title="Users")
|
260
|
-
|
261
|
-
|
262
|
-
class SetModeratorRequest(BaseModel):
|
263
|
-
user_id: str = Field(..., title="User Id")
|
264
|
-
is_mod: bool = Field(..., title="Is Mod")
|
265
|
-
|
266
|
-
|
267
|
-
class SetRequest(BaseModel):
|
268
|
-
onshape_url: Optional[str] = Field(..., title="Onshape Url")
|
269
|
-
|
270
|
-
|
271
|
-
class ArtifactType(Enum):
|
272
|
-
image = "image"
|
273
|
-
|
274
|
-
|
275
|
-
class ArtifactType1(Enum):
|
276
|
-
urdf = "urdf"
|
277
|
-
mjcf = "mjcf"
|
278
|
-
|
279
|
-
|
280
|
-
class ArtifactType2(Enum):
|
281
|
-
stl = "stl"
|
282
|
-
obj = "obj"
|
283
|
-
dae = "dae"
|
284
|
-
ply = "ply"
|
285
|
-
|
286
|
-
|
287
|
-
class ArtifactType3(Enum):
|
288
|
-
tgz = "tgz"
|
289
|
-
zip = "zip"
|
290
|
-
|
291
|
-
|
292
|
-
class SingleArtifactResponse(BaseModel):
|
293
|
-
artifact_id: str = Field(..., title="Artifact Id")
|
294
|
-
listing_id: str = Field(..., title="Listing Id")
|
295
|
-
name: str = Field(..., title="Name")
|
296
|
-
artifact_type: Union[ArtifactType, ArtifactType1, ArtifactType2, ArtifactType3] = Field(..., title="Artifact Type")
|
297
|
-
description: Optional[str] = Field(..., title="Description")
|
298
|
-
timestamp: int = Field(..., title="Timestamp")
|
299
|
-
urls: ArtifactUrls
|
300
|
-
|
301
|
-
|
302
|
-
class SortOption(Enum):
|
303
|
-
newest = "newest"
|
304
|
-
most_viewed = "most_viewed"
|
305
|
-
most_upvoted = "most_upvoted"
|
306
|
-
|
307
|
-
|
308
|
-
class UpdateArtifactRequest(BaseModel):
|
309
|
-
name: Optional[str] = Field(None, title="Name")
|
310
|
-
description: Optional[str] = Field(None, title="Description")
|
311
|
-
|
312
|
-
|
313
|
-
class UpdateListingRequest(BaseModel):
|
314
|
-
name: Optional[str] = Field(None, title="Name")
|
315
|
-
child_ids: Optional[List[str]] = Field(None, title="Child Ids")
|
316
|
-
description: Optional[str] = Field(None, title="Description")
|
317
|
-
tags: Optional[List[str]] = Field(None, title="Tags")
|
318
|
-
|
319
|
-
|
320
|
-
class UpdateOrderAddressRequest(BaseModel):
|
321
|
-
shipping_name: str = Field(..., title="Shipping Name")
|
322
|
-
shipping_address_line1: str = Field(..., title="Shipping Address Line1")
|
323
|
-
shipping_address_line2: Optional[str] = Field(..., title="Shipping Address Line2")
|
324
|
-
shipping_city: str = Field(..., title="Shipping City")
|
325
|
-
shipping_state: str = Field(..., title="Shipping State")
|
326
|
-
shipping_postal_code: str = Field(..., title="Shipping Postal Code")
|
327
|
-
shipping_country: str = Field(..., title="Shipping Country")
|
328
|
-
|
329
|
-
|
330
|
-
class UpdateUserRequest(BaseModel):
|
331
|
-
email: Optional[str] = Field(None, title="Email")
|
332
|
-
password: Optional[str] = Field(None, title="Password")
|
333
|
-
github_id: Optional[str] = Field(None, title="Github Id")
|
334
|
-
google_id: Optional[str] = Field(None, title="Google Id")
|
335
|
-
first_name: Optional[str] = Field(None, title="First Name")
|
336
|
-
last_name: Optional[str] = Field(None, title="Last Name")
|
337
|
-
name: Optional[str] = Field(None, title="Name")
|
338
|
-
bio: Optional[str] = Field(None, title="Bio")
|
339
|
-
|
340
|
-
|
341
|
-
class UploadArtifactResponse(BaseModel):
|
342
|
-
artifacts: List[SingleArtifactResponse] = Field(..., title="Artifacts")
|
343
|
-
|
344
|
-
|
345
|
-
class UpvotedListingsResponse(BaseModel):
|
346
|
-
upvoted_listing_ids: List[str] = Field(..., title="Upvoted Listing Ids")
|
347
|
-
has_more: bool = Field(..., title="Has More")
|
348
|
-
|
349
|
-
|
350
|
-
class UserInfoResponseItem(BaseModel):
|
351
|
-
id: str = Field(..., title="Id")
|
352
|
-
email: str = Field(..., title="Email")
|
353
|
-
|
354
|
-
|
355
|
-
class UserPublic(BaseModel):
|
356
|
-
id: str = Field(..., title="Id")
|
357
|
-
email: str = Field(..., title="Email")
|
358
|
-
permissions: Optional[List[Permission1]] = Field(None, title="Permissions")
|
359
|
-
created_at: int = Field(..., title="Created At")
|
360
|
-
updated_at: Optional[int] = Field(None, title="Updated At")
|
361
|
-
first_name: Optional[str] = Field(None, title="First Name")
|
362
|
-
last_name: Optional[str] = Field(None, title="Last Name")
|
363
|
-
name: Optional[str] = Field(None, title="Name")
|
364
|
-
bio: Optional[str] = Field(None, title="Bio")
|
365
|
-
|
366
|
-
|
367
|
-
class UserSignup(BaseModel):
|
368
|
-
signup_token_id: str = Field(..., title="Signup Token Id")
|
369
|
-
email: str = Field(..., title="Email")
|
370
|
-
password: str = Field(..., title="Password")
|
371
|
-
|
372
|
-
|
373
|
-
class ValidationError(BaseModel):
|
374
|
-
loc: List[Union[str, int]] = Field(..., title="Location")
|
375
|
-
msg: str = Field(..., title="Message")
|
376
|
-
type: str = Field(..., title="Error Type")
|
377
|
-
|
378
|
-
|
379
|
-
class DumpListingsResponse(BaseModel):
|
380
|
-
listings: List[Listing] = Field(..., title="Listings")
|
381
|
-
|
382
|
-
|
383
|
-
class GetBatchListingsResponse(BaseModel):
|
384
|
-
listings: List[ListingInfoResponse] = Field(..., title="Listings")
|
385
|
-
|
386
|
-
|
387
|
-
class HTTPValidationError(BaseModel):
|
388
|
-
detail: Optional[List[ValidationError]] = Field(None, title="Detail")
|
389
|
-
|
390
|
-
|
391
|
-
class ListArtifactsResponse(BaseModel):
|
392
|
-
artifacts: List[SingleArtifactResponse] = Field(..., title="Artifacts")
|
393
|
-
|
394
|
-
|
395
|
-
class OrderWithProduct(BaseModel):
|
396
|
-
order: Order
|
397
|
-
product: ProductInfo
|
kscale/store/pybullet.py
DELETED
@@ -1,180 +0,0 @@
|
|
1
|
-
"""Simple script to interact with a URDF in PyBullet."""
|
2
|
-
|
3
|
-
import argparse
|
4
|
-
import asyncio
|
5
|
-
import itertools
|
6
|
-
import logging
|
7
|
-
import math
|
8
|
-
import time
|
9
|
-
from typing import Sequence
|
10
|
-
|
11
|
-
from kscale.artifacts import PLANE_URDF_PATH
|
12
|
-
from kscale.store.urdf import download_urdf
|
13
|
-
|
14
|
-
logger = logging.getLogger(__name__)
|
15
|
-
|
16
|
-
|
17
|
-
async def main(args: Sequence[str] | None = None) -> None:
|
18
|
-
parser = argparse.ArgumentParser(description="Show a URDF in PyBullet")
|
19
|
-
parser.add_argument("listing_id", help="Listing ID for the URDF")
|
20
|
-
parser.add_argument("--dt", type=float, default=0.01, help="Time step")
|
21
|
-
parser.add_argument("-n", "--hide-gui", action="store_true", help="Hide the GUI")
|
22
|
-
parser.add_argument("--no-merge", action="store_true", help="Do not merge fixed links")
|
23
|
-
parser.add_argument("--hide-origin", action="store_true", help="Do not show the origin")
|
24
|
-
parser.add_argument("--show-inertia", action="store_true", help="Visualizes the inertia frames")
|
25
|
-
parser.add_argument("--see-thru", action="store_true", help="Use see-through mode")
|
26
|
-
parser.add_argument("--show-collision", action="store_true", help="Show collision meshes")
|
27
|
-
parsed_args = parser.parse_args(args)
|
28
|
-
|
29
|
-
# Gets the URDF path.
|
30
|
-
urdf_dir = await download_urdf(parsed_args.listing_id)
|
31
|
-
urdf_path = next(urdf_dir.glob("*.urdf"), None)
|
32
|
-
if urdf_path is None:
|
33
|
-
raise ValueError(f"No URDF found in {urdf_dir}")
|
34
|
-
|
35
|
-
try:
|
36
|
-
import pybullet as p # type: ignore[import-not-found]
|
37
|
-
except ImportError:
|
38
|
-
raise ImportError("pybullet is required to run this script")
|
39
|
-
|
40
|
-
# Connect to PyBullet.
|
41
|
-
p.connect(p.GUI)
|
42
|
-
p.setGravity(0, 0, -9.81)
|
43
|
-
p.setRealTimeSimulation(0)
|
44
|
-
|
45
|
-
# Turn off panels.
|
46
|
-
if parsed_args.hide_gui:
|
47
|
-
p.configureDebugVisualizer(p.COV_ENABLE_GUI, 0)
|
48
|
-
p.configureDebugVisualizer(p.COV_ENABLE_SEGMENTATION_MARK_PREVIEW, 0)
|
49
|
-
p.configureDebugVisualizer(p.COV_ENABLE_DEPTH_BUFFER_PREVIEW, 0)
|
50
|
-
p.configureDebugVisualizer(p.COV_ENABLE_RGB_BUFFER_PREVIEW, 0)
|
51
|
-
|
52
|
-
# Enable mouse picking.
|
53
|
-
p.configureDebugVisualizer(p.COV_ENABLE_MOUSE_PICKING, 1)
|
54
|
-
|
55
|
-
# Loads the floor plane.
|
56
|
-
floor = p.loadURDF(str(PLANE_URDF_PATH))
|
57
|
-
|
58
|
-
# Load the robot URDF.
|
59
|
-
start_position = [0.0, 0.0, 1.0]
|
60
|
-
start_orientation = p.getQuaternionFromEuler([0.0, 0.0, 0.0])
|
61
|
-
flags = p.URDF_USE_INERTIA_FROM_FILE
|
62
|
-
if not parsed_args.no_merge:
|
63
|
-
flags |= p.URDF_MERGE_FIXED_LINKS
|
64
|
-
robot = p.loadURDF(str(urdf_path), start_position, start_orientation, flags=flags, useFixedBase=0)
|
65
|
-
|
66
|
-
# Display collision meshes as separate object.
|
67
|
-
if parsed_args.show_collision:
|
68
|
-
collision_flags = p.URDF_USE_INERTIA_FROM_FILE | p.URDF_USE_SELF_COLLISION_EXCLUDE_ALL_PARENTS
|
69
|
-
collision = p.loadURDF(str(urdf_path), start_position, start_orientation, flags=collision_flags, useFixedBase=0)
|
70
|
-
|
71
|
-
# Make collision shapes semi-transparent.
|
72
|
-
joint_ids = [i for i in range(p.getNumJoints(collision))] + [-1]
|
73
|
-
for i in joint_ids:
|
74
|
-
p.changeVisualShape(collision, i, rgbaColor=[1, 0, 0, 0.5])
|
75
|
-
|
76
|
-
# Initializes physics parameters.
|
77
|
-
p.changeDynamics(floor, -1, lateralFriction=1, spinningFriction=-1, rollingFriction=-1)
|
78
|
-
p.setPhysicsEngineParameter(fixedTimeStep=parsed_args.dt, maxNumCmdPer1ms=1000)
|
79
|
-
|
80
|
-
# Shows the origin of the robot.
|
81
|
-
if not parsed_args.hide_origin:
|
82
|
-
p.addUserDebugLine([0, 0, 0], [0.1, 0, 0], [1, 0, 0], parentObjectUniqueId=robot, parentLinkIndex=-1)
|
83
|
-
p.addUserDebugLine([0, 0, 0], [0, 0.1, 0], [0, 1, 0], parentObjectUniqueId=robot, parentLinkIndex=-1)
|
84
|
-
p.addUserDebugLine([0, 0, 0], [0, 0, 0.1], [0, 0, 1], parentObjectUniqueId=robot, parentLinkIndex=-1)
|
85
|
-
|
86
|
-
# Make the robot see-through.
|
87
|
-
joint_ids = [i for i in range(p.getNumJoints(robot))] + [-1]
|
88
|
-
if parsed_args.see_thru:
|
89
|
-
for i in joint_ids:
|
90
|
-
p.changeVisualShape(robot, i, rgbaColor=[1, 1, 1, 0.5])
|
91
|
-
|
92
|
-
def draw_box(pt: list[list[float]], color: tuple[float, float, float], obj_id: int, link_id: int) -> None:
|
93
|
-
assert len(pt) == 8
|
94
|
-
assert all(len(p) == 3 for p in pt)
|
95
|
-
|
96
|
-
mapping = [1, 3, 0, 2]
|
97
|
-
for i in range(4):
|
98
|
-
p.addUserDebugLine(pt[i], pt[i + 4], color, 1, parentObjectUniqueId=obj_id, parentLinkIndex=link_id)
|
99
|
-
p.addUserDebugLine(pt[i], pt[mapping[i]], color, 1, parentObjectUniqueId=obj_id, parentLinkIndex=link_id)
|
100
|
-
p.addUserDebugLine(
|
101
|
-
pt[i + 4], pt[mapping[i] + 4], color, 1, parentObjectUniqueId=obj_id, parentLinkIndex=link_id
|
102
|
-
)
|
103
|
-
|
104
|
-
# Shows bounding boxes around each part of the robot representing the inertia frame.
|
105
|
-
if parsed_args.show_inertia:
|
106
|
-
for i in joint_ids:
|
107
|
-
dynamics_info = p.getDynamicsInfo(robot, i)
|
108
|
-
mass = dynamics_info[0]
|
109
|
-
if mass <= 0:
|
110
|
-
continue
|
111
|
-
inertia = dynamics_info[2]
|
112
|
-
ixx = inertia[0]
|
113
|
-
iyy = inertia[1]
|
114
|
-
izz = inertia[2]
|
115
|
-
box_scale_x = 0.5 * math.sqrt(6 * (izz + iyy - ixx) / mass)
|
116
|
-
box_scale_y = 0.5 * math.sqrt(6 * (izz + ixx - iyy) / mass)
|
117
|
-
box_scale_z = 0.5 * math.sqrt(6 * (ixx + iyy - izz) / mass)
|
118
|
-
|
119
|
-
half_extents = [box_scale_x, box_scale_y, box_scale_z]
|
120
|
-
pt = [
|
121
|
-
[x, y, z]
|
122
|
-
for x, y, z in itertools.product(
|
123
|
-
[-half_extents[0], half_extents[0]],
|
124
|
-
[-half_extents[1], half_extents[1]],
|
125
|
-
[-half_extents[2], half_extents[2]],
|
126
|
-
)
|
127
|
-
]
|
128
|
-
draw_box(pt, (1, 0, 0), robot, i)
|
129
|
-
|
130
|
-
# Show joint controller.
|
131
|
-
joints: dict[str, int] = {}
|
132
|
-
controls: dict[str, float] = {}
|
133
|
-
for i in range(p.getNumJoints(robot)):
|
134
|
-
joint_info = p.getJointInfo(robot, i)
|
135
|
-
name = joint_info[1].decode("utf-8")
|
136
|
-
joint_type = joint_info[2]
|
137
|
-
joints[name] = i
|
138
|
-
if joint_type == p.JOINT_PRISMATIC:
|
139
|
-
joint_min, joint_max = joint_info[8:10]
|
140
|
-
controls[name] = p.addUserDebugParameter(name, joint_min, joint_max, 0.0)
|
141
|
-
elif joint_type == p.JOINT_REVOLUTE:
|
142
|
-
joint_min, joint_max = joint_info[8:10]
|
143
|
-
controls[name] = p.addUserDebugParameter(name, joint_min, joint_max, 0.0)
|
144
|
-
|
145
|
-
# Run the simulation until the user closes the window.
|
146
|
-
last_time = time.time()
|
147
|
-
prev_control_values = {k: 0.0 for k in controls}
|
148
|
-
while p.isConnected():
|
149
|
-
# Reset the simulation if "r" was pressed.
|
150
|
-
keys = p.getKeyboardEvents()
|
151
|
-
if ord("r") in keys and keys[ord("r")] & p.KEY_WAS_TRIGGERED:
|
152
|
-
p.resetBasePositionAndOrientation(robot, start_position, start_orientation)
|
153
|
-
p.setJointMotorControlArray(
|
154
|
-
robot,
|
155
|
-
range(p.getNumJoints(robot)),
|
156
|
-
p.POSITION_CONTROL,
|
157
|
-
targetPositions=[0] * p.getNumJoints(robot),
|
158
|
-
)
|
159
|
-
|
160
|
-
# Set joint positions.
|
161
|
-
for k, v in controls.items():
|
162
|
-
try:
|
163
|
-
target_position = p.readUserDebugParameter(v)
|
164
|
-
if target_position != prev_control_values[k]:
|
165
|
-
prev_control_values[k] = target_position
|
166
|
-
p.setJointMotorControl2(robot, joints[k], p.POSITION_CONTROL, target_position)
|
167
|
-
except p.error:
|
168
|
-
logger.debug("Failed to set joint %s", k)
|
169
|
-
pass
|
170
|
-
|
171
|
-
# Step simulation.
|
172
|
-
p.stepSimulation()
|
173
|
-
cur_time = time.time()
|
174
|
-
time.sleep(max(0, parsed_args.dt - (cur_time - last_time)))
|
175
|
-
last_time = cur_time
|
176
|
-
|
177
|
-
|
178
|
-
if __name__ == "__main__":
|
179
|
-
# python -m kscale.store.pybullet
|
180
|
-
asyncio.run(main())
|