bosdyn-client 3.3.2__py3-none-any.whl → 4.0.1__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 (56) hide show
  1. bosdyn/client/__init__.py +5 -6
  2. bosdyn/client/area_callback_region_handler_base.py +19 -4
  3. bosdyn/client/area_callback_service_servicer.py +29 -1
  4. bosdyn/client/area_callback_service_utils.py +45 -51
  5. bosdyn/client/auth.py +13 -28
  6. bosdyn/client/autowalk.py +3 -0
  7. bosdyn/client/channel.py +23 -26
  8. bosdyn/client/command_line.py +64 -13
  9. bosdyn/client/common.py +4 -4
  10. bosdyn/client/data_acquisition.py +47 -6
  11. bosdyn/client/data_acquisition_plugin.py +12 -2
  12. bosdyn/client/data_acquisition_plugin_service.py +33 -2
  13. bosdyn/client/data_acquisition_store.py +38 -0
  14. bosdyn/client/data_buffer.py +22 -8
  15. bosdyn/client/data_chunk.py +1 -0
  16. bosdyn/client/directory_registration.py +1 -14
  17. bosdyn/client/exceptions.py +0 -4
  18. bosdyn/client/frame_helpers.py +3 -1
  19. bosdyn/client/gps/NMEAParser.py +189 -0
  20. bosdyn/client/gps/__init__.py +6 -0
  21. bosdyn/client/gps/aggregator_client.py +56 -0
  22. bosdyn/client/gps/gps_listener.py +153 -0
  23. bosdyn/client/gps/registration_client.py +48 -0
  24. bosdyn/client/graph_nav.py +50 -20
  25. bosdyn/client/image.py +20 -7
  26. bosdyn/client/image_service_helpers.py +14 -14
  27. bosdyn/client/lease.py +27 -22
  28. bosdyn/client/lease_validator.py +5 -5
  29. bosdyn/client/manipulation_api_client.py +1 -1
  30. bosdyn/client/map_processing.py +10 -5
  31. bosdyn/client/math_helpers.py +21 -11
  32. bosdyn/client/metrics_logging.py +147 -0
  33. bosdyn/client/network_compute_bridge_client.py +6 -0
  34. bosdyn/client/power.py +40 -0
  35. bosdyn/client/recording.py +3 -3
  36. bosdyn/client/robot.py +15 -16
  37. bosdyn/client/robot_command.py +341 -203
  38. bosdyn/client/robot_id.py +6 -5
  39. bosdyn/client/robot_state.py +6 -0
  40. bosdyn/client/sdk.py +5 -11
  41. bosdyn/client/server_util.py +11 -11
  42. bosdyn/client/service_customization_helpers.py +776 -64
  43. bosdyn/client/signals_helpers.py +105 -0
  44. bosdyn/client/spot_cam/compositor.py +6 -2
  45. bosdyn/client/spot_cam/ptz.py +24 -14
  46. bosdyn/client/spot_check.py +160 -0
  47. bosdyn/client/time_sync.py +5 -5
  48. bosdyn/client/units_helpers.py +39 -0
  49. bosdyn/client/util.py +100 -64
  50. bosdyn/client/world_object.py +5 -5
  51. {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/METADATA +4 -3
  52. bosdyn_client-4.0.1.dist-info/RECORD +97 -0
  53. {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/WHEEL +1 -1
  54. bosdyn/client/log_annotation.py +0 -359
  55. bosdyn_client-3.3.2.dist-info/RECORD +0 -90
  56. {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/top_level.txt +0 -0
bosdyn/client/power.py CHANGED
@@ -67,8 +67,16 @@ class FanControlTemperatureError(PowerResponseError):
67
67
  """Current measured robot temperatures are too high to accept user fan command."""
68
68
 
69
69
 
70
+ class SafetyStopIncompatibleHardwareError(PowerResponseError):
71
+ """SafetyStop command invalid because robot is not configured for SRSF."""
70
72
 
71
73
 
74
+ class SafetyStopFailedError(PowerResponseError):
75
+ """SafetyStop command executed and failed."""
76
+
77
+
78
+ class SafetyStopUnknownStopTypeError(PowerResponseError):
79
+ """SafetyStop command failed due to unknown stop type."""
72
80
 
73
81
 
74
82
  class PowerClient(BaseClient):
@@ -136,7 +144,17 @@ class PowerClient(BaseClient):
136
144
  return self.call_async(self._stub.FanPowerCommandFeedback, req, None,
137
145
  _fan_power_feedback_error_from_response, **kwargs)
138
146
 
147
+ def reset_safety_stop(self, safety_stop_type, lease=None, **kwargs):
148
+ """Issue a reset safety stop request to the robot."""
149
+ req = self._reset_safety_stop_request(lease, safety_stop_type)
150
+ return self.call(self._stub.ResetSafetyStop, req, None,
151
+ _reset_safety_stop_error_from_response, **kwargs)
139
152
 
153
+ def reset_safety_stop_async(self, safety_stop_type, lease=None, **kwargs):
154
+ """Async version of reset_safety_stop()"""
155
+ req = self._reset_safety_stop_request(lease, safety_stop_type)
156
+ return self.call_async(self._stub.ResetSafetyStop, req, None,
157
+ _reset_safety_stop_error_from_response, **kwargs)
140
158
 
141
159
  @staticmethod
142
160
  def _power_command_request(lease, request):
@@ -155,6 +173,9 @@ class PowerClient(BaseClient):
155
173
  def _fan_power_command_feedback_request(command_id):
156
174
  return power_pb2.FanPowerCommandFeedbackRequest(command_id=command_id)
157
175
 
176
+ @staticmethod
177
+ def _reset_safety_stop_request(lease, safety_stop_type):
178
+ return power_pb2.ResetSafetyStopRequest(lease=lease, safety_stop_type=safety_stop_type)
158
179
 
159
180
 
160
181
  def _handle_license_errors(func):
@@ -247,6 +268,25 @@ def _fan_power_feedback_error_from_response(response):
247
268
  return None
248
269
 
249
270
 
271
+ @handle_common_header_errors
272
+ @handle_lease_use_result_errors
273
+ @handle_unset_status_error(unset='STATUS_UNKNOWN', statustype=power_pb2.ResetSafetyStopResponse)
274
+ def _reset_safety_stop_error_from_response(response):
275
+ return error_factory(response, response.status,
276
+ status_to_string=power_pb2.ResetSafetyStopResponse.Status.Name,
277
+ status_to_error=_RESET_SAFETY_STOP_STATUS_TO_ERROR)
278
+
279
+
280
+ _RESET_SAFETY_STOP_STATUS_TO_ERROR = collections.defaultdict(lambda: (ResponseError, None))
281
+ _RESET_SAFETY_STOP_STATUS_TO_ERROR.update({
282
+ power_pb2.ResetSafetyStopResponse.STATUS_OK: (None, None),
283
+ power_pb2.ResetSafetyStopResponse.STATUS_INCOMPATIBLE_HARDWARE_ERROR:
284
+ (SafetyStopIncompatibleHardwareError, SafetyStopIncompatibleHardwareError.__doc__),
285
+ power_pb2.ResetSafetyStopResponse.STATUS_FAILED:
286
+ (SafetyStopFailedError, SafetyStopFailedError.__doc__),
287
+ power_pb2.ResetSafetyStopResponse.STATUS_UNKNOWN_STOP_TYPE:
288
+ (SafetyStopUnknownStopTypeError, SafetyStopUnknownStopTypeError.__doc__)
289
+ })
250
290
 
251
291
 
252
292
  @deprecated(reason='Replaced by the less ambiguous safe_power_off_motors function.',
@@ -158,7 +158,7 @@ class GraphNavRecordingServiceClient(BaseClient):
158
158
  **kwargs)
159
159
 
160
160
  def create_edge(self, lease=None, edge=None, **kwargs):
161
- """Create a edge in the map between two existing waypoints.
161
+ """Create an edge in the map between two existing waypoints.
162
162
 
163
163
  Args:
164
164
  lease: Leases to show ownership of necessary resources. Will use the client's leases by default.
@@ -276,7 +276,7 @@ class GraphNavRecordingServiceClient(BaseClient):
276
276
  def make_edge_environment(
277
277
  vel_limit=None, direction_constraint=map_pb2.Edge.Annotations.DIRECTION_CONSTRAINT_NONE,
278
278
  require_alignment=False, flat_ground=False, ground_mu_hint=.8, grated_floor=False):
279
- """Create a edge environment.
279
+ """Create an edge environment.
280
280
 
281
281
  Args:
282
282
  vel_limit: A SE2VelocityLimit to use while traversing the edge. Note this is not a target speed, just a max/min.
@@ -373,7 +373,7 @@ class RemoteCloudFailureNoDataError(RecordingServiceResponseError):
373
373
 
374
374
 
375
375
  class NotReadyYetError(RecordingServiceResponseError):
376
- """The service is processing the map at it's current position. Try again in 1-2 seconds."""
376
+ """The service is processing the map at its current position. Try again in 1-2 seconds."""
377
377
 
378
378
 
379
379
  class MapTooLargeLicenseError(RecordingServiceResponseError):
bosdyn/client/robot.py CHANGED
@@ -8,10 +8,11 @@
8
8
  import copy
9
9
  import logging
10
10
  import time
11
+ from typing import Optional
11
12
 
12
13
  import bosdyn.api.data_buffer_pb2 as data_buffer_protos
13
14
  import bosdyn.client.channel
14
- from bosdyn.util import timestamp_to_sec
15
+ from bosdyn.util import now_sec, timestamp_to_sec
15
16
 
16
17
  from .auth import AuthClient
17
18
  from .channel import DEFAULT_MAX_MESSAGE_LENGTH
@@ -27,9 +28,9 @@ from .payload_registration import (PayloadAlreadyExistsError, PayloadNotAuthoriz
27
28
  PayloadRegistrationClient)
28
29
  from .power import PowerClient
29
30
  from .power import is_powered_on as pkg_is_powered_on
30
- from .power import power_off as pkg_power_off
31
- from .power import power_on as pkg_power_on
32
- from .power import safe_power_off as pkg_safe_power_off
31
+ from .power import power_off_motors as pkg_power_off
32
+ from .power import power_on_motors as pkg_power_on
33
+ from .power import safe_power_off_motors as pkg_safe_power_off
33
34
  from .robot_command import RobotCommandClient
34
35
  from .robot_id import RobotIdClient
35
36
  from .robot_state import RobotStateClient
@@ -125,7 +126,6 @@ class Robot(object):
125
126
  self.service_type_by_name = {}
126
127
  self.request_processors = []
127
128
  self.response_processors = []
128
- self.app_token = None
129
129
  self.cert = None
130
130
  self.lease_wallet = LeaseWallet()
131
131
  self._time_sync_thread = None
@@ -261,7 +261,7 @@ class Robot(object):
261
261
  def get_cached_hardware_hardware_configuration(self):
262
262
  """Return the HardwareConfiguration proto for this robot, querying it from the robot if not
263
263
  yet cached.
264
-
264
+
265
265
  Raises:
266
266
  RpcError: There as a problem communicating with the robot.
267
267
  """
@@ -301,10 +301,9 @@ class Robot(object):
301
301
  if not authority:
302
302
  raise UnregisteredServiceNameError(service_name)
303
303
 
304
- skip_app_token_check = service_name == 'robot-id'
305
- return self.ensure_secure_channel(authority, skip_app_token_check, options=options)
304
+ return self.ensure_secure_channel(authority, options=options)
306
305
 
307
- def ensure_secure_channel(self, authority, skip_app_token_check=False, options=[]):
306
+ def ensure_secure_channel(self, authority, options=[]):
308
307
  """Get the channel to access the given authority, creating it if it doesn't exist."""
309
308
  if authority in self.channels_by_authority:
310
309
  return self.channels_by_authority[authority]
@@ -316,8 +315,8 @@ class Robot(object):
316
315
  options.append(('grpc.max_send_message_length', self.max_send_message_length))
317
316
 
318
317
  # Channel doesn't exist, so create it.
319
- creds = bosdyn.client.channel.create_secure_channel_creds(
320
- self.cert, lambda: (self.app_token, self.user_token))
318
+ creds = bosdyn.client.channel.create_secure_channel_creds(self.cert,
319
+ lambda: self.user_token)
321
320
  channel = bosdyn.client.channel.create_secure_channel(self.address,
322
321
  self._secure_channel_port, creds,
323
322
  authority, options=options)
@@ -346,7 +345,7 @@ class Robot(object):
346
345
  auth_channel = self.ensure_secure_channel(
347
346
  Robot._bootstrap_service_authorities[AuthClient.default_service_name])
348
347
  auth_client = self.ensure_client(AuthClient.default_service_name, auth_channel)
349
- user_token = auth_client.auth(username, password, self.app_token, timeout=timeout)
348
+ user_token = auth_client.auth(username, password, timeout=timeout)
350
349
 
351
350
  self.update_user_token(user_token, username)
352
351
 
@@ -362,7 +361,7 @@ class Robot(object):
362
361
  # We cannot use the directory for the auth service until we are authenticated, so hard-code
363
362
  # the authority name.
364
363
  auth_client = self.ensure_client(AuthClient.default_service_name)
365
- user_token = auth_client.auth_with_token(token, self.app_token, timeout=timeout)
364
+ user_token = auth_client.auth_with_token(token, timeout=timeout)
366
365
 
367
366
  self.update_user_token(user_token)
368
367
 
@@ -379,7 +378,7 @@ class Robot(object):
379
378
  # We cannot use the directory for the auth service until we are authenticated, so hard-code
380
379
  # the authority name.
381
380
  auth_client = self.ensure_client(AuthClient.default_service_name)
382
- user_token = auth_client.auth_with_token(token, self.app_token, timeout=timeout)
381
+ user_token = auth_client.auth_with_token(token, timeout=timeout)
383
382
 
384
383
  self.update_user_token(user_token, username)
385
384
 
@@ -519,7 +518,7 @@ class Robot(object):
519
518
  Returns:
520
519
  double: Current robot time, seconds.
521
520
  """
522
- robot_timestamp = self.time_sync.robot_timestamp_from_local_secs(time.time())
521
+ robot_timestamp = self.time_sync.robot_timestamp_from_local_secs(now_sec())
523
522
  return timestamp_to_sec(robot_timestamp)
524
523
 
525
524
  def operator_comment(self, comment, timestamp_secs=None, timeout=None):
@@ -542,7 +541,7 @@ class Robot(object):
542
541
  client = self.ensure_client(DataBufferClient.default_service_name)
543
542
  if timestamp_secs is None:
544
543
  try:
545
- robot_timestamp = self.time_sync.robot_timestamp_from_local_secs(time.time())
544
+ robot_timestamp = self.time_sync.robot_timestamp_from_local_secs(now_sec())
546
545
  except TimeSyncError:
547
546
  robot_timestamp = None # Timestamp will be set when robot receives the request msg.
548
547
  else: