bosdyn-client 5.0.1.2__py3-none-any.whl → 5.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.
- bosdyn/client/access_controlled_door_util.py +206 -0
- bosdyn/client/arm_surface_contact.py +2 -2
- bosdyn/client/async_tasks.py +3 -2
- bosdyn/client/audio_visual_helpers.py +3 -2
- bosdyn/client/autowalk.py +0 -2
- bosdyn/client/command_line.py +61 -4
- bosdyn/client/common.py +1 -1
- bosdyn/client/data_acquisition.py +3 -5
- bosdyn/client/data_acquisition_helpers.py +0 -3
- bosdyn/client/data_acquisition_plugin.py +1 -2
- bosdyn/client/data_acquisition_plugin_service.py +3 -2
- bosdyn/client/data_acquisition_store.py +1 -7
- bosdyn/client/data_buffer.py +5 -4
- bosdyn/client/directory_registration.py +3 -2
- bosdyn/client/estop.py +3 -2
- bosdyn/client/fault.py +1 -1
- bosdyn/client/gps/aggregator_client.py +2 -4
- bosdyn/client/gps/gps_listener.py +5 -7
- bosdyn/client/gps/ntrip_client.py +12 -3
- bosdyn/client/graph_nav.py +67 -13
- bosdyn/client/hazard_avoidance.py +119 -0
- bosdyn/client/image.py +5 -4
- bosdyn/client/image_service_helpers.py +6 -7
- bosdyn/client/ir_enable_disable.py +1 -1
- bosdyn/client/keepalive.py +4 -2
- bosdyn/client/lease.py +3 -2
- bosdyn/client/lease_validator.py +0 -1
- bosdyn/client/log_status.py +57 -3
- bosdyn/client/map_processing.py +2 -4
- bosdyn/client/network_compute_bridge_client.py +4 -6
- bosdyn/client/payload.py +2 -3
- bosdyn/client/payload_registration.py +11 -10
- bosdyn/client/power.py +84 -27
- bosdyn/client/processors.py +27 -2
- bosdyn/client/recording.py +3 -3
- bosdyn/client/robot_command.py +22 -22
- bosdyn/client/robot_state.py +1 -1
- bosdyn/client/sdk.py +2 -3
- bosdyn/client/service_customization_helpers.py +1 -1
- bosdyn/client/spot_cam/audio.py +1 -2
- bosdyn/client/spot_cam/health.py +1 -1
- bosdyn/client/spot_cam/lighting.py +1 -1
- bosdyn/client/spot_cam/media_log.py +1 -1
- bosdyn/client/spot_cam/network.py +3 -2
- bosdyn/client/spot_cam/power.py +1 -1
- bosdyn/client/spot_cam/ptz.py +1 -1
- bosdyn/client/spot_cam/streamquality.py +1 -1
- bosdyn/client/spot_cam/version.py +1 -1
- bosdyn/client/spot_check.py +5 -6
- bosdyn/client/url_validation_util.py +220 -0
- bosdyn/client/util.py +2 -4
- bosdyn/client/world_object.py +1 -1
- {bosdyn_client-5.0.1.2.dist-info → bosdyn_client-5.1.0.dist-info}/METADATA +3 -3
- bosdyn_client-5.1.0.dist-info/RECORD +106 -0
- bosdyn_client-5.0.1.2.dist-info/RECORD +0 -103
- {bosdyn_client-5.0.1.2.dist-info → bosdyn_client-5.1.0.dist-info}/WHEEL +0 -0
- {bosdyn_client-5.0.1.2.dist-info → bosdyn_client-5.1.0.dist-info}/top_level.txt +0 -0
|
@@ -19,8 +19,9 @@ import bosdyn.api.payload_registration_service_pb2_grpc as payload_registration_
|
|
|
19
19
|
from bosdyn.client import (ResponseError, RetryableUnavailableError, TimedOutError,
|
|
20
20
|
TooManyRequestsError)
|
|
21
21
|
from bosdyn.client.common import (BaseClient, error_factory, handle_common_header_errors,
|
|
22
|
-
|
|
22
|
+
handle_unset_status_error)
|
|
23
23
|
from bosdyn.client.error_callback_result import ErrorCallbackResult
|
|
24
|
+
from bosdyn.util import now_sec
|
|
24
25
|
|
|
25
26
|
LOGGER = logging.getLogger('payload_registration_client')
|
|
26
27
|
|
|
@@ -156,7 +157,7 @@ class PayloadRegistrationClient(BaseClient):
|
|
|
156
157
|
|
|
157
158
|
def get_payload_auth_token(self, guid, secret, **kw_args):
|
|
158
159
|
"""Request a limited-access auth token for a payload.
|
|
159
|
-
|
|
160
|
+
|
|
160
161
|
Getting the auth token requires payload to be authorized via the web console.
|
|
161
162
|
|
|
162
163
|
Args:
|
|
@@ -166,7 +167,7 @@ class PayloadRegistrationClient(BaseClient):
|
|
|
166
167
|
|
|
167
168
|
Returns:
|
|
168
169
|
A limited-access user token for the robot
|
|
169
|
-
|
|
170
|
+
|
|
170
171
|
Raises:
|
|
171
172
|
RpcError: Problem communicating with the robot.
|
|
172
173
|
PayloadNotAuthorizedError: The payload with the provided GUID is
|
|
@@ -370,7 +371,7 @@ class PayloadRegistrationKeepAlive(object):
|
|
|
370
371
|
the robot if it is ever forgotten. However, payload registrations on Spot are persistent
|
|
371
372
|
across power cycles and updates, so in most cases there is no need to send a payload
|
|
372
373
|
registration request after the first successful payload registration. The use of a payload
|
|
373
|
-
registration keep alive should only be used when a payload is expected to be regularly
|
|
374
|
+
registration keep alive should only be used when a payload is expected to be regularly
|
|
374
375
|
reconfigured by forgetting & re-authorizing the payload in the web page.
|
|
375
376
|
|
|
376
377
|
Args:
|
|
@@ -413,9 +414,9 @@ class PayloadRegistrationKeepAlive(object):
|
|
|
413
414
|
|
|
414
415
|
def start(self):
|
|
415
416
|
"""Register and then kick off thread.
|
|
416
|
-
|
|
417
|
+
|
|
417
418
|
Can not be restarted with this method after a shutdown.
|
|
418
|
-
|
|
419
|
+
|
|
419
420
|
Raises:
|
|
420
421
|
RpcError: Problem communicating with the robot.
|
|
421
422
|
RuntimeError: The thread was attempted to start more than once.
|
|
@@ -435,7 +436,7 @@ class PayloadRegistrationKeepAlive(object):
|
|
|
435
436
|
|
|
436
437
|
def is_alive(self):
|
|
437
438
|
"""Are we still periodically re-registering?
|
|
438
|
-
|
|
439
|
+
|
|
439
440
|
Returns:
|
|
440
441
|
A bool stating if still alive
|
|
441
442
|
"""
|
|
@@ -449,7 +450,7 @@ class PayloadRegistrationKeepAlive(object):
|
|
|
449
450
|
|
|
450
451
|
def _periodic_reregister(self):
|
|
451
452
|
"""Handles a removal of the payload from the robot payload page while still connected.
|
|
452
|
-
|
|
453
|
+
|
|
453
454
|
Raises:
|
|
454
455
|
RpcError: Problem communicating with the robot.
|
|
455
456
|
"""
|
|
@@ -458,7 +459,7 @@ class PayloadRegistrationKeepAlive(object):
|
|
|
458
459
|
wait_time = self._registration_interval_secs
|
|
459
460
|
|
|
460
461
|
while not self._end_reregister_signal.wait(wait_time):
|
|
461
|
-
exec_start =
|
|
462
|
+
exec_start = now_sec()
|
|
462
463
|
action = ErrorCallbackResult.RESUME_NORMAL_OPERATION
|
|
463
464
|
try:
|
|
464
465
|
self.pay_reg_client.register_payload(self.payload, self.secret)
|
|
@@ -486,7 +487,7 @@ class PayloadRegistrationKeepAlive(object):
|
|
|
486
487
|
# Log all other exceptions, but continue looping in hopes that it resolves itself
|
|
487
488
|
self.logger.exception('Caught general exception.')
|
|
488
489
|
|
|
489
|
-
exec_sec =
|
|
490
|
+
exec_sec = now_sec() - exec_start
|
|
490
491
|
if action == ErrorCallbackResult.ABORT:
|
|
491
492
|
self.logger.warning('Callback directed the re-registration loop to exit.')
|
|
492
493
|
break
|
bosdyn/client/power.py
CHANGED
|
@@ -13,13 +13,14 @@ from concurrent.futures import TimeoutError
|
|
|
13
13
|
from deprecated.sphinx import deprecated
|
|
14
14
|
from google.protobuf.duration_pb2 import Duration
|
|
15
15
|
|
|
16
|
-
from bosdyn.api import (basic_command_pb2, full_body_command_pb2,
|
|
17
|
-
|
|
16
|
+
from bosdyn.api import (basic_command_pb2, full_body_command_pb2, power_pb2, power_service_pb2_grpc,
|
|
17
|
+
robot_command_pb2, robot_state_pb2)
|
|
18
18
|
from bosdyn.client.common import (BaseClient, common_license_errors, error_factory,
|
|
19
19
|
handle_common_header_errors, handle_lease_use_result_errors,
|
|
20
20
|
handle_unset_status_error)
|
|
21
21
|
from bosdyn.client.exceptions import (Error, InternalServerError, LicenseError, ResponseError,
|
|
22
22
|
TimedOutError)
|
|
23
|
+
from bosdyn.util import now_sec
|
|
23
24
|
|
|
24
25
|
from .lease import add_lease_wallet_processors
|
|
25
26
|
|
|
@@ -82,9 +83,10 @@ class SafetyStopUnknownStopTypeError(PowerResponseError):
|
|
|
82
83
|
|
|
83
84
|
class PowerClient(BaseClient):
|
|
84
85
|
"""A client for enabling / disabling robot motor power.
|
|
86
|
+
|
|
85
87
|
Commands are non-blocking. Clients are expected to issue a power command and then periodically
|
|
86
|
-
check the status of this command.
|
|
87
|
-
|
|
88
|
+
check the status of this command. This service requires ownership over the robot, in the form of
|
|
89
|
+
a lease.
|
|
88
90
|
"""
|
|
89
91
|
default_service_name = 'power'
|
|
90
92
|
service_type = 'bosdyn.api.PowerService'
|
|
@@ -134,7 +136,7 @@ class PowerClient(BaseClient):
|
|
|
134
136
|
_fan_power_command_error_from_response, **kwargs)
|
|
135
137
|
|
|
136
138
|
def fan_power_command_feedback(self, command_id, **kwargs):
|
|
137
|
-
"""Check the status of a previously issued fan command"""
|
|
139
|
+
"""Check the status of a previously issued fan command."""
|
|
138
140
|
req = self._fan_power_command_feedback_request(command_id)
|
|
139
141
|
return self.call(self._stub.FanPowerCommandFeedback, req, None,
|
|
140
142
|
_fan_power_feedback_error_from_response, **kwargs)
|
|
@@ -190,7 +192,10 @@ def _handle_license_errors(func):
|
|
|
190
192
|
|
|
191
193
|
|
|
192
194
|
def _common_license_errors(response):
|
|
193
|
-
"""Return an exception based on license status.
|
|
195
|
+
"""Return an exception based on license status.
|
|
196
|
+
|
|
197
|
+
None if no error.
|
|
198
|
+
"""
|
|
194
199
|
if response.status != power_pb2.STATUS_LICENSE_ERROR:
|
|
195
200
|
return None
|
|
196
201
|
|
|
@@ -284,14 +289,17 @@ _RESET_SAFETY_STOP_STATUS_TO_ERROR.update({
|
|
|
284
289
|
@deprecated(reason='Replaced by the less ambiguous safe_power_off_motors function.',
|
|
285
290
|
version='3.0.0', action="ignore")
|
|
286
291
|
def safe_power_off(command_client, state_client, timeout_sec=30, update_frequency=1.0, **kwargs):
|
|
287
|
-
"""Safely power off motors.
|
|
292
|
+
"""Safely power off motors.
|
|
293
|
+
|
|
294
|
+
See safe_power_off_motors().
|
|
295
|
+
"""
|
|
288
296
|
safe_power_off_motors(command_client, state_client, timeout_sec, update_frequency, **kwargs)
|
|
289
297
|
|
|
290
298
|
|
|
291
299
|
def safe_power_off_motors(command_client, state_client, timeout_sec=30, update_frequency=1.0,
|
|
292
300
|
**kwargs):
|
|
293
|
-
"""Power off robot motors safely. This function blocks until robot safely powers off. This
|
|
294
|
-
|
|
301
|
+
"""Power off robot motors safely. This function blocks until robot safely powers off. This means
|
|
302
|
+
the robot will attempt to sit before powering motors off.
|
|
295
303
|
|
|
296
304
|
Args:
|
|
297
305
|
command_client (RobotCommandClient): client for calling RobotCommandService safe power off.
|
|
@@ -305,7 +313,7 @@ def safe_power_off_motors(command_client, state_client, timeout_sec=30, update_f
|
|
|
305
313
|
power.CommandTimedOutError: Did not power off within timeout_sec
|
|
306
314
|
RobotCommandResponseError: Something went wrong with the safe power off.
|
|
307
315
|
"""
|
|
308
|
-
start_time =
|
|
316
|
+
start_time = now_sec()
|
|
309
317
|
end_time = start_time + timeout_sec
|
|
310
318
|
update_time = 1.0 / update_frequency
|
|
311
319
|
|
|
@@ -314,9 +322,9 @@ def safe_power_off_motors(command_client, state_client, timeout_sec=30, update_f
|
|
|
314
322
|
command = robot_command_pb2.RobotCommand(full_body_command=full_body_command)
|
|
315
323
|
command_client.robot_command(command=command, **kwargs)
|
|
316
324
|
|
|
317
|
-
while
|
|
318
|
-
time_until_timeout = end_time -
|
|
319
|
-
start_call_time =
|
|
325
|
+
while now_sec() < end_time:
|
|
326
|
+
time_until_timeout = end_time - now_sec()
|
|
327
|
+
start_call_time = now_sec()
|
|
320
328
|
future = state_client.get_robot_state_async(**kwargs)
|
|
321
329
|
try:
|
|
322
330
|
response = future.result(timeout=time_until_timeout)
|
|
@@ -324,7 +332,7 @@ def safe_power_off_motors(command_client, state_client, timeout_sec=30, update_f
|
|
|
324
332
|
return
|
|
325
333
|
except TimeoutError:
|
|
326
334
|
raise CommandTimedOutError
|
|
327
|
-
call_time =
|
|
335
|
+
call_time = now_sec() - start_call_time
|
|
328
336
|
sleep_time = max(0.0, update_time - call_time)
|
|
329
337
|
time.sleep(sleep_time)
|
|
330
338
|
raise CommandTimedOutError
|
|
@@ -333,14 +341,20 @@ def safe_power_off_motors(command_client, state_client, timeout_sec=30, update_f
|
|
|
333
341
|
@deprecated(reason='Replaced by the less ambiguous power_on_motors function.', version='2.3.4',
|
|
334
342
|
action="ignore")
|
|
335
343
|
def power_on(power_client, timeout_sec=30, update_frequency=1.0, **kwargs):
|
|
336
|
-
"""Power on robot motors.
|
|
344
|
+
"""Power on robot motors.
|
|
345
|
+
|
|
346
|
+
See power_on_motors().
|
|
347
|
+
"""
|
|
337
348
|
power_on_motors(power_client, timeout_sec, update_frequency, **kwargs)
|
|
338
349
|
|
|
339
350
|
|
|
340
351
|
@deprecated(reason='Replaced by the less ambiguous power_off_motors function.', version='2.3.4',
|
|
341
352
|
action="ignore")
|
|
342
353
|
def power_off(power_client, timeout_sec=30, update_frequency=1.0, **kwargs):
|
|
343
|
-
"""Power off the robot motors.
|
|
354
|
+
"""Power off the robot motors.
|
|
355
|
+
|
|
356
|
+
See power_off_motors().
|
|
357
|
+
"""
|
|
344
358
|
power_off_motors(power_client, timeout_sec, update_frequency, **kwargs)
|
|
345
359
|
|
|
346
360
|
|
|
@@ -399,10 +413,10 @@ def safe_power_off_robot(command_client, state_client, power_client, timeout_sec
|
|
|
399
413
|
power.CommandTimedOutError: Did not power off within timeout_sec
|
|
400
414
|
RobotCommandResponseError: Something went wrong with the safe power off.
|
|
401
415
|
"""
|
|
402
|
-
end_time =
|
|
403
|
-
safe_power_off_motors(command_client, state_client, timeout_sec=end_time -
|
|
416
|
+
end_time = now_sec() + timeout_sec
|
|
417
|
+
safe_power_off_motors(command_client, state_client, timeout_sec=end_time - now_sec(),
|
|
404
418
|
update_frequency=update_frequency, **kwargs)
|
|
405
|
-
power_off_robot(power_client, timeout_sec=end_time -
|
|
419
|
+
power_off_robot(power_client, timeout_sec=end_time - now_sec(),
|
|
406
420
|
update_frequency=update_frequency, **kwargs)
|
|
407
421
|
|
|
408
422
|
|
|
@@ -442,10 +456,10 @@ def safe_power_cycle_robot(command_client, state_client, power_client, timeout_s
|
|
|
442
456
|
power.CommandTimedOutError: Did not power off within timeout_sec
|
|
443
457
|
RobotCommandResponseError: Something went wrong with the safe power off.
|
|
444
458
|
"""
|
|
445
|
-
end_time =
|
|
446
|
-
safe_power_off_motors(command_client, state_client, timeout_sec=end_time -
|
|
459
|
+
end_time = now_sec() + timeout_sec
|
|
460
|
+
safe_power_off_motors(command_client, state_client, timeout_sec=end_time - now_sec(),
|
|
447
461
|
update_frequency=update_frequency, **kwargs)
|
|
448
|
-
power_cycle_robot(power_client, timeout_sec=end_time -
|
|
462
|
+
power_cycle_robot(power_client, timeout_sec=end_time - now_sec(),
|
|
449
463
|
update_frequency=update_frequency, **kwargs)
|
|
450
464
|
|
|
451
465
|
|
|
@@ -467,6 +481,49 @@ def power_cycle_robot(power_client, timeout_sec=30, update_frequency=1.0, **kwar
|
|
|
467
481
|
**kwargs)
|
|
468
482
|
|
|
469
483
|
|
|
484
|
+
def safe_soft_reboot_robot(command_client, state_client, power_client, timeout_sec=30,
|
|
485
|
+
update_frequency=1.0, **kwargs):
|
|
486
|
+
"""Soft reboot the robot safely. This function blocks until robot safely powers off. The robot
|
|
487
|
+
will attempt to sit before soft rebooting.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
command_client (RobotCommandClient): client for calling RobotCommandService safe power off.
|
|
491
|
+
state_client (RobotStateClient): client for monitoring power state.
|
|
492
|
+
power_client (bosdyn.api.PowerClient): client for calling power service.
|
|
493
|
+
timeout_sec (float): Max time this function will block for.
|
|
494
|
+
update_frequency (float): The frequency with which the robot should check if the command
|
|
495
|
+
has succeeded.
|
|
496
|
+
|
|
497
|
+
Raises:
|
|
498
|
+
RpcError: Problem communicating with the robot.
|
|
499
|
+
power.CommandTimedOutError: Did not power off within timeout_sec
|
|
500
|
+
RobotCommandResponseError: Something went wrong with the safe power off.
|
|
501
|
+
"""
|
|
502
|
+
end_time = now_sec() + timeout_sec
|
|
503
|
+
safe_power_off_motors(command_client, state_client, timeout_sec=end_time - now_sec(),
|
|
504
|
+
update_frequency=update_frequency, **kwargs)
|
|
505
|
+
soft_reboot_robot(power_client, timeout_sec=end_time - now_sec(),
|
|
506
|
+
update_frequency=update_frequency, **kwargs)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def soft_reboot_robot(power_client, timeout_sec=30, update_frequency=1.0, **kwargs):
|
|
510
|
+
"""Soft reboot the robot. Rebooting the robot will stop API comms.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
power_client (bosdyn.api.PowerClient): client for calling power service.
|
|
514
|
+
timeout_sec (float): Max time this function will block for.
|
|
515
|
+
update_frequency (float): The frequency with which the robot should check if the command
|
|
516
|
+
has succeeded.
|
|
517
|
+
Raises:
|
|
518
|
+
RpcError: Problem communicating with the robot.
|
|
519
|
+
power.CommandTimedOutError: Did not power off within timeout_sec
|
|
520
|
+
PowerResponseError: Something went wrong during the power off sequence.
|
|
521
|
+
"""
|
|
522
|
+
request = power_pb2.PowerCommandRequest.REQUEST_SOFT_REBOOT_ROBOT
|
|
523
|
+
_power_command(power_client, request, timeout_sec, update_frequency, expect_grpc_timeout=True,
|
|
524
|
+
**kwargs)
|
|
525
|
+
|
|
526
|
+
|
|
470
527
|
def power_off_payload_ports(power_client, timeout_sec=30, update_frequency=1.0, **kwargs):
|
|
471
528
|
"""Power off the robot payload ports.
|
|
472
529
|
|
|
@@ -551,7 +608,7 @@ def _power_command(power_client, request, timeout_sec=30, update_frequency=1.0,
|
|
|
551
608
|
has succeeded.
|
|
552
609
|
expect_timeout (bool): Expect API comms to drop on a success.
|
|
553
610
|
"""
|
|
554
|
-
start_time =
|
|
611
|
+
start_time = now_sec()
|
|
555
612
|
end_time = start_time + timeout_sec
|
|
556
613
|
update_time = 1.0 / update_frequency
|
|
557
614
|
|
|
@@ -566,9 +623,9 @@ def _power_command(power_client, request, timeout_sec=30, update_frequency=1.0,
|
|
|
566
623
|
return # Command succeeded immediately.
|
|
567
624
|
|
|
568
625
|
power_command_id = response.power_command_id
|
|
569
|
-
while
|
|
570
|
-
time_until_timeout = end_time -
|
|
571
|
-
start_call_time =
|
|
626
|
+
while now_sec() < end_time:
|
|
627
|
+
time_until_timeout = end_time - now_sec()
|
|
628
|
+
start_call_time = now_sec()
|
|
572
629
|
future = power_client.power_command_feedback_async(power_command_id, **kwargs)
|
|
573
630
|
try:
|
|
574
631
|
response = future.result(timeout=time_until_timeout)
|
|
@@ -585,7 +642,7 @@ def _power_command(power_client, request, timeout_sec=30, update_frequency=1.0,
|
|
|
585
642
|
raise
|
|
586
643
|
except TimeoutError:
|
|
587
644
|
raise CommandTimedOutError
|
|
588
|
-
call_time =
|
|
645
|
+
call_time = now_sec() - start_call_time
|
|
589
646
|
sleep_time = max(0.0, update_time - call_time)
|
|
590
647
|
time.sleep(sleep_time)
|
|
591
648
|
raise CommandTimedOutError
|
bosdyn/client/processors.py
CHANGED
|
@@ -25,11 +25,36 @@ class AddRequestHeader(object):
|
|
|
25
25
|
|
|
26
26
|
def mutate(self, request):
|
|
27
27
|
"""Mutate request such that its header contains a client name and a timestamp.
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
Headers are not required for third party proto requests/responses.
|
|
30
30
|
"""
|
|
31
31
|
header = self._create_header()
|
|
32
32
|
try:
|
|
33
33
|
request.header.CopyFrom(header)
|
|
34
34
|
except AttributeError:
|
|
35
|
-
pass
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DataBufferLoggingProcessor:
|
|
39
|
+
"""Processor that logs every protobuf message to the robot's data buffer."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, data_buffer_client):
|
|
42
|
+
"""
|
|
43
|
+
Args:
|
|
44
|
+
data_buffer_client: Instance of DataBufferClient.
|
|
45
|
+
"""
|
|
46
|
+
self.data_buffer_client = data_buffer_client
|
|
47
|
+
|
|
48
|
+
def mutate(self, proto, **kwargs):
|
|
49
|
+
"""Logs the protobuf message to the data buffer.
|
|
50
|
+
Args:
|
|
51
|
+
proto: The protobuf request or response to log.
|
|
52
|
+
"""
|
|
53
|
+
self.data_buffer_client.add_protobuf_async(proto)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def log_all_rpcs(client, data_buffer_client):
|
|
57
|
+
"""Attach a DataBufferLoggingProcessor to log all RPC requests and responses for the given client."""
|
|
58
|
+
processor = DataBufferLoggingProcessor(data_buffer_client)
|
|
59
|
+
client.request_processors.append(processor)
|
|
60
|
+
client.response_processors.append(processor)
|
bosdyn/client/recording.py
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
import collections
|
|
10
10
|
from enum import Enum
|
|
11
11
|
|
|
12
|
-
from bosdyn.api.graph_nav import map_pb2,
|
|
12
|
+
from bosdyn.api.graph_nav import map_pb2, recording_pb2
|
|
13
13
|
from bosdyn.api.graph_nav import recording_service_pb2_grpc as recording_service
|
|
14
14
|
from bosdyn.client.common import (BaseClient, common_header_errors, error_factory,
|
|
15
|
-
handle_common_header_errors,
|
|
16
|
-
|
|
15
|
+
handle_common_header_errors, handle_license_errors_if_present,
|
|
16
|
+
handle_unset_status_error)
|
|
17
17
|
from bosdyn.client.exceptions import ResponseError
|
|
18
18
|
|
|
19
19
|
|
bosdyn/client/robot_command.py
CHANGED
|
@@ -8,27 +8,26 @@
|
|
|
8
8
|
import collections
|
|
9
9
|
import time
|
|
10
10
|
|
|
11
|
-
from google.protobuf import any_pb2, wrappers_pb2
|
|
12
|
-
|
|
13
|
-
from bosdyn import geometry
|
|
14
11
|
from bosdyn.api import (arm_command_pb2, basic_command_pb2, full_body_command_pb2, geometry_pb2,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
trajectory_pb2)
|
|
12
|
+
mobility_command_pb2, payload_estimation_pb2, robot_command_pb2,
|
|
13
|
+
robot_command_service_pb2_grpc, synchronized_command_pb2, trajectory_pb2)
|
|
18
14
|
|
|
19
15
|
# isort: off
|
|
20
16
|
# isort: on
|
|
17
|
+
from google.protobuf import any_pb2, wrappers_pb2
|
|
18
|
+
|
|
19
|
+
from bosdyn import geometry
|
|
21
20
|
from bosdyn.api.spot import robot_command_pb2 as spot_command_pb2
|
|
22
21
|
from bosdyn.client.common import (BaseClient, error_factory, error_pair,
|
|
23
22
|
handle_common_header_errors, handle_lease_use_result_errors,
|
|
24
23
|
handle_unset_status_error)
|
|
25
|
-
from bosdyn.util import seconds_to_duration
|
|
24
|
+
from bosdyn.util import now_sec, seconds_to_duration
|
|
26
25
|
|
|
27
26
|
from .exceptions import Error as BaseError
|
|
28
27
|
from .exceptions import InvalidRequestError, ResponseError, TimedOutError, UnsetStatusError
|
|
29
28
|
from .frame_helpers import BODY_FRAME_NAME, ODOM_FRAME_NAME, get_se2_a_tform_b
|
|
30
29
|
from .lease import add_lease_wallet_processors
|
|
31
|
-
from .math_helpers import SE2Pose, SE3Pose
|
|
30
|
+
from .math_helpers import SE2Pose, SE3Pose
|
|
32
31
|
|
|
33
32
|
# The angles (in radians) that represent the claw gripper open and closed positions.
|
|
34
33
|
_CLAW_GRIPPER_OPEN_ANGLE = -1.5708
|
|
@@ -372,11 +371,12 @@ class RobotCommandClient(BaseClient):
|
|
|
372
371
|
return self.call_async(self._stub.RobotCommand, req, _robot_command_value,
|
|
373
372
|
_robot_command_error, copy_request=False, **kwargs)
|
|
374
373
|
|
|
375
|
-
def robot_command_feedback(self, robot_command_id, **kwargs):
|
|
374
|
+
def robot_command_feedback(self, robot_command_id=None, **kwargs):
|
|
376
375
|
"""Get feedback from a previously issued command.
|
|
377
376
|
|
|
378
377
|
Args:
|
|
379
|
-
robot_command_id: ID of the robot command to get feedback on.
|
|
378
|
+
robot_command_id: ID of the robot command to get feedback on. If blank, will return feedback for the
|
|
379
|
+
current active command if a command is in progress.
|
|
380
380
|
|
|
381
381
|
Raises:
|
|
382
382
|
RpcError: Problem communicating with the robot.
|
|
@@ -386,7 +386,7 @@ class RobotCommandClient(BaseClient):
|
|
|
386
386
|
return self.call(self._stub.RobotCommandFeedback, req, None, _robot_command_feedback_error,
|
|
387
387
|
copy_request=False, **kwargs)
|
|
388
388
|
|
|
389
|
-
def robot_command_feedback_async(self, robot_command_id, **kwargs):
|
|
389
|
+
def robot_command_feedback_async(self, robot_command_id=None, **kwargs):
|
|
390
390
|
"""Async version of robot_command_feedback().
|
|
391
391
|
|
|
392
392
|
Args:
|
|
@@ -1928,18 +1928,18 @@ def blocking_command(command_client, command, check_status_fn, end_time_secs=Non
|
|
|
1928
1928
|
basic_command_pb2.RobotCommandFeedbackStatus.Status.Name(feedback_status)),
|
|
1929
1929
|
response)
|
|
1930
1930
|
|
|
1931
|
-
start_time =
|
|
1931
|
+
start_time = now_sec()
|
|
1932
1932
|
end_time = start_time + timeout_sec
|
|
1933
1933
|
update_time = 1.0 / update_frequency
|
|
1934
1934
|
|
|
1935
1935
|
command_id = command_client.robot_command(command, timeout=timeout_sec,
|
|
1936
1936
|
end_time_secs=end_time_secs)
|
|
1937
1937
|
|
|
1938
|
-
now =
|
|
1938
|
+
now = now_sec()
|
|
1939
1939
|
while now < end_time:
|
|
1940
1940
|
time_until_timeout = end_time - now
|
|
1941
1941
|
rpc_timeout = max(time_until_timeout, 1)
|
|
1942
|
-
start_call_time =
|
|
1942
|
+
start_call_time = now_sec()
|
|
1943
1943
|
try:
|
|
1944
1944
|
response = command_client.robot_command_feedback(command_id, timeout=rpc_timeout)
|
|
1945
1945
|
except TimedOutError:
|
|
@@ -1977,9 +1977,9 @@ def blocking_command(command_client, command, check_status_fn, end_time_secs=Non
|
|
|
1977
1977
|
if check_status_fn(response):
|
|
1978
1978
|
return
|
|
1979
1979
|
|
|
1980
|
-
delta_t =
|
|
1980
|
+
delta_t = now_sec() - start_call_time
|
|
1981
1981
|
time.sleep(max(min(delta_t, update_time), 0.0))
|
|
1982
|
-
now =
|
|
1982
|
+
now = now_sec()
|
|
1983
1983
|
|
|
1984
1984
|
raise CommandTimedOutError(
|
|
1985
1985
|
"Took longer than {:.1f} seconds to execute the command.".format(now - start_time))
|
|
@@ -2079,9 +2079,9 @@ def block_until_arm_arrives(command_client, cmd_id, timeout_sec=None):
|
|
|
2079
2079
|
arm_command.proto for more information about why a trajectory would succeed or fail.
|
|
2080
2080
|
"""
|
|
2081
2081
|
if timeout_sec is not None:
|
|
2082
|
-
start_time =
|
|
2082
|
+
start_time = now_sec()
|
|
2083
2083
|
end_time = start_time + timeout_sec
|
|
2084
|
-
now =
|
|
2084
|
+
now = now_sec()
|
|
2085
2085
|
|
|
2086
2086
|
while timeout_sec is None or now < end_time:
|
|
2087
2087
|
feedback_resp = command_client.robot_command_feedback(cmd_id)
|
|
@@ -2114,7 +2114,7 @@ def block_until_arm_arrives(command_client, cmd_id, timeout_sec=None):
|
|
|
2114
2114
|
return False
|
|
2115
2115
|
|
|
2116
2116
|
time.sleep(0.1)
|
|
2117
|
-
now =
|
|
2117
|
+
now = now_sec()
|
|
2118
2118
|
return False
|
|
2119
2119
|
|
|
2120
2120
|
|
|
@@ -2145,9 +2145,9 @@ def block_for_trajectory_cmd(
|
|
|
2145
2145
|
"""
|
|
2146
2146
|
|
|
2147
2147
|
if timeout_sec is not None:
|
|
2148
|
-
start_time =
|
|
2148
|
+
start_time = now_sec()
|
|
2149
2149
|
end_time = start_time + timeout_sec
|
|
2150
|
-
now =
|
|
2150
|
+
now = now_sec()
|
|
2151
2151
|
|
|
2152
2152
|
while timeout_sec is None or now < end_time:
|
|
2153
2153
|
feedback_resp = command_client.robot_command_feedback(cmd_id)
|
|
@@ -2173,7 +2173,7 @@ def block_for_trajectory_cmd(
|
|
|
2173
2173
|
return True
|
|
2174
2174
|
|
|
2175
2175
|
time.sleep(feedback_interval_secs)
|
|
2176
|
-
now =
|
|
2176
|
+
now = now_sec()
|
|
2177
2177
|
|
|
2178
2178
|
if logger is not None:
|
|
2179
2179
|
logger.info('block_for_trajectory_cmd: timeout exceeded.')
|
bosdyn/client/robot_state.py
CHANGED
|
@@ -131,7 +131,7 @@ class RobotStateClient(BaseClient):
|
|
|
131
131
|
|
|
132
132
|
class RobotStateStreamingClient(BaseClient):
|
|
133
133
|
"""Client for the RobotState service.
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
This client is in BETA and may undergo changes in future releases.
|
|
136
136
|
"""
|
|
137
137
|
default_service_name = 'robot-state-streaming'
|
bosdyn/client/sdk.py
CHANGED
|
@@ -14,6 +14,7 @@ import os
|
|
|
14
14
|
import platform
|
|
15
15
|
from enum import Enum
|
|
16
16
|
|
|
17
|
+
import __main__
|
|
17
18
|
import jwt
|
|
18
19
|
from deprecated.sphinx import deprecated
|
|
19
20
|
|
|
@@ -87,10 +88,8 @@ BOSDYN_RESOURCE_ROOT = os.environ.get('BOSDYN_RESOURCE_ROOT',
|
|
|
87
88
|
|
|
88
89
|
def generate_client_name(prefix=''):
|
|
89
90
|
"""Returns a descriptive client name for API clients with an optional prefix."""
|
|
90
|
-
import bosdyn.client.__main__
|
|
91
91
|
try:
|
|
92
|
-
process_info = '{}-{}'.format(os.path.basename(
|
|
93
|
-
os.getpid())
|
|
92
|
+
process_info = '{}-{}'.format(os.path.basename(__main__.__file__), os.getpid())
|
|
94
93
|
except AttributeError:
|
|
95
94
|
process_info = '{}'.format(os.getpid())
|
|
96
95
|
machine_name = platform.node()
|
|
@@ -149,7 +149,7 @@ def oneof_param_to_dict(oneof_param: OneOfParam, oneof_spec: OneOfParam.Spec,
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
def check_types_match(param, proto_type):
|
|
152
|
-
if type(param)
|
|
152
|
+
if type(param) is not proto_type:
|
|
153
153
|
return CustomParamError(
|
|
154
154
|
status=CustomParamError.STATUS_INVALID_VALUE,
|
|
155
155
|
error_messages=[
|
bosdyn/client/spot_cam/audio.py
CHANGED
|
@@ -12,9 +12,8 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
12
12
|
|
|
13
13
|
from google.protobuf.wrappers_pb2 import FloatValue
|
|
14
14
|
|
|
15
|
-
from bosdyn.api import data_chunk_pb2
|
|
16
15
|
from bosdyn.api.spot_cam import audio_pb2, service_pb2_grpc
|
|
17
|
-
from bosdyn.client.common import BaseClient,
|
|
16
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class AudioClient(BaseClient):
|
bosdyn/client/spot_cam/health.py
CHANGED
|
@@ -11,7 +11,7 @@ import logging
|
|
|
11
11
|
_LOGGER = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
from bosdyn.api.spot_cam import health_pb2, service_pb2_grpc
|
|
14
|
-
from bosdyn.client.common import BaseClient,
|
|
14
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class HealthClient(BaseClient):
|
|
@@ -11,7 +11,7 @@ import logging
|
|
|
11
11
|
_LOGGER = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
from bosdyn.api.spot_cam import LED_pb2, service_pb2_grpc
|
|
14
|
-
from bosdyn.client.common import BaseClient,
|
|
14
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class LightingClient(BaseClient):
|
|
@@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
13
13
|
from deprecated.sphinx import deprecated
|
|
14
14
|
|
|
15
15
|
from bosdyn.api.spot_cam import logging_pb2, service_pb2_grpc
|
|
16
|
-
from bosdyn.client.common import BaseClient,
|
|
16
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class MediaLogClient(BaseClient):
|
|
@@ -27,7 +27,7 @@ class NetworkClient(BaseClient):
|
|
|
27
27
|
super(NetworkClient, self).__init__(service_pb2_grpc.NetworkServiceStub)
|
|
28
28
|
|
|
29
29
|
def get_ice_configuration(self, **kwargs):
|
|
30
|
-
"""
|
|
30
|
+
"""Get ICE configuration from Spot CAM"""
|
|
31
31
|
request = network_pb2.GetICEConfigurationRequest()
|
|
32
32
|
return self.call(self._stub.GetICEConfiguration, request, self._ice_servers_from_response,
|
|
33
33
|
self._ice_network_error_from_response, copy_request=False, **kwargs)
|
|
@@ -41,7 +41,7 @@ class NetworkClient(BaseClient):
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def set_ice_configuration(self, ice_servers, **kwargs):
|
|
44
|
-
"""
|
|
44
|
+
"""Set ICE configuration on Spot CAM. This overrides all existing configured servers"""
|
|
45
45
|
request = self._set_ice_configuration_request(ice_servers)
|
|
46
46
|
return self.call(self._stub.SetICEConfiguration, request, None,
|
|
47
47
|
self._ice_network_error_from_response, copy_request=False, **kwargs)
|
|
@@ -67,3 +67,4 @@ class NetworkClient(BaseClient):
|
|
|
67
67
|
@handle_common_header_errors
|
|
68
68
|
def _ice_network_error_from_response(response): # pylint: disable=unused-argument
|
|
69
69
|
return None
|
|
70
|
+
|
bosdyn/client/spot_cam/power.py
CHANGED
|
@@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
13
13
|
from google.protobuf.wrappers_pb2 import BoolValue
|
|
14
14
|
|
|
15
15
|
from bosdyn.api.spot_cam import power_pb2, service_pb2_grpc
|
|
16
|
-
from bosdyn.client.common import BaseClient,
|
|
16
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class PowerClient(BaseClient):
|
bosdyn/client/spot_cam/ptz.py
CHANGED
|
@@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
13
13
|
from google.protobuf.wrappers_pb2 import FloatValue, Int32Value
|
|
14
14
|
|
|
15
15
|
from bosdyn.api.spot_cam import ptz_pb2, service_pb2_grpc
|
|
16
|
-
from bosdyn.client.common import BaseClient, common_header_errors
|
|
16
|
+
from bosdyn.client.common import BaseClient, common_header_errors
|
|
17
17
|
from bosdyn.client.math_helpers import recenter_value_mod
|
|
18
18
|
|
|
19
19
|
|
|
@@ -11,7 +11,7 @@ import logging
|
|
|
11
11
|
_LOGGER = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
from bosdyn.api.spot_cam import service_pb2_grpc, streamquality_pb2
|
|
14
|
-
from bosdyn.client.common import BaseClient,
|
|
14
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class StreamQualityClient(BaseClient):
|
|
@@ -11,7 +11,7 @@ import logging
|
|
|
11
11
|
_LOGGER = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
from bosdyn.api.spot_cam import service_pb2_grpc, version_pb2
|
|
14
|
-
from bosdyn.client.common import BaseClient,
|
|
14
|
+
from bosdyn.client.common import BaseClient, handle_common_header_errors
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class VersionClient(BaseClient):
|