bosdyn-client 5.0.1__py3-none-any.whl → 5.0.1.2__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.
- bosdyn/client/audio_visual.py +177 -0
- bosdyn/client/sdk.py +2 -0
- {bosdyn_client-5.0.1.dist-info → bosdyn_client-5.0.1.2.dist-info}/METADATA +3 -3
- {bosdyn_client-5.0.1.dist-info → bosdyn_client-5.0.1.2.dist-info}/RECORD +6 -6
- {bosdyn_client-5.0.1.dist-info → bosdyn_client-5.0.1.2.dist-info}/WHEEL +0 -0
- {bosdyn_client-5.0.1.dist-info → bosdyn_client-5.0.1.2.dist-info}/top_level.txt +0 -0
bosdyn/client/audio_visual.py
CHANGED
|
@@ -145,6 +145,98 @@ class AudioVisualClient(BaseClient):
|
|
|
145
145
|
error_from_response=_stop_behavior_error, copy_request=False,
|
|
146
146
|
**kwargs)
|
|
147
147
|
|
|
148
|
+
def add_or_modify_behavior(self, name, behavior, **kwargs):
|
|
149
|
+
"""Add or modify an AudioVisualBehavior.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
name: The name of the behavior to add.
|
|
153
|
+
behavior: The AudioVisualBehavior proto to add.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
The LiveAudioVisualBehavior proto that was just added or modified.
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
RpcError: Problem communicating with the robot.
|
|
160
|
+
PermanentBehaviorError: The behavior specified is permanent and cannot be modified.
|
|
161
|
+
InvalidBehaviorError: The request contained a behavior with invalid fields.
|
|
162
|
+
"""
|
|
163
|
+
# Clamp and normalize colors in the behavior before sending the request.
|
|
164
|
+
led_sequence_group = getattr(behavior, "led_sequence_group", None)
|
|
165
|
+
if led_sequence_group is not None:
|
|
166
|
+
behavior.led_sequence_group.CopyFrom(check_color(led_sequence_group))
|
|
167
|
+
|
|
168
|
+
req = audio_visual_pb2.AddOrModifyBehaviorRequest(name=name, behavior=behavior)
|
|
169
|
+
return self.call(self._stub.AddOrModifyBehavior, req,
|
|
170
|
+
value_from_response=_get_live_behavior,
|
|
171
|
+
error_from_response=_add_or_modify_behavior_error, copy_request=False,
|
|
172
|
+
**kwargs)
|
|
173
|
+
|
|
174
|
+
def add_or_modify_behavior_async(self, name, behavior, **kwargs):
|
|
175
|
+
"""Add or modify an AudioVisualBehavior.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
name: The name of the behavior to add.
|
|
179
|
+
behavior: The AudioVisualBehavior proto to add.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
The LiveAudioVisualBehavior proto that was just added or modified.
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
RpcError: Problem communicating with the robot.
|
|
186
|
+
PermanentBehaviorError: The behavior specified is permanent and cannot be modified.
|
|
187
|
+
InvalidBehaviorError: The request contained a behavior with invalid fields.
|
|
188
|
+
"""
|
|
189
|
+
# Clamp and normalize colors in the behavior before sending the request.
|
|
190
|
+
led_sequence_group = getattr(behavior, "led_sequence_group", None)
|
|
191
|
+
if led_sequence_group is not None:
|
|
192
|
+
behavior.led_sequence_group.CopyFrom(check_color(led_sequence_group))
|
|
193
|
+
|
|
194
|
+
req = audio_visual_pb2.AddOrModifyBehaviorRequest(name=name, behavior=behavior)
|
|
195
|
+
return self.call_async(self._stub.AddOrModifyBehavior, req,
|
|
196
|
+
value_from_response=_get_live_behavior,
|
|
197
|
+
error_from_response=_add_or_modify_behavior_error,
|
|
198
|
+
copy_request=False, **kwargs)
|
|
199
|
+
|
|
200
|
+
def delete_behaviors(self, behavior_names, **kwargs):
|
|
201
|
+
"""Delete an AudioVisualBehavior.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
behavior_names: A list of behavior names to delete.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
A list of LiveAudioVisualBehavior protos that were deleted.
|
|
208
|
+
|
|
209
|
+
Raises:
|
|
210
|
+
RpcError: Problem communicating with the robot.
|
|
211
|
+
DoesNotExistError: A specified behavior name has not been added to the system.
|
|
212
|
+
PermanentBehaviorError: A specified behavior is permanent and cannot be deleted.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
req = audio_visual_pb2.DeleteBehaviorsRequest(behavior_names=behavior_names)
|
|
216
|
+
return self.call(self._stub.DeleteBehaviors, req,
|
|
217
|
+
value_from_response=_get_deleted_behaviors,
|
|
218
|
+
error_from_response=_delete_behaviors_error, copy_request=False, **kwargs)
|
|
219
|
+
|
|
220
|
+
def delete_behaviors_async(self, behavior_names, **kwargs):
|
|
221
|
+
"""Async version of delete_behaviors().
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
behavior_names: A list of behavior names to delete.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
A list of LiveAudioVisualBehavior protos that were deleted.
|
|
228
|
+
|
|
229
|
+
Raises:
|
|
230
|
+
RpcError: Problem communicating with the robot.
|
|
231
|
+
DoesNotExistError: A specified behavior name has not been added to the system.
|
|
232
|
+
PermanentBehaviorError: A specified behavior is permanent and cannot be deleted.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
req = audio_visual_pb2.DeleteBehaviorsRequest(behavior_names=behavior_names)
|
|
236
|
+
return self.call_async(self._stub.DeleteBehaviors, req,
|
|
237
|
+
value_from_response=_get_deleted_behaviors,
|
|
238
|
+
error_from_response=_delete_behaviors_error, copy_request=False,
|
|
239
|
+
**kwargs)
|
|
148
240
|
|
|
149
241
|
def list_behaviors(self, **kwargs):
|
|
150
242
|
"""List all currently added AudioVisualBehaviors.
|
|
@@ -301,6 +393,9 @@ def _get_live_behavior(response):
|
|
|
301
393
|
return response.live_behavior
|
|
302
394
|
|
|
303
395
|
|
|
396
|
+
def _get_deleted_behaviors(response):
|
|
397
|
+
return response.deleted_behaviors
|
|
398
|
+
|
|
304
399
|
|
|
305
400
|
_AUDIO_VISUAL_RUN_BEHAVIOR_STATUS_TO_ERROR = collections.defaultdict(
|
|
306
401
|
lambda: (AudioVisualResponseError, None))
|
|
@@ -317,6 +412,25 @@ _AUDIO_VISUAL_STOP_BEHAVIOR_STATUS_TO_ERROR.update({
|
|
|
317
412
|
audio_visual_pb2.StopBehaviorResponse.STATUS_INVALID_CLIENT: error_pair(InvalidClientError)
|
|
318
413
|
})
|
|
319
414
|
|
|
415
|
+
_AUDIO_VISUAL_ADD_OR_MODIFY_BEHAVIOR_STATUS_TO_ERROR = collections.defaultdict(
|
|
416
|
+
lambda: (AudioVisualResponseError, None))
|
|
417
|
+
_AUDIO_VISUAL_ADD_OR_MODIFY_BEHAVIOR_STATUS_TO_ERROR.update({
|
|
418
|
+
audio_visual_pb2.AddOrModifyBehaviorResponse.STATUS_SUCCESS: (None, None),
|
|
419
|
+
audio_visual_pb2.AddOrModifyBehaviorResponse.STATUS_INVALID:
|
|
420
|
+
error_pair(InvalidBehaviorError),
|
|
421
|
+
audio_visual_pb2.AddOrModifyBehaviorResponse.STATUS_MODIFY_PERMANENT:
|
|
422
|
+
error_pair(PermanentBehaviorError),
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
_AUDIO_VISUAL_DELETE_BEHAVIORS_STATUS_TO_ERROR = collections.defaultdict(
|
|
426
|
+
lambda: (AudioVisualResponseError, None))
|
|
427
|
+
_AUDIO_VISUAL_DELETE_BEHAVIORS_STATUS_TO_ERROR.update({
|
|
428
|
+
audio_visual_pb2.DeleteBehaviorsResponse.STATUS_SUCCESS: (None, None),
|
|
429
|
+
audio_visual_pb2.DeleteBehaviorsResponse.STATUS_DOES_NOT_EXIST:
|
|
430
|
+
error_pair(DoesNotExistError),
|
|
431
|
+
audio_visual_pb2.DeleteBehaviorsResponse.STATUS_DELETE_PERMANENT:
|
|
432
|
+
error_pair(PermanentBehaviorError),
|
|
433
|
+
})
|
|
320
434
|
|
|
321
435
|
|
|
322
436
|
@handle_common_header_errors
|
|
@@ -337,3 +451,66 @@ def _stop_behavior_error(response):
|
|
|
337
451
|
status_to_error=_AUDIO_VISUAL_STOP_BEHAVIOR_STATUS_TO_ERROR)
|
|
338
452
|
|
|
339
453
|
|
|
454
|
+
@handle_common_header_errors
|
|
455
|
+
@handle_unset_status_error(unset='STATUS_UNKNOWN')
|
|
456
|
+
def _add_or_modify_behavior_error(response):
|
|
457
|
+
"""AddOrModifyBehaviorResponse response to exception."""
|
|
458
|
+
return error_factory(response, response.status,
|
|
459
|
+
status_to_string=audio_visual_pb2.AddOrModifyBehaviorResponse.Status.Name,
|
|
460
|
+
status_to_error=_AUDIO_VISUAL_ADD_OR_MODIFY_BEHAVIOR_STATUS_TO_ERROR)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@handle_common_header_errors
|
|
464
|
+
@handle_unset_status_error(unset='STATUS_UNKNOWN')
|
|
465
|
+
def _delete_behaviors_error(response):
|
|
466
|
+
"""DeleteBehaviorResponse response to exception."""
|
|
467
|
+
return error_factory(response, response.status,
|
|
468
|
+
status_to_string=audio_visual_pb2.DeleteBehaviorsResponse.Status.Name,
|
|
469
|
+
status_to_error=_AUDIO_VISUAL_DELETE_BEHAVIORS_STATUS_TO_ERROR)
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def check_color(led_sequence_group):
|
|
473
|
+
# Check every LED
|
|
474
|
+
leds = ["center", "front_left", "front_right", "hind_left", "hind_right"]
|
|
475
|
+
for led in leds:
|
|
476
|
+
# Get the LED sequence by location
|
|
477
|
+
led_sequence = getattr(led_sequence_group, led, None)
|
|
478
|
+
if led_sequence is not None:
|
|
479
|
+
# Now, normalize the color in the LED sequence by location
|
|
480
|
+
if led_sequence.HasField("animation_sequence"):
|
|
481
|
+
for idx, frame in enumerate(led_sequence.animation_sequence.frames):
|
|
482
|
+
if frame.HasField("color"):
|
|
483
|
+
led_sequence.animation_sequence.frames[idx].color.CopyFrom(
|
|
484
|
+
clamp_and_normalize_color(frame.color))
|
|
485
|
+
elif led_sequence.HasField("blink_sequence"):
|
|
486
|
+
if led_sequence.blink_sequence.HasField("color"):
|
|
487
|
+
led_sequence.blink_sequence.color.CopyFrom(
|
|
488
|
+
clamp_and_normalize_color(led_sequence.blink_sequence.color))
|
|
489
|
+
elif led_sequence.HasField("pulse_sequence"):
|
|
490
|
+
if led_sequence.pulse_sequence.HasField("color"):
|
|
491
|
+
led_sequence.pulse_sequence.color.CopyFrom(
|
|
492
|
+
clamp_and_normalize_color(led_sequence.pulse_sequence.color))
|
|
493
|
+
elif led_sequence.HasField("synced_blink_sequence"):
|
|
494
|
+
if led_sequence.synced_blink_sequence.HasField("color"):
|
|
495
|
+
led_sequence.synced_blink_sequence.color.CopyFrom(
|
|
496
|
+
clamp_and_normalize_color(led_sequence.synced_blink_sequence.color))
|
|
497
|
+
elif led_sequence.HasField("solid_color_sequence"):
|
|
498
|
+
if led_sequence.solid_color_sequence.HasField("color"):
|
|
499
|
+
led_sequence.solid_color_sequence.color.CopyFrom(
|
|
500
|
+
clamp_and_normalize_color(led_sequence.solid_color_sequence.color))
|
|
501
|
+
return led_sequence_group
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
# Scale color so that their Euclidean norm does not exceed max_color_magnitude.
|
|
505
|
+
# NOTE: max_color_magnitude of 255 (roughly 50% of sqrt(3*255^2)=441.67) is a heuristic chosen to prevent damage to the robot's LEDs.
|
|
506
|
+
# Exceeding this value may result in damage to the robot's LEDs that will NOT be covered under warranty.
|
|
507
|
+
def clamp_and_normalize_color(color, max_color_magnitude=255):
|
|
508
|
+
r, g, b = color.rgb.r, color.rgb.g, color.rgb.b
|
|
509
|
+
norm = math.sqrt(r**2 + g**2 + b**2)
|
|
510
|
+
if norm > max_color_magnitude and norm > 0:
|
|
511
|
+
scale = max_color_magnitude / norm
|
|
512
|
+
scaled_color = audio_visual_pb2.Color(
|
|
513
|
+
rgb=audio_visual_pb2.Color.RGB(r=int(r * scale), g=int(g * scale), b=int(b * scale)))
|
|
514
|
+
print(f"Input color {color} scaled by {scale:.2f}. Clamped color: {scaled_color}.")
|
|
515
|
+
color = scaled_color
|
|
516
|
+
return color
|
bosdyn/client/sdk.py
CHANGED
|
@@ -64,6 +64,7 @@ from .spot_check import SpotCheckClient
|
|
|
64
64
|
from .time_sync import TimeSyncClient
|
|
65
65
|
from .world_object import WorldObjectClient
|
|
66
66
|
|
|
67
|
+
from .audio_visual import AudioVisualClient # isort:skip
|
|
67
68
|
|
|
68
69
|
|
|
69
70
|
class SdkError(Error):
|
|
@@ -111,6 +112,7 @@ _DEFAULT_SERVICE_CLIENTS = [
|
|
|
111
112
|
AuthClient,
|
|
112
113
|
AutoReturnClient,
|
|
113
114
|
AutowalkClient,
|
|
115
|
+
AudioVisualClient,
|
|
114
116
|
DataAcquisitionClient,
|
|
115
117
|
DataAcquisitionStoreClient,
|
|
116
118
|
DataBufferClient,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bosdyn-client
|
|
3
|
-
Version: 5.0.1
|
|
3
|
+
Version: 5.0.1.2
|
|
4
4
|
Summary: Boston Dynamics API client code and interfaces
|
|
5
5
|
Home-page: https://dev.bostondynamics.com/
|
|
6
6
|
Author: Boston Dynamics
|
|
@@ -15,8 +15,8 @@ Classifier: License :: Other/Proprietary License
|
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Requires-Python: >=3.7
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
-
Requires-Dist: bosdyn-api (==5.0.1)
|
|
19
|
-
Requires-Dist: bosdyn-core (==5.0.1)
|
|
18
|
+
Requires-Dist: bosdyn-api (==5.0.1.2)
|
|
19
|
+
Requires-Dist: bosdyn-core (==5.0.1.2)
|
|
20
20
|
Requires-Dist: grpcio
|
|
21
21
|
Requires-Dist: pyjwt
|
|
22
22
|
Requires-Dist: numpy
|
|
@@ -8,7 +8,7 @@ bosdyn/client/area_callback_service_servicer.py,sha256=o1kYKV83Q-ud-_rmT17XTSqBd
|
|
|
8
8
|
bosdyn/client/area_callback_service_utils.py,sha256=R8ljJe8fPszMI6RyuGRyv_QGu63kw1yZAveZydlpERI,5858
|
|
9
9
|
bosdyn/client/arm_surface_contact.py,sha256=DRfPfsFEzfk6ufe080ViqasUefl2ZUtcvcNENgcf55k,3710
|
|
10
10
|
bosdyn/client/async_tasks.py,sha256=gEPev6_jaUCe-G5PqktMiMGb7ohDy0daunxzQD5jafg,5594
|
|
11
|
-
bosdyn/client/audio_visual.py,sha256=
|
|
11
|
+
bosdyn/client/audio_visual.py,sha256=MVwmcAtBQ4xcAY-pYsbKtoAti_2jwQH2a02zNkW-ixY,23150
|
|
12
12
|
bosdyn/client/audio_visual_helpers.py,sha256=9qksn7epH5jBdbwa6VVMcm2mn8HCVtJuSW1C847Jo6w,4499
|
|
13
13
|
bosdyn/client/auth.py,sha256=YLo6jP0Ssl_Z6rHtTiPiKUNIweDRYub9w3iHdUe6n40,5302
|
|
14
14
|
bosdyn/client/auto_return.py,sha256=kqT1gaaneLYIPFVAFzpvTHRwa8NYYQ2OBf7wViBQudE,5598
|
|
@@ -66,7 +66,7 @@ bosdyn/client/robot.py,sha256=XQCp9NjcwS4Bhhohjup_AcLlYm67DV0tlPxuqZTwU1M,31114
|
|
|
66
66
|
bosdyn/client/robot_command.py,sha256=LtoVKlJwwhTmADRMvJIWJ4B5rY_MpdhHnL72zKm1ECU,108248
|
|
67
67
|
bosdyn/client/robot_id.py,sha256=0VZHG9hltwTLAm1_Bt26Xq1O6EROswqNwHvjY7kaplk,2482
|
|
68
68
|
bosdyn/client/robot_state.py,sha256=h551ke5eHdAC7NgVuLphY8FZR899Ii8_lYwuoX1w1nk,7073
|
|
69
|
-
bosdyn/client/sdk.py,sha256=
|
|
69
|
+
bosdyn/client/sdk.py,sha256=XGW0DqlBfZv31LNYjjtU8p-86C5U-x2zJd7bAF3eDzg,12945
|
|
70
70
|
bosdyn/client/server_util.py,sha256=uLT12vs5nAhdJ0ryaKuE82dxXnBOupebyDuzI8tbLRo,10560
|
|
71
71
|
bosdyn/client/service_customization_helpers.py,sha256=GD23vhBfwCi1S4eBYIBoTbvHe9kwap1cbq0CHXlciGw,49155
|
|
72
72
|
bosdyn/client/signals_helpers.py,sha256=Sp91IrMxVU-PeH6TK2njzFCKmFMyshRJqNa4DYRMqDU,3682
|
|
@@ -97,7 +97,7 @@ bosdyn/client/spot_cam/power.py,sha256=HS3nJF8hXq9m1JziOIwLHGLtlNMyLgewWBgs-mRZm
|
|
|
97
97
|
bosdyn/client/spot_cam/ptz.py,sha256=O1m7zDZ92zRmvy9qhjojiphMQwAweTO0HVizQFdWFFE,10630
|
|
98
98
|
bosdyn/client/spot_cam/streamquality.py,sha256=e-RjizZPwZSOS4Jlqb5Ds-mC6uKam252dpEHkb58Oc8,6364
|
|
99
99
|
bosdyn/client/spot_cam/version.py,sha256=R82eyCAY9PfZqbN8D6hNzSeZatpgpsFr995dRt1Mbe0,2856
|
|
100
|
-
bosdyn_client-5.0.1.dist-info/METADATA,sha256=
|
|
101
|
-
bosdyn_client-5.0.1.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
|
|
102
|
-
bosdyn_client-5.0.1.dist-info/top_level.txt,sha256=an2OWgx1ej2jFjmBjPWNQ68ZglvUfKhmXWW-WhTtDmA,7
|
|
103
|
-
bosdyn_client-5.0.1.dist-info/RECORD,,
|
|
100
|
+
bosdyn_client-5.0.1.2.dist-info/METADATA,sha256=6Lup1U3iViBamJWCL5qGN3kg3x_YaQ1OH_uxJqLnilE,3993
|
|
101
|
+
bosdyn_client-5.0.1.2.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
|
|
102
|
+
bosdyn_client-5.0.1.2.dist-info/top_level.txt,sha256=an2OWgx1ej2jFjmBjPWNQ68ZglvUfKhmXWW-WhTtDmA,7
|
|
103
|
+
bosdyn_client-5.0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|