bosdyn-client 5.0.1.1__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.
Files changed (58) hide show
  1. bosdyn/client/access_controlled_door_util.py +206 -0
  2. bosdyn/client/arm_surface_contact.py +2 -2
  3. bosdyn/client/async_tasks.py +3 -2
  4. bosdyn/client/audio_visual.py +6 -7
  5. bosdyn/client/audio_visual_helpers.py +3 -2
  6. bosdyn/client/autowalk.py +0 -2
  7. bosdyn/client/command_line.py +61 -4
  8. bosdyn/client/common.py +1 -1
  9. bosdyn/client/data_acquisition.py +3 -5
  10. bosdyn/client/data_acquisition_helpers.py +0 -3
  11. bosdyn/client/data_acquisition_plugin.py +1 -2
  12. bosdyn/client/data_acquisition_plugin_service.py +3 -2
  13. bosdyn/client/data_acquisition_store.py +1 -7
  14. bosdyn/client/data_buffer.py +5 -4
  15. bosdyn/client/directory_registration.py +3 -2
  16. bosdyn/client/estop.py +3 -2
  17. bosdyn/client/fault.py +1 -1
  18. bosdyn/client/gps/aggregator_client.py +2 -4
  19. bosdyn/client/gps/gps_listener.py +5 -7
  20. bosdyn/client/gps/ntrip_client.py +12 -3
  21. bosdyn/client/graph_nav.py +67 -13
  22. bosdyn/client/hazard_avoidance.py +119 -0
  23. bosdyn/client/image.py +5 -4
  24. bosdyn/client/image_service_helpers.py +6 -7
  25. bosdyn/client/ir_enable_disable.py +1 -1
  26. bosdyn/client/keepalive.py +4 -2
  27. bosdyn/client/lease.py +3 -2
  28. bosdyn/client/lease_validator.py +0 -1
  29. bosdyn/client/log_status.py +57 -3
  30. bosdyn/client/map_processing.py +2 -4
  31. bosdyn/client/network_compute_bridge_client.py +4 -6
  32. bosdyn/client/payload.py +2 -3
  33. bosdyn/client/payload_registration.py +11 -10
  34. bosdyn/client/power.py +84 -27
  35. bosdyn/client/processors.py +27 -2
  36. bosdyn/client/recording.py +3 -3
  37. bosdyn/client/robot_command.py +22 -22
  38. bosdyn/client/robot_state.py +1 -1
  39. bosdyn/client/sdk.py +2 -3
  40. bosdyn/client/service_customization_helpers.py +1 -1
  41. bosdyn/client/spot_cam/audio.py +1 -2
  42. bosdyn/client/spot_cam/health.py +1 -1
  43. bosdyn/client/spot_cam/lighting.py +1 -1
  44. bosdyn/client/spot_cam/media_log.py +1 -1
  45. bosdyn/client/spot_cam/network.py +3 -2
  46. bosdyn/client/spot_cam/power.py +1 -1
  47. bosdyn/client/spot_cam/ptz.py +1 -1
  48. bosdyn/client/spot_cam/streamquality.py +1 -1
  49. bosdyn/client/spot_cam/version.py +1 -1
  50. bosdyn/client/spot_check.py +5 -6
  51. bosdyn/client/url_validation_util.py +220 -0
  52. bosdyn/client/util.py +2 -4
  53. bosdyn/client/world_object.py +1 -1
  54. {bosdyn_client-5.0.1.1.dist-info → bosdyn_client-5.1.0.dist-info}/METADATA +3 -3
  55. bosdyn_client-5.1.0.dist-info/RECORD +106 -0
  56. bosdyn_client-5.0.1.1.dist-info/RECORD +0 -103
  57. {bosdyn_client-5.0.1.1.dist-info → bosdyn_client-5.1.0.dist-info}/WHEEL +0 -0
  58. {bosdyn_client-5.0.1.1.dist-info → bosdyn_client-5.1.0.dist-info}/top_level.txt +0 -0
@@ -8,12 +8,10 @@
8
8
 
9
9
  import collections
10
10
 
11
- from bosdyn.api import (network_compute_bridge_pb2, network_compute_bridge_service_pb2,
12
- network_compute_bridge_service_pb2_grpc)
13
- from bosdyn.client.common import (BaseClient, error_factory, error_pair,
14
- handle_common_header_errors, handle_custom_params_errors,
15
- handle_lease_use_result_errors, handle_unset_status_error)
16
- from bosdyn.client.exceptions import Error, InternalServerError, ResponseError, UnsetStatusError
11
+ from bosdyn.api import network_compute_bridge_pb2, network_compute_bridge_service_pb2_grpc
12
+ from bosdyn.client.common import (BaseClient, error_pair, handle_common_header_errors,
13
+ handle_custom_params_errors)
14
+ from bosdyn.client.exceptions import ResponseError, UnsetStatusError
17
15
 
18
16
 
19
17
  class ExternalServiceNotFoundError(ResponseError):
bosdyn/client/payload.py CHANGED
@@ -11,7 +11,6 @@ This allows client code to read from the robot payload registry.
11
11
 
12
12
  import logging
13
13
 
14
- import bosdyn.api.payload_pb2 as payload_protos
15
14
  import bosdyn.api.payload_pb2 as payload_service_protos
16
15
  import bosdyn.api.payload_service_pb2_grpc as payload_service
17
16
 
@@ -38,7 +37,7 @@ class PayloadClient(BaseClient):
38
37
 
39
38
  Args:
40
39
  kw_args: Extra arguments to pass to grpc call invocation.
41
-
40
+
42
41
  Returns:
43
42
  A list of the proto message definitions of all registered payloads
44
43
 
@@ -54,7 +53,7 @@ class PayloadClient(BaseClient):
54
53
 
55
54
  Args:
56
55
  kw_args: Extra arguments to pass to grpc call invocation.
57
-
56
+
58
57
  Returns:
59
58
  A list of the proto message definitions of all registered payloads
60
59
 
@@ -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
- handle_lease_use_result_errors, handle_unset_status_error)
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 = time.time()
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 = time.time() - exec_start
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, license_pb2, power_pb2,
17
- power_service_pb2_grpc, robot_command_pb2, robot_state_pb2)
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
- This service requires ownership over the robot, in the form of a lease.
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. None if no error."""
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. See safe_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
- means the robot will attempt to sit before powering motors off.
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 = time.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 time.time() < end_time:
318
- time_until_timeout = end_time - time.time()
319
- start_call_time = time.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 = time.time() - start_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. See power_on_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. See power_off_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 = time.time() + timeout_sec
403
- safe_power_off_motors(command_client, state_client, timeout_sec=end_time - time.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 - time.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 = time.time() + timeout_sec
446
- safe_power_off_motors(command_client, state_client, timeout_sec=end_time - time.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 - time.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 = time.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 time.time() < end_time:
570
- time_until_timeout = end_time - time.time()
571
- start_call_time = time.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 = time.time() - start_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
@@ -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)
@@ -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, nav_pb2, recording_pb2, recording_service_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, handle_lease_use_result_errors,
16
- handle_license_errors_if_present, handle_unset_status_error)
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
 
@@ -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
- gripper_command_pb2, mobility_command_pb2, payload_estimation_pb2,
16
- robot_command_pb2, robot_command_service_pb2_grpc, synchronized_command_pb2,
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, SE3Velocity
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 = time.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 = time.time()
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 = time.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 = time.time() - start_call_time
1980
+ delta_t = now_sec() - start_call_time
1981
1981
  time.sleep(max(min(delta_t, update_time), 0.0))
1982
- now = time.time()
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 = time.time()
2082
+ start_time = now_sec()
2083
2083
  end_time = start_time + timeout_sec
2084
- now = time.time()
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 = time.time()
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 = time.time()
2148
+ start_time = now_sec()
2149
2149
  end_time = start_time + timeout_sec
2150
- now = time.time()
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 = time.time()
2176
+ now = now_sec()
2177
2177
 
2178
2178
  if logger is not None:
2179
2179
  logger.info('block_for_trajectory_cmd: timeout exceeded.')
@@ -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(bosdyn.client.__main__.__file__),
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) != proto_type:
152
+ if type(param) is not proto_type:
153
153
  return CustomParamError(
154
154
  status=CustomParamError.STATUS_INVALID_VALUE,
155
155
  error_messages=[
@@ -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, common_header_errors, handle_common_header_errors
16
+ from bosdyn.client.common import BaseClient, handle_common_header_errors
18
17
 
19
18
 
20
19
  class AudioClient(BaseClient):
@@ -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, common_header_errors, handle_common_header_errors
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, common_header_errors, handle_common_header_errors
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, common_header_errors, handle_common_header_errors
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
- """Set ICE configuration on Spot CAM. This overrides all existing configured servers"""
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
- """Get ICE configuration from Spot CAM"""
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
+
@@ -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, common_header_errors, handle_common_header_errors
16
+ from bosdyn.client.common import BaseClient, handle_common_header_errors
17
17
 
18
18
 
19
19
  class PowerClient(BaseClient):