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.
- bosdyn/client/__init__.py +5 -6
- bosdyn/client/area_callback_region_handler_base.py +19 -4
- bosdyn/client/area_callback_service_servicer.py +29 -1
- bosdyn/client/area_callback_service_utils.py +45 -51
- bosdyn/client/auth.py +13 -28
- bosdyn/client/autowalk.py +3 -0
- bosdyn/client/channel.py +23 -26
- bosdyn/client/command_line.py +64 -13
- bosdyn/client/common.py +4 -4
- bosdyn/client/data_acquisition.py +47 -6
- bosdyn/client/data_acquisition_plugin.py +12 -2
- bosdyn/client/data_acquisition_plugin_service.py +33 -2
- bosdyn/client/data_acquisition_store.py +38 -0
- bosdyn/client/data_buffer.py +22 -8
- bosdyn/client/data_chunk.py +1 -0
- bosdyn/client/directory_registration.py +1 -14
- bosdyn/client/exceptions.py +0 -4
- bosdyn/client/frame_helpers.py +3 -1
- bosdyn/client/gps/NMEAParser.py +189 -0
- bosdyn/client/gps/__init__.py +6 -0
- bosdyn/client/gps/aggregator_client.py +56 -0
- bosdyn/client/gps/gps_listener.py +153 -0
- bosdyn/client/gps/registration_client.py +48 -0
- bosdyn/client/graph_nav.py +50 -20
- bosdyn/client/image.py +20 -7
- bosdyn/client/image_service_helpers.py +14 -14
- bosdyn/client/lease.py +27 -22
- bosdyn/client/lease_validator.py +5 -5
- bosdyn/client/manipulation_api_client.py +1 -1
- bosdyn/client/map_processing.py +10 -5
- bosdyn/client/math_helpers.py +21 -11
- bosdyn/client/metrics_logging.py +147 -0
- bosdyn/client/network_compute_bridge_client.py +6 -0
- bosdyn/client/power.py +40 -0
- bosdyn/client/recording.py +3 -3
- bosdyn/client/robot.py +15 -16
- bosdyn/client/robot_command.py +341 -203
- bosdyn/client/robot_id.py +6 -5
- bosdyn/client/robot_state.py +6 -0
- bosdyn/client/sdk.py +5 -11
- bosdyn/client/server_util.py +11 -11
- bosdyn/client/service_customization_helpers.py +776 -64
- bosdyn/client/signals_helpers.py +105 -0
- bosdyn/client/spot_cam/compositor.py +6 -2
- bosdyn/client/spot_cam/ptz.py +24 -14
- bosdyn/client/spot_check.py +160 -0
- bosdyn/client/time_sync.py +5 -5
- bosdyn/client/units_helpers.py +39 -0
- bosdyn/client/util.py +100 -64
- bosdyn/client/world_object.py +5 -5
- {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/METADATA +4 -3
- bosdyn_client-4.0.1.dist-info/RECORD +97 -0
- {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/WHEEL +1 -1
- bosdyn/client/log_annotation.py +0 -359
- bosdyn_client-3.3.2.dist-info/RECORD +0 -90
- {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.',
|
bosdyn/client/recording.py
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
31
|
-
from .power import
|
|
32
|
-
from .power import
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
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:
|