kscale 0.0.11__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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())
|