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
@@ -8,7 +8,6 @@
8
8
  import collections
9
9
  import time
10
10
 
11
- from deprecated.sphinx import deprecated
12
11
  from google.protobuf import any_pb2, wrappers_pb2
13
12
 
14
13
  from bosdyn import geometry
@@ -16,6 +15,9 @@ from bosdyn.api import (arm_command_pb2, basic_command_pb2, full_body_command_pb
16
15
  gripper_command_pb2, mobility_command_pb2, payload_estimation_pb2,
17
16
  robot_command_pb2, robot_command_service_pb2_grpc, synchronized_command_pb2,
18
17
  trajectory_pb2)
18
+
19
+ # isort: off
20
+ # isort: on
19
21
  from bosdyn.api.spot import robot_command_pb2 as spot_command_pb2
20
22
  from bosdyn.client.common import (BaseClient, error_factory, error_pair,
21
23
  handle_common_header_errors, handle_lease_use_result_errors,
@@ -26,7 +28,7 @@ from .exceptions import Error as BaseError
26
28
  from .exceptions import InvalidRequestError, ResponseError, TimedOutError, UnsetStatusError
27
29
  from .frame_helpers import BODY_FRAME_NAME, ODOM_FRAME_NAME, get_se2_a_tform_b
28
30
  from .lease import add_lease_wallet_processors
29
- from .math_helpers import SE2Pose, SE3Pose
31
+ from .math_helpers import SE2Pose, SE3Pose, SE3Velocity
30
32
 
31
33
  # The angles (in radians) that represent the claw gripper open and closed positions.
32
34
  _CLAW_GRIPPER_OPEN_ANGLE = -1.5708
@@ -164,19 +166,6 @@ END_TIME_EDIT_TREE = {
164
166
  }
165
167
  }
166
168
  }
167
- },
168
- 'mobility_command': {
169
- '@command': { # 'command' is a oneof submessage
170
- 'se2_velocity_request': {
171
- 'end_time': None
172
- },
173
- 'se2_trajectory_request': {
174
- 'end_time': None
175
- },
176
- 'stance_request': {
177
- 'end_time': None
178
- }
179
- }
180
169
  }
181
170
  }
182
171
 
@@ -234,15 +223,6 @@ EDIT_TREE_CONVERT_LOCAL_TIME_TO_ROBOT_TIME = {
234
223
  }
235
224
  }
236
225
  }
237
- },
238
- 'mobility_command': {
239
- '@command': {
240
- 'se2_trajectory_request': {
241
- 'trajectory': {
242
- 'reference_time': None
243
- }
244
- }
245
- }
246
226
  }
247
227
  }
248
228
 
@@ -542,6 +522,8 @@ class RobotCommandClient(BaseClient):
542
522
  behavior_fault_id=behavior_fault_id)
543
523
 
544
524
 
525
+
526
+
545
527
  def _robot_command_value(response):
546
528
  """Get the command id from a RobotCommandResponse.
547
529
 
@@ -594,9 +576,7 @@ def _robot_command_error(response):
594
576
  def _robot_command_feedback_error(response):
595
577
  # Write custom handling unset errors here. Only one of these statuses needs to be set.
596
578
  field = 'status'
597
- code = getattr(response, 'STATUS_UNKNOWN')
598
- if ((getattr(response, field) != code) or
599
- (getattr(response.feedback.full_body_feedback, field)) or
579
+ if ((getattr(response.feedback.full_body_feedback, field)) or
600
580
  (getattr(response.feedback.synchronized_feedback.mobility_command_feedback, field)) or
601
581
  (getattr(response.feedback.synchronized_feedback.arm_command_feedback, field)) or
602
582
  (getattr(response.feedback.synchronized_feedback.gripper_command_feedback, field))):
@@ -776,138 +756,10 @@ class RobotCommandBuilder(object):
776
756
  command = robot_command_pb2.RobotCommand(full_body_command=full_body_command)
777
757
  return command
778
758
 
779
- ###################################
780
- # Mobility commands - DEPRECATED #
781
- ###################################
782
-
783
- @staticmethod
784
- @deprecated(reason='Mobility commands are now sent as a part of synchronized commands. '
785
- 'Use synchro_se2_trajectory_command instead.', version='2.1.0', action="always")
786
- def trajectory_command(goal_x, goal_y, goal_heading, frame_name, params=None, body_height=0.0,
787
- locomotion_hint=spot_command_pb2.HINT_AUTO):
788
- """
789
- Command robot to move to pose along a 2D plane. Pose can be specified in the world
790
- (kinematic odometry) frame or the robot body frame. The arguments body_height and
791
- locomotion_hint are ignored if params argument is passed.
792
-
793
- A trajectory command requires an end time. End time is not set in this function, but rather
794
- is set externally before call to RobotCommandService.
795
-
796
- Args:
797
- goal_x: Position X coordinate.
798
- goal_y: Position Y coordinate.
799
- goal_heading: Pose heading in radians.
800
- frame_name: Name of the frame to use.
801
- params(spot.MobilityParams): Spot specific parameters for mobility commands. If not set,
802
- this will be constructed using other args.
803
- body_height: Height, meters, relative to a nominal stand height.
804
- locomotion_hint: Locomotion hint to use for the trajectory command.
805
-
806
- Returns:
807
- RobotCommand, which can be issued to the robot command service.
808
- """
809
- if not params:
810
- params = RobotCommandBuilder.mobility_params(body_height=body_height,
811
- locomotion_hint=locomotion_hint)
812
- any_params = RobotCommandBuilder._to_any(params)
813
- position = geometry_pb2.Vec2(x=goal_x, y=goal_y)
814
- pose = geometry_pb2.SE2Pose(position=position, angle=goal_heading)
815
- point = trajectory_pb2.SE2TrajectoryPoint(pose=pose)
816
- traj = trajectory_pb2.SE2Trajectory(points=[point])
817
- traj_command = basic_command_pb2.SE2TrajectoryCommand.Request(trajectory=traj,
818
- se2_frame_name=frame_name)
819
- mobility_command = mobility_command_pb2.MobilityCommand.Request(
820
- se2_trajectory_request=traj_command, params=any_params)
821
- command = robot_command_pb2.RobotCommand(mobility_command=mobility_command)
822
- return command
823
-
824
- @staticmethod
825
- @deprecated(reason='Mobility commands are now sent as a part of synchronized commands. '
826
- 'Use synchro_velocity_command instead.', version='2.1.0', action="always")
827
- def velocity_command(v_x, v_y, v_rot, params=None, body_height=0.0,
828
- locomotion_hint=spot_command_pb2.HINT_AUTO, frame_name=BODY_FRAME_NAME):
829
- """
830
- Command robot to move along 2D plane. Velocity should be specified in the robot body
831
- frame. Other frames are currently not supported. The arguments body_height and
832
- locomotion_hint are ignored if params argument is passed.
833
-
834
- A velocity command requires an end time. End time is not set in this function, but rather
835
- is set externally before call to RobotCommandService.
836
-
837
- Args:
838
- v_x: Velocity in X direction.
839
- v_y: Velocity in Y direction.
840
- v_rot: Velocity heading in radians.
841
- params(spot.MobilityParams): Spot specific parameters for mobility commands. If not set,
842
- this will be constructed using other args.
843
- body_height: Height, meters, relative to a nominal stand height.
844
- locomotion_hint: Locomotion hint to use for the velocity command.
845
- frame_name: Name of the frame to use.
846
- """
847
- if not params:
848
- params = RobotCommandBuilder.mobility_params(body_height=body_height,
849
- locomotion_hint=locomotion_hint)
850
- any_params = RobotCommandBuilder._to_any(params)
851
- linear = geometry_pb2.Vec2(x=v_x, y=v_y)
852
- vel = geometry_pb2.SE2Velocity(linear=linear, angular=v_rot)
853
- slew_rate_limit = geometry_pb2.SE2Velocity(linear=geometry_pb2.Vec2(x=4, y=4), angular=2.0)
854
- vel_command = basic_command_pb2.SE2VelocityCommand.Request(velocity=vel,
855
- se2_frame_name=frame_name,
856
- slew_rate_limit=slew_rate_limit)
857
- mobility_command = mobility_command_pb2.MobilityCommand.Request(
858
- se2_velocity_request=vel_command, params=any_params)
859
- command = robot_command_pb2.RobotCommand(mobility_command=mobility_command)
860
- return command
861
-
862
759
  @staticmethod
863
- @deprecated(reason='Mobility commands are now sent as a part of synchronized commands. '
864
- 'Use synchro_stand_command instead.', version='2.1.0', action="always")
865
- def stand_command(params=None, body_height=0.0, footprint_R_body=geometry.EulerZXY()):
866
- """
867
- Command robot to stand. If the robot is sitting, it will stand up. If the robot is
868
- moving, it will come to a stop. Params can specify a trajectory for the body to follow
869
- while standing. In the simplest case, this can be a specific position+orientation which the
870
- body will hold at. The arguments body_height and footprint_R_body are ignored if params
871
- argument is passed.
872
-
873
- Args:
874
- params(spot.MobilityParams): Spot specific parameters for mobility commands. If not set,
875
- this will be constructed using other args.
876
- body_height(float): Height, meters, to stand at relative to a nominal stand height.
877
- footprint_R_body(EulerZXY): The orientation of the body frame with respect to the
878
- footprint frame (gravity aligned framed with yaw computed from the stance feet)
879
-
880
- Returns:
881
- RobotCommand, which can be issued to the robot command service.
882
- """
883
- if not params:
884
- params = RobotCommandBuilder.mobility_params(body_height=body_height,
885
- footprint_R_body=footprint_R_body)
886
- any_params = RobotCommandBuilder._to_any(params)
887
- mobility_command = mobility_command_pb2.MobilityCommand.Request(
888
- stand_request=basic_command_pb2.StandCommand.Request(), params=any_params)
889
- command = robot_command_pb2.RobotCommand(mobility_command=mobility_command)
890
- return command
891
-
892
- @staticmethod
893
- @deprecated(reason='Mobility commands are now sent as a part of synchronized commands. '
894
- 'Use synchro_sit_command instead.', version='2.1.0', action="always")
895
- def sit_command(params=None):
896
- """
897
- Command the robot to sit.
898
-
899
- Args:
900
- params(spot.MobilityParams): Spot specific parameters for mobility commands.
901
-
902
- Returns:
903
- RobotCommand, which can be issued to the robot command service.
904
- """
905
- if not params:
906
- params = RobotCommandBuilder.mobility_params()
907
- any_params = RobotCommandBuilder._to_any(params)
908
- mobility_command = mobility_command_pb2.MobilityCommand.Request(
909
- sit_request=basic_command_pb2.SitCommand.Request(), params=any_params)
910
- command = robot_command_pb2.RobotCommand(mobility_command=mobility_command)
760
+ def joint_command():
761
+ command = robot_command_pb2.RobotCommand()
762
+ command.full_body_command.joint_request.SetInParent()
911
763
  return command
912
764
 
913
765
  #########################
@@ -992,10 +844,9 @@ class RobotCommandBuilder(object):
992
844
  return robot_command
993
845
 
994
846
  @staticmethod
995
- def synchro_trajectory_command_in_body_frame(goal_x_rt_body, goal_y_rt_body,
996
- goal_heading_rt_body, frame_tree_snapshot,
997
- params=None, body_height=0.0,
998
- locomotion_hint=spot_command_pb2.HINT_AUTO):
847
+ def synchro_trajectory_command_in_body_frame(
848
+ goal_x_rt_body, goal_y_rt_body, goal_heading_rt_body, frame_tree_snapshot, params=None,
849
+ body_height=0.0, locomotion_hint=spot_command_pb2.HINT_AUTO, build_on_command=None):
999
850
  """Command robot to move to pose described relative to the robots body along a 2D plane. For example,
1000
851
  a command to move forward 2 meters at the same heading will have goal_x_rt_body=2.0, goal_y_rt_body=0.0,
1001
852
  goal_heading_rt_body=0.0.
@@ -1027,7 +878,8 @@ class RobotCommandBuilder(object):
1027
878
  odom_tform_goto = odom_tform_body * goto_rt_body
1028
879
  return RobotCommandBuilder.synchro_se2_trajectory_command(odom_tform_goto.to_proto(),
1029
880
  ODOM_FRAME_NAME, params,
1030
- body_height, locomotion_hint)
881
+ body_height, locomotion_hint,
882
+ build_on_command=build_on_command)
1031
883
 
1032
884
  @staticmethod
1033
885
  def synchro_velocity_command(v_x, v_y, v_rot, params=None, body_height=0.0,
@@ -1251,7 +1103,7 @@ class RobotCommandBuilder(object):
1251
1103
  frame1_name=frame_name)
1252
1104
 
1253
1105
  if frame2_tform_desired_hand is not None and frame2_name is not None:
1254
- if type(frame2_tform_desired_hand) == SE3Pose:
1106
+ if isinstance(frame2_tform_desired_hand, SE3Pose):
1255
1107
  # Convert input argument from math_helpers class to protobuf message.
1256
1108
  frame2_tform_desired_hand = frame2_tform_desired_hand.to_proto()
1257
1109
 
@@ -1355,25 +1207,109 @@ class RobotCommandBuilder(object):
1355
1207
  return robot_command
1356
1208
 
1357
1209
  @staticmethod
1358
- def claw_gripper_open_command(build_on_command=None):
1359
- command = robot_command_pb2.RobotCommand()
1360
- command.synchronized_command.gripper_command.claw_gripper_command.trajectory.points.add(
1361
- ).point = _CLAW_GRIPPER_OPEN_ANGLE
1210
+ def claw_gripper_open_command(build_on_command=None, max_acc=None, max_vel=None):
1211
+ """Builds a command to open the gripper. Wraps it in SynchronizedCommand.
1212
+
1213
+ Args:
1214
+ build_on_command: Option to input a RobotCommand (not containing a full_body_command). An
1215
+ arm_command and mobility_command from this incoming RobotCommand will be added
1216
+ to the returned RobotCommand.
1217
+ max_acc: Optional maximum allowable gripper acceleration. Not setting this will lead to the
1218
+ robot using a relatively safe low default. If the user is sure their gripper
1219
+ trajectory is safe and achievable, this can be set to a large value so it
1220
+ doesn't get in the way.
1221
+ max_vel: Optional maximum allowable gripper velocity. Same thing about defaults as max_acc.
1222
+
1223
+ Returns:
1224
+ robot_command_pb2.RobotCommand with a claw_gripper_command filled out.
1225
+ """
1226
+
1227
+ robot_cmd = robot_command_pb2.RobotCommand()
1228
+ gripper_cmd = robot_cmd.synchronized_command.gripper_command.claw_gripper_command
1229
+ gripper_cmd.trajectory.points.add().point = _CLAW_GRIPPER_OPEN_ANGLE
1230
+
1231
+ if max_acc is not None:
1232
+ # Set a maximum allowable joint acceleration if desired.
1233
+ # If unset, a safe default will be used
1234
+ gripper_cmd.maximum_open_close_acceleration.value = max_acc
1235
+ if max_vel is not None:
1236
+ # Set a maximum allowable joint velocity if desired.
1237
+ # If unset, a safe default will be used
1238
+ gripper_cmd.maximum_open_close_velocity.value = max_vel
1239
+
1362
1240
  if build_on_command:
1363
- return RobotCommandBuilder.build_synchro_command(build_on_command, command)
1364
- return command
1241
+ return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1242
+ return robot_cmd
1365
1243
 
1366
1244
  @staticmethod
1367
- def claw_gripper_close_command(build_on_command=None):
1368
- command = robot_command_pb2.RobotCommand()
1369
- command.synchronized_command.gripper_command.claw_gripper_command.trajectory.points.add(
1370
- ).point = _CLAW_GRIPPER_CLOSED_ANGLE
1245
+ def claw_gripper_close_command(build_on_command=None, max_acc=None, max_vel=None,
1246
+ disable_force_on_contact=False, max_torque=None):
1247
+ """Builds a command to close the gripper. Wraps it in SynchronizedCommand.
1248
+
1249
+ Args:
1250
+ build_on_command: Option to input a RobotCommand (not containing a full_body_command). An
1251
+ arm_command and mobility_command from this incoming RobotCommand will be added
1252
+ to the returned RobotCommand.
1253
+ max_acc: Optional maximum allowable gripper acceleration. Not setting this will lead to the
1254
+ robot using a relatively safe low default. If the user is sure their gripper
1255
+ trajectory is safe and achievable, this can be set to a large value so it
1256
+ doesn't get in the way.
1257
+ max_vel: Optional maximum allowable gripper velocity. Same thing about defaults as max_acc.
1258
+ disable_force_on_contact: Whether to switch the gripper to force control on contact detection.
1259
+ max_torque: Optional Maximum torque applied if contact detected closing the gripper. If
1260
+ unspecified, a default value of 5.5 (Nm) will be used.
1261
+
1262
+ Returns:
1263
+ robot_command_pb2.RobotCommand with a claw_gripper_command filled out.
1264
+ """
1265
+
1266
+ robot_cmd = robot_command_pb2.RobotCommand()
1267
+ gripper_cmd = robot_cmd.synchronized_command.gripper_command.claw_gripper_command
1268
+ gripper_cmd.trajectory.points.add().point = _CLAW_GRIPPER_CLOSED_ANGLE
1269
+
1270
+ if max_acc is not None:
1271
+ # Set a maximum allowable joint acceleration if desired.
1272
+ # If unset, a safe default will be used
1273
+ gripper_cmd.maximum_open_close_acceleration.value = max_acc
1274
+ if max_vel is not None:
1275
+ # Set a maximum allowable joint velocity if desired.
1276
+ # If unset, a safe default will be used
1277
+ gripper_cmd.maximum_open_close_velocity.value = max_vel
1278
+ if max_torque is not None:
1279
+ # Maximum torque applied if contact detected closing the gripper.
1280
+ # If unspecified, a default value of 5.5 (Nm) will be used.
1281
+ gripper_cmd.maximum_torque.value = max_torque
1282
+
1283
+ gripper_cmd.disable_force_on_contact = disable_force_on_contact
1284
+
1371
1285
  if build_on_command:
1372
- return RobotCommandBuilder.build_synchro_command(build_on_command, command)
1373
- return command
1286
+ return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1287
+ return robot_cmd
1374
1288
 
1375
1289
  @staticmethod
1376
- def claw_gripper_open_fraction_command(open_fraction, build_on_command=None):
1290
+ def claw_gripper_open_fraction_command(open_fraction, build_on_command=None, max_acc=None,
1291
+ max_vel=None, disable_force_on_contact=False,
1292
+ max_torque=None):
1293
+ """Builds a command to set the gripper using a fractional input. Wraps it in SynchronizedCommand.
1294
+
1295
+ Args:
1296
+ open_fraction: Percentage [0, 1] to open the gripper. 0 fully closed, 1 fully open.
1297
+ build_on_command: Option to input a RobotCommand (not containing a full_body_command). An
1298
+ arm_command and mobility_command from this incoming RobotCommand will be added
1299
+ to the returned RobotCommand.
1300
+ max_acc: Optional maximum allowable gripper acceleration. Not setting this will lead to the
1301
+ robot using a relatively safe low default. If the user is sure their gripper
1302
+ trajectory is safe and achievable, this can be set to a large value so it
1303
+ doesn't get in the way.
1304
+ max_vel: Optional maximum allowable gripper velocity. Same thing about defaults as max_acc.
1305
+ disable_force_on_contact: Whether to switch the gripper to force control on contact detection.
1306
+ max_torque: Optional Maximum torque applied if contact detected closing the gripper. If
1307
+ unspecified, a default value of 5.5 (Nm) will be used.
1308
+
1309
+ Returns:
1310
+ robot_command_pb2.RobotCommand with a claw_gripper_command filled out.
1311
+ """
1312
+
1377
1313
  gripper_q = 0
1378
1314
  if open_fraction <= 0:
1379
1315
  gripper_q = _CLAW_GRIPPER_CLOSED_ANGLE
@@ -1383,21 +1319,75 @@ class RobotCommandBuilder(object):
1383
1319
  gripper_q = ((_CLAW_GRIPPER_OPEN_ANGLE - _CLAW_GRIPPER_CLOSED_ANGLE) *
1384
1320
  open_fraction) + _CLAW_GRIPPER_CLOSED_ANGLE
1385
1321
 
1386
- command = robot_command_pb2.RobotCommand()
1387
- command.synchronized_command.gripper_command.claw_gripper_command.trajectory.points.add(
1388
- ).point = gripper_q
1322
+ robot_cmd = robot_command_pb2.RobotCommand()
1323
+ gripper_cmd = robot_cmd.synchronized_command.gripper_command.claw_gripper_command
1324
+ gripper_cmd.trajectory.points.add().point = gripper_q
1325
+
1326
+ if max_acc is not None:
1327
+ # Set a maximum allowable joint acceleration if desired.
1328
+ # If unset, a safe default will be used
1329
+ gripper_cmd.maximum_open_close_acceleration.value = max_acc
1330
+ if max_vel is not None:
1331
+ # Set a maximum allowable joint velocity if desired.
1332
+ # If unset, a safe default will be used
1333
+ gripper_cmd.maximum_open_close_velocity.value = max_vel
1334
+ if max_torque is not None:
1335
+ # Maximum torque applied if contact detected closing the gripper.
1336
+ # If unspecified, a default value of 5.5 (Nm) will be used.
1337
+ gripper_cmd.maximum_torque.value = max_torque
1338
+
1339
+ gripper_cmd.disable_force_on_contact = disable_force_on_contact
1340
+
1389
1341
  if build_on_command:
1390
- return RobotCommandBuilder.build_synchro_command(build_on_command, command)
1391
- return command
1342
+ return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1343
+ return robot_cmd
1392
1344
 
1393
1345
  @staticmethod
1394
- def claw_gripper_open_angle_command(gripper_q, build_on_command=None):
1395
- command = robot_command_pb2.RobotCommand()
1396
- command.synchronized_command.gripper_command.claw_gripper_command.trajectory.points.add(
1397
- ).point = gripper_q
1346
+ def claw_gripper_open_angle_command(gripper_q, build_on_command=None, max_acc=None,
1347
+ max_vel=None, disable_force_on_contact=False,
1348
+ max_torque=None):
1349
+ """Builds a command to set the gripper open angle. Wraps it in SynchronizedCommand.
1350
+
1351
+ Args:
1352
+ gripper_q: [-1.5708, 0] where -1.5708 is fully open and 0 is fully closed.
1353
+ build_on_command: Option to input a RobotCommand (not containing a full_body_command). An
1354
+ arm_command and mobility_command from this incoming RobotCommand will be added
1355
+ to the returned RobotCommand.
1356
+ max_acc: Optional maximum allowable gripper acceleration. Not setting this will lead to the
1357
+ robot using a relatively safe low default. If the user is sure their gripper
1358
+ trajectory is safe and achievable, this can be set to a large value so it
1359
+ doesn't get in the way.
1360
+ max_vel: Optional maximum allowable gripper velocity. Same thing about defaults as max_acc.
1361
+ disable_force_on_contact: Whether to switch the gripper to force control on contact detection.
1362
+ max_torque: Optional Maximum torque applied if contact detected closing the gripper. If
1363
+ unspecified, a default value of 5.5 (Nm) will be used.
1364
+
1365
+ Returns:
1366
+ robot_command_pb2.RobotCommand with a claw_gripper_command filled out.
1367
+ """
1368
+
1369
+ robot_cmd = robot_command_pb2.RobotCommand()
1370
+ gripper_cmd = robot_cmd.synchronized_command.gripper_command.claw_gripper_command
1371
+ gripper_cmd.trajectory.points.add().point = gripper_q
1372
+
1373
+ if max_acc is not None:
1374
+ # Set a maximum allowable joint acceleration if desired.
1375
+ # If unset, a safe default will be used
1376
+ gripper_cmd.maximum_open_close_acceleration.value = max_acc
1377
+ if max_vel is not None:
1378
+ # Set a maximum allowable joint velocity if desired.
1379
+ # If unset, a safe default will be used
1380
+ gripper_cmd.maximum_open_close_velocity.value = max_vel
1381
+ if max_torque is not None:
1382
+ # Maximum torque applied if contact detected closing the gripper.
1383
+ # If unspecified, a default value of 5.5 (Nm) will be used.
1384
+ gripper_cmd.maximum_torque.value = max_torque
1385
+
1386
+ gripper_cmd.disable_force_on_contact = disable_force_on_contact
1387
+
1398
1388
  if build_on_command:
1399
- return RobotCommandBuilder.build_synchro_command(build_on_command, command)
1400
- return command
1389
+ return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1390
+ return robot_cmd
1401
1391
 
1402
1392
  @staticmethod
1403
1393
  def create_arm_joint_trajectory_point(sh0, sh1, el0, el1, wr0, wr1,
@@ -1534,9 +1524,131 @@ class RobotCommandBuilder(object):
1534
1524
  return robot_cmd
1535
1525
 
1536
1526
  @staticmethod
1537
- def claw_gripper_command_helper(gripper_positions, times, gripper_velocities=None,
1538
- ref_time=None, max_acc=None, max_vel=None,
1539
- disable_force_on_contact=False, build_on_command=None):
1527
+ def arm_cartesian_move_helper(se3_poses, times, root_frame_name, wrist_tform_tool=None,
1528
+ root_tform_task=None, se3_velocities=None, ref_time=None,
1529
+ max_acc=None, max_linear_vel=None, max_angular_vel=None,
1530
+ build_on_command=None):
1531
+ """Given a set of SE3Poses, times, and optional velocities, create a synchro command
1532
+ containing an arm_cartesian_command.
1533
+
1534
+ Args:
1535
+ se3_poses (geometry_pb2.SE3Pose): A list of length N with SE3 transforms at each knot point in our
1536
+ trajectory.
1537
+ times: A list of length N with the corresponding time_since_reference for
1538
+ each of our knots.
1539
+ root_frame_name: The name of the root frame. It must be a valid frame name in the
1540
+ frame_tree.
1541
+ wrist_tform_tool (geometry_pb2.SE3Pose): The optional tool pose to use during the move. If unset, defaults to
1542
+ a pose slightly in front of the gripper's palm plate aligned with the wrist's
1543
+ orientation.
1544
+ root_tform_task (geometry_pb2.SE3Pose): The SE3 transform between the root and the task frame.
1545
+ If unset, it will treat the root frame as the task frame.
1546
+ se3_velocities (geometry_pb2.SE3Velocity): An optional list of length N with SE3 velocities at each knot point in
1547
+ our trajectory.
1548
+ ref_time: Optional reference time for the trajectory gotten from the computer. If unset, we'll use the current
1549
+ robot-synchronized time
1550
+ max_acc: Optional maximum allowable linear acceleration (m/s^2).
1551
+ max_linear_vel: Optional maximum allowable linear velocity (m/s).
1552
+ max_angular_vel: Optional maximum allowable angular velocity (rad/s).
1553
+ build_on_command: Option to input a RobotCommand for synchronous commands.
1554
+
1555
+ Returns:
1556
+ robot_command_pb2.RobotCommand with an arm_cartesian_command filled out.
1557
+ """
1558
+
1559
+ assert se3_poses is not None, "Must pass in a list of SE3Poses"
1560
+ assert times is not None, "Must pass in a list of times"
1561
+ assert len(se3_poses) == len(times), "Number of poses must match number of times"
1562
+ if se3_velocities is not None:
1563
+ assert len(se3_velocities) == len(
1564
+ times), "Number of SE3Velocities must match number of times"
1565
+
1566
+ # Create an arm_cartesian_command, and set the trajectory
1567
+ robot_cmd = robot_command_pb2.RobotCommand()
1568
+ arm_cartesian_command = robot_cmd.synchronized_command.arm_command.arm_cartesian_command
1569
+ arm_cartesian_traj = arm_cartesian_command.pose_trajectory_in_task
1570
+ arm_cartesian_traj.pos_interpolation = trajectory_pb2.POS_INTERP_CUBIC
1571
+ arm_cartesian_traj.ang_interpolation = trajectory_pb2.ANG_INTERP_CUBIC_EULER
1572
+ for i, time in enumerate(times):
1573
+ # Add a new trajectory point to our trajectory
1574
+ traj_point = arm_cartesian_traj.points.add()
1575
+
1576
+ se3pose = se3_poses[i]
1577
+
1578
+ # If it is not a geometry_pb2.SE3Pose, throw an error.
1579
+ assert isinstance(
1580
+ se3pose, geometry_pb2.SE3Pose), ('All poses must be of type geometry_pb2.SE3Pose')
1581
+
1582
+ traj_point.pose.CopyFrom(se3pose)
1583
+ if se3_velocities is not None:
1584
+ se3_velocity = se3_velocities[i]
1585
+
1586
+ assert isinstance(se3_velocity, geometry_pb2.SE3Velocity), (
1587
+ 'All Velocities must be of type geometry_pb2.SE3Velocity')
1588
+
1589
+ traj_point.velocity.CopyFrom(se3_velocity)
1590
+
1591
+ # Set our time_since_reference for this trajectory point
1592
+ traj_point.time_since_reference.CopyFrom(seconds_to_duration(times[i]))
1593
+
1594
+ if ref_time is not None:
1595
+ # Set a reference time if desired. If not, we'll automatically set the reference time
1596
+ # to be the current robot-synchronized time
1597
+ arm_cartesian_traj.reference_time.CopyFrom(ref_time)
1598
+
1599
+ if max_acc is not None:
1600
+ # Set a maximum allowable linear acceleration if desired.
1601
+ # If unset, a safe default will be used
1602
+ arm_cartesian_command.maximum_acceleration.value = max_acc
1603
+
1604
+ if max_linear_vel is not None:
1605
+ # Set a maximum allowable linear velocity if desired.
1606
+ # If unset, a safe default will be used
1607
+ arm_cartesian_command.max_linear_velocity.value = max_linear_vel
1608
+
1609
+ if max_angular_vel is not None:
1610
+ # Set a maximum allowable angular velocity if desired.
1611
+ # If unset, a safe default will be used
1612
+ arm_cartesian_command.max_angular_velocity.value = max_angular_vel
1613
+
1614
+ if wrist_tform_tool is not None:
1615
+ # Set the gripper position if it is a valid SE3Pose.
1616
+ # If unset, defaults to a pose slightly in front of the gripper's palm plate aligned
1617
+ # with the wrist's orientation.
1618
+ assert isinstance(
1619
+ wrist_tform_tool,
1620
+ geometry_pb2.SE3Pose), 'All poses must be of type geometry_pb2.SE3Pose'
1621
+
1622
+ arm_cartesian_command.wrist_tform_tool.CopyFrom(wrist_tform_tool)
1623
+
1624
+ if root_tform_task is not None:
1625
+ # Set the transformation from the root frame to the task frame if it is a valid SE3Pose
1626
+ # If unset, it will be assumed that the root frame is the task frame
1627
+ assert isinstance(
1628
+ root_tform_task,
1629
+ geometry_pb2.SE3Pose), 'All poses must be of type geometry_pb2.SE3Pose'
1630
+
1631
+ arm_cartesian_command.root_tform_task.CopyFrom(root_tform_task)
1632
+
1633
+ # If the root frame name is invalid the command will be rejected
1634
+ arm_cartesian_command.root_frame_name = root_frame_name
1635
+
1636
+ if build_on_command:
1637
+ return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1638
+ return robot_cmd
1639
+
1640
+ @staticmethod
1641
+ def claw_gripper_command_helper(
1642
+ gripper_positions,
1643
+ times,
1644
+ gripper_velocities=None,
1645
+ ref_time=None,
1646
+ max_acc=None,
1647
+ max_vel=None,
1648
+ disable_force_on_contact=False,
1649
+ build_on_command=None,
1650
+ max_torque=None,
1651
+ ):
1540
1652
  """Given a set of gripper positions, times, and optional velocities, create a synchro command.
1541
1653
 
1542
1654
  Args:
@@ -1556,6 +1668,8 @@ class RobotCommandBuilder(object):
1556
1668
  build_on_command: Option to input a RobotCommand (not containing a full_body_command). An
1557
1669
  arm_command and mobility_command from this incoming RobotCommand will be added
1558
1670
  to the returned RobotCommand.
1671
+ max_torque: Optional Maximum torque applied if contact detected closing the gripper. If
1672
+ unspecified, a default value of 5.5 (Nm) will be used.
1559
1673
 
1560
1674
  Returns:
1561
1675
  robot_command_pb2.RobotCommand with a claw_gripper_command filled out.
@@ -1596,6 +1710,10 @@ class RobotCommandBuilder(object):
1596
1710
  # Set a maximum allowable joint velocity if desired.
1597
1711
  # If unset, a safe default will be used
1598
1712
  gripper_cmd.maximum_open_close_velocity.value = max_vel
1713
+ if max_torque is not None:
1714
+ # Maximum torque applied if contact detected closing the gripper.
1715
+ # If unspecified, a default value of 5.5 (Nm) will be used.
1716
+ gripper_cmd.maximum_torque.value = max_torque
1599
1717
 
1600
1718
  gripper_cmd.disable_force_on_contact = disable_force_on_contact
1601
1719
 
@@ -1603,6 +1721,26 @@ class RobotCommandBuilder(object):
1603
1721
  return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1604
1722
  return robot_cmd
1605
1723
 
1724
+ @staticmethod
1725
+ def arm_joint_freeze_command(build_on_command=None):
1726
+ """Returns a RobotCommand with an ArmCommand that will freeze the arm's joints in place.
1727
+
1728
+ Args:
1729
+ build_on_command: Option to input a RobotCommand (not containing a full_body_command). An
1730
+ arm_command and mobility_command from this incoming RobotCommand will be added
1731
+ to the returned RobotCommand.
1732
+
1733
+ Returns:
1734
+ robot_command_pb2.RobotCommand
1735
+ """
1736
+
1737
+ robot_cmd = robot_command_pb2.RobotCommand()
1738
+ robot_cmd.synchronized_command.arm_command.arm_joint_move_command.trajectory.points.add()
1739
+
1740
+ if build_on_command:
1741
+ return RobotCommandBuilder.build_synchro_command(build_on_command, robot_cmd)
1742
+ return robot_cmd
1743
+
1606
1744
  ########################
1607
1745
  # Spot mobility params #
1608
1746
  ########################
@@ -1711,18 +1849,18 @@ class RobotCommandBuilder(object):
1711
1849
  def build_synchro_command(*args):
1712
1850
  """ Combines multiple commands into one command. There's no intelligence here on
1713
1851
  duplicate commands.
1714
- Args: RobotCommand containing only either mobility commands or synchro commands
1715
- Returns: RobotCommand containing a synchro command """
1852
+
1853
+ Args:
1854
+ RobotCommand containing only either mobility commands or synchro commands
1855
+ Returns:
1856
+ RobotCommand containing a synchro command """
1716
1857
  mobility_request = None
1717
1858
  arm_request = None
1718
1859
  gripper_request = None
1719
1860
 
1720
1861
  for command in args:
1721
1862
  if command.HasField('full_body_command'):
1722
- raise Exception(
1723
- 'this function only takes RobotCommands containing mobility or synchro cmds')
1724
- elif command.HasField('mobility_command'):
1725
- mobility_request = command.mobility_command
1863
+ raise Exception('this function only takes RobotCommands containing synchro cmds')
1726
1864
  elif command.HasField('synchronized_command'):
1727
1865
  if command.synchronized_command.HasField('mobility_command'):
1728
1866
  mobility_request = command.synchronized_command.mobility_command
@@ -1750,13 +1888,13 @@ def blocking_command(command_client, command, check_status_fn, end_time_secs=Non
1750
1888
 
1751
1889
  Blocks until check_status_fn return true, or raises an exception if the command times out or fails.
1752
1890
  This helper checks the main full_body/synchronized command status (RobotCommandFeedbackStatus), but
1753
- the caller should check the status of the specific commands (stand, stow, selfright, etc) in the callback.
1891
+ the caller should check the status of the specific commands (stand, stow, selfright, etc.) in the callback.
1754
1892
 
1755
1893
  Args:
1756
1894
  command_client: RobotCommand client.
1757
1895
  command: The robot command to issue to the robot.
1758
1896
  check_status_fn: A callback that accepts RobotCommandFeedbackResponse and returns True when the
1759
- correct status's are achieved for the specific requested command and throws
1897
+ correct statuses are achieved for the specific requested command and throws
1760
1898
  CommandFailedErrorWithFeedback if an error state occurs.
1761
1899
  end_time_sec: The local end time of the command (will be converted to robot time)
1762
1900
  timeout_sec: Timeout for the rpc in seconds.
@@ -1922,7 +2060,7 @@ def block_until_arm_arrives(command_client, cmd_id, timeout_sec=None):
1922
2060
 
1923
2061
  Return values:
1924
2062
  True if successfully got to the end of the trajectory, False if the arm stalled or
1925
- the move was canceled (the arm failed to reach the goal). See the proto definitions in
2063
+ the move was canceled (the arm failed to reach the goal). See the proto definitions in
1926
2064
  arm_command.proto for more information about why a trajectory would succeed or fail.
1927
2065
  """
1928
2066
  if timeout_sec is not None:
@@ -1967,7 +2105,7 @@ def block_until_arm_arrives(command_client, cmd_id, timeout_sec=None):
1967
2105
 
1968
2106
  def block_for_trajectory_cmd(
1969
2107
  command_client, cmd_id,
1970
- trajectory_end_statuses=(basic_command_pb2.SE2TrajectoryCommand.Feedback.STATUS_AT_GOAL,),
2108
+ trajectory_end_statuses=(basic_command_pb2.SE2TrajectoryCommand.Feedback.STATUS_STOPPED,),
1971
2109
  body_movement_statuses=None, feedback_interval_secs=0.1, timeout_sec=None, logger=None):
1972
2110
  """Helper that blocks until a trajectory command reaches a desired goal state or a timeout is reached.
1973
2111
 
@@ -1976,7 +2114,7 @@ def block_for_trajectory_cmd(
1976
2114
  cmd_id (int): command ID returned by the robot when the trajectory command was sent
1977
2115
  trajectory_end_statuses (set of SE2TrajectoryCommand.Feedback.Status): the feedback must have a
1978
2116
  status which is included in this set of statuses to be considered successfully complete.
1979
- By default, this includes only the "STATUS_AT_GOAL" end condition.
2117
+ By default, this includes only the "STATUS_STOPPED" end condition.
1980
2118
  body_movement_statuses (set of SE2TrajectoryCommand.Feedback.BodyMovementStatus): the body
1981
2119
  movement status must be one of these statuses to be considered successfully complete. By
1982
2120
  default, this is "None", which means any body movement status will be accepted.
@@ -1988,7 +2126,7 @@ def block_for_trajectory_cmd(
1988
2126
  will be sent.
1989
2127
 
1990
2128
  Return values:
1991
- True if reaches STATUS_AT_GOAL, False otherwise.
2129
+ True if reaches STATUS_STOPPED, False otherwise.
1992
2130
  """
1993
2131
 
1994
2132
  if timeout_sec is not None: