def test_arm_stow_command(): command = RobotCommandBuilder.arm_stow_command() _test_has_synchronized(command) _test_has_arm(command.synchronized_command) assert (command.synchronized_command.arm_command.WhichOneof("command") == 'named_arm_position_command') # with a build_on_command mobility_command = RobotCommandBuilder.synchro_sit_command() command = RobotCommandBuilder.arm_stow_command(build_on_command=mobility_command) _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) _test_has_arm(command.synchronized_command)
def test_synchro_sit_command(): command = RobotCommandBuilder.synchro_sit_command() _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) assert command.synchronized_command.mobility_command.HasField("sit_request") # with a build_on_command arm_command = RobotCommandBuilder.arm_stow_command() command = RobotCommandBuilder.synchro_sit_command(build_on_command=arm_command) _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) _test_has_arm(command.synchronized_command)
def test_synchro_se2_trajectory_point_command(): goal_x = 1.0 goal_y = 2.0 goal_heading = 3.0 frame = ODOM_FRAME_NAME command = RobotCommandBuilder.synchro_se2_trajectory_point_command( goal_x, goal_y, goal_heading, frame) _check_se2_traj_command(command, goal_x, goal_y, goal_heading, frame, 1) # with a build_on_command arm_command = RobotCommandBuilder.arm_stow_command() command = RobotCommandBuilder.synchro_se2_trajectory_point_command( goal_x, goal_y, goal_heading, frame, build_on_command=arm_command) _check_se2_traj_command(command, goal_x, goal_y, goal_heading, frame, 1) _test_has_arm(command.synchronized_command)
def test_synchro_se2_trajectory_command(): goal_x = 1.0 goal_y = 2.0 goal_heading = 3.0 frame = ODOM_FRAME_NAME position = geometry_pb2.Vec2(x=goal_x, y=goal_y) goal_se2 = geometry_pb2.SE2Pose(position=position, angle=goal_heading) command = RobotCommandBuilder.synchro_se2_trajectory_command(goal_se2, frame) _check_se2_traj_command(command, goal_x, goal_y, goal_heading, frame, 1) # with a build_on_command arm_command = RobotCommandBuilder.arm_stow_command() command = RobotCommandBuilder.synchro_se2_trajectory_command(goal_se2, frame, build_on_command=arm_command) _check_se2_traj_command(command, goal_x, goal_y, goal_heading, frame, 1) _test_has_arm(command.synchronized_command)
def test_synchro_velocity_command(): v_x = 1.0 v_y = 2.0 v_rot = 3.0 command = RobotCommandBuilder.synchro_velocity_command(v_x, v_y, v_rot) _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) assert command.synchronized_command.mobility_command.HasField("se2_velocity_request") vel_cmd = command.synchronized_command.mobility_command.se2_velocity_request assert vel_cmd.velocity.linear.x == v_x assert vel_cmd.velocity.linear.y == v_y assert vel_cmd.velocity.angular == v_rot assert vel_cmd.se2_frame_name == BODY_FRAME_NAME # with a build_on_command arm_command = RobotCommandBuilder.arm_stow_command() command = RobotCommandBuilder.synchro_velocity_command(v_x, v_y, v_rot, build_on_command=arm_command) _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) _test_has_arm(command.synchronized_command)
def test_build_synchro_command(): # two synchro subcommands of the same type: arm_command_1 = RobotCommandBuilder.arm_ready_command() arm_command_2 = RobotCommandBuilder.arm_stow_command() command = RobotCommandBuilder.build_synchro_command(arm_command_1, arm_command_2) _test_has_synchronized(command) _test_has_arm(command.synchronized_command) assert not command.synchronized_command.HasField("gripper_command") assert not command.synchronized_command.HasField("mobility_command") command_position = command.synchronized_command.arm_command.named_arm_position_command.position assert command_position == arm_command_pb2.NamedArmPositionsCommand.POSITIONS_STOW # two synchro subcommands of a different type: arm_command = RobotCommandBuilder.arm_ready_command() mobility_command = RobotCommandBuilder.synchro_stand_command() command = RobotCommandBuilder.build_synchro_command(arm_command, mobility_command) _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) _test_has_arm(command.synchronized_command) assert not command.synchronized_command.HasField("gripper_command") assert command.synchronized_command.mobility_command.HasField("stand_request") command_position = command.synchronized_command.arm_command.named_arm_position_command.position assert command_position == arm_command_pb2.NamedArmPositionsCommand.POSITIONS_READY # one synchro command and one deprecated mobility command: deprecated_mobility_command = RobotCommandBuilder.sit_command() command = RobotCommandBuilder.build_synchro_command(mobility_command, deprecated_mobility_command) _test_has_synchronized(command) _test_has_mobility(command.synchronized_command) assert command.synchronized_command.mobility_command.HasField("sit_request") # fullbody command is rejected full_body_command = RobotCommandBuilder.selfright_command() with pytest.raises(Exception): command = RobotCommandBuilder.build_synchro_command(arm_command, full_body_command)
def main(argv): parser = argparse.ArgumentParser() bosdyn.client.util.add_common_arguments(parser) parser.add_argument( '-s', '--ml-service', help='Service name of external machine learning server.', required=True) parser.add_argument('-m', '--model', help='Model name running on the external server.', required=True) parser.add_argument( '-p', '--person-model', help='Person detection model name running on the external server.') parser.add_argument( '-c', '--confidence-dogtoy', help= 'Minimum confidence to return an object for the dogoy (0.0 to 1.0)', default=0.5, type=float) parser.add_argument( '-e', '--confidence-person', help='Minimum confidence for person detection (0.0 to 1.0)', default=0.6, type=float) options = parser.parse_args(argv) cv2.namedWindow("Fetch") cv2.waitKey(500) sdk = bosdyn.client.create_standard_sdk('SpotFetchClient') sdk.register_service_client(NetworkComputeBridgeClient) robot = sdk.create_robot(options.hostname) robot.authenticate(options.username, options.password) # Time sync is necessary so that time-based filter requests can be converted robot.time_sync.wait_for_sync() network_compute_client = robot.ensure_client( NetworkComputeBridgeClient.default_service_name) robot_state_client = robot.ensure_client( RobotStateClient.default_service_name) command_client = robot.ensure_client( RobotCommandClient.default_service_name) lease_client = robot.ensure_client(LeaseClient.default_service_name) manipulation_api_client = robot.ensure_client( ManipulationApiClient.default_service_name) # This script assumes the robot is already standing via the tablet. We'll take over from the # tablet. lease = lease_client.take() lk = bosdyn.client.lease.LeaseKeepAlive(lease_client) # Store the position of the hand at the last toy drop point. vision_tform_hand_at_drop = None while True: holding_toy = False while not holding_toy: # Capture an image and run ML on it. dogtoy, image, vision_tform_dogtoy = get_obj_and_img( network_compute_client, options.ml_service, options.model, options.confidence_dogtoy, kImageSources, 'dogtoy') if dogtoy is None: # Didn't find anything, keep searching. continue # If we have already dropped the toy off, make sure it has moved a sufficient amount before # picking it up again if vision_tform_hand_at_drop is not None and pose_dist( vision_tform_hand_at_drop, vision_tform_dogtoy) < 0.5: print('Found dogtoy, but it hasn\'t moved. Waiting...') time.sleep(1) continue print('Found dogtoy...') # Got a dogtoy. Request pick up. # Stow the arm in case it is deployed stow_cmd = RobotCommandBuilder.arm_stow_command() command_client.robot_command(stow_cmd) # Walk to the object. walk_rt_vision, heading_rt_vision = compute_stand_location_and_yaw( vision_tform_dogtoy, robot_state_client, distance_margin=1.0) move_cmd = RobotCommandBuilder.trajectory_command( goal_x=walk_rt_vision[0], goal_y=walk_rt_vision[1], goal_heading=heading_rt_vision, frame_name=frame_helpers.VISION_FRAME_NAME, params=get_walking_params(0.5, 0.5)) end_time = 5.0 cmd_id = command_client.robot_command(command=move_cmd, end_time_secs=time.time() + end_time) # Wait until the robot reports that it is at the goal. block_for_trajectory_cmd(command_client, cmd_id, timeout_sec=5, verbose=True) # The ML result is a bounding box. Find the center. (center_px_x, center_px_y) = find_center_px(dogtoy.image_properties.coordinates) # Request Pick Up on that pixel. pick_vec = geometry_pb2.Vec2(x=center_px_x, y=center_px_y) grasp = manipulation_api_pb2.PickObjectInImage( pixel_xy=pick_vec, transforms_snapshot_for_camera=image.shot.transforms_snapshot, frame_name_image_sensor=image.shot.frame_name_image_sensor, camera_model=image.source.pinhole) # We can specify where in the gripper we want to grasp. About halfway is generally good for # small objects like this. For a bigger object like a shoe, 0 is better (use the entire # gripper) grasp.grasp_params.grasp_palm_to_fingertip = 0.6 # Tell the grasping system that we want a top-down grasp. # Add a constraint that requests that the x-axis of the gripper is pointing in the # negative-z direction in the vision frame. # The axis on the gripper is the x-axis. axis_on_gripper_ewrt_gripper = geometry_pb2.Vec3(x=1, y=0, z=0) # The axis in the vision frame is the negative z-axis axis_to_align_with_ewrt_vision = geometry_pb2.Vec3(x=0, y=0, z=-1) # Add the vector constraint to our proto. constraint = grasp.grasp_params.allowable_orientation.add() constraint.vector_alignment_with_tolerance.axis_on_gripper_ewrt_gripper.CopyFrom( axis_on_gripper_ewrt_gripper) constraint.vector_alignment_with_tolerance.axis_to_align_with_ewrt_frame.CopyFrom( axis_to_align_with_ewrt_vision) # We'll take anything within about 15 degrees for top-down or horizontal grasps. constraint.vector_alignment_with_tolerance.threshold_radians = 0.25 # Specify the frame we're using. grasp.grasp_params.grasp_params_frame_name = frame_helpers.VISION_FRAME_NAME # Build the proto grasp_request = manipulation_api_pb2.ManipulationApiRequest( pick_object_in_image=grasp) # Send the request print('Sending grasp request...') cmd_response = manipulation_api_client.manipulation_api_command( manipulation_api_request=grasp_request) # Wait for the grasp to finish grasp_done = False failed = False time_start = time.time() while not grasp_done: feedback_request = manipulation_api_pb2.ManipulationApiFeedbackRequest( manipulation_cmd_id=cmd_response.manipulation_cmd_id) # Send a request for feedback response = manipulation_api_client.manipulation_api_feedback_command( manipulation_api_feedback_request=feedback_request) current_state = response.current_state current_time = time.time() - time_start print('Current state ({time:.1f} sec): {state}'.format( time=current_time, state=manipulation_api_pb2.ManipulationFeedbackState.Name( current_state)), end=' \r') sys.stdout.flush() failed_states = [ manipulation_api_pb2.MANIP_STATE_GRASP_FAILED, manipulation_api_pb2. MANIP_STATE_GRASP_PLANNING_NO_SOLUTION, manipulation_api_pb2. MANIP_STATE_GRASP_FAILED_TO_RAYCAST_INTO_MAP, manipulation_api_pb2. MANIP_STATE_GRASP_PLANNING_WAITING_DATA_AT_EDGE ] failed = current_state in failed_states grasp_done = current_state == manipulation_api_pb2.MANIP_STATE_GRASP_SUCCEEDED or failed time.sleep(0.1) holding_toy = not failed # Move the arm to a carry position. print('') print('Grasp finished, search for a person...') carry_cmd = RobotCommandBuilder.arm_carry_command() command_client.robot_command(carry_cmd) # Wait for the carry command to finish time.sleep(0.75) person = None while person is None: # Find a person to deliver the toy to person, image, vision_tform_person = get_obj_and_img( network_compute_client, options.ml_service, options.person_model, options.confidence_person, kImageSources, 'person') # We now have found a person to drop the toy off near. drop_position_rt_vision, heading_rt_vision = compute_stand_location_and_yaw( vision_tform_person, robot_state_client, distance_margin=2.0) wait_position_rt_vision, wait_heading_rt_vision = compute_stand_location_and_yaw( vision_tform_person, robot_state_client, distance_margin=3.0) # Tell the robot to go there # Limit the speed so we don't charge at the person. move_cmd = RobotCommandBuilder.trajectory_command( goal_x=drop_position_rt_vision[0], goal_y=drop_position_rt_vision[1], goal_heading=heading_rt_vision, frame_name=frame_helpers.VISION_FRAME_NAME, params=get_walking_params(0.5, 0.5)) end_time = 5.0 cmd_id = command_client.robot_command(command=move_cmd, end_time_secs=time.time() + end_time) # Wait until the robot reports that it is at the goal. block_for_trajectory_cmd(command_client, cmd_id, timeout_sec=5, verbose=True) print('Arrived at goal, dropping object...') # Do an arm-move to gently put the object down. # Build a position to move the arm to (in meters, relative to and expressed in the gravity aligned body frame). x = 0.75 y = 0 z = -0.25 hand_ewrt_flat_body = geometry_pb2.Vec3(x=x, y=y, z=z) # Point the hand straight down with a quaternion. qw = 0.707 qx = 0 qy = 0.707 qz = 0 flat_body_Q_hand = geometry_pb2.Quaternion(w=qw, x=qx, y=qy, z=qz) flat_body_tform_hand = geometry_pb2.SE3Pose( position=hand_ewrt_flat_body, rotation=flat_body_Q_hand) robot_state = robot_state_client.get_robot_state() vision_tform_flat_body = frame_helpers.get_a_tform_b( robot_state.kinematic_state.transforms_snapshot, frame_helpers.VISION_FRAME_NAME, frame_helpers.GRAV_ALIGNED_BODY_FRAME_NAME) vision_tform_hand_at_drop = vision_tform_flat_body * math_helpers.SE3Pose.from_obj( flat_body_tform_hand) # duration in seconds seconds = 1 arm_command = RobotCommandBuilder.arm_pose_command( vision_tform_hand_at_drop.x, vision_tform_hand_at_drop.y, vision_tform_hand_at_drop.z, vision_tform_hand_at_drop.rot.w, vision_tform_hand_at_drop.rot.x, vision_tform_hand_at_drop.rot.y, vision_tform_hand_at_drop.rot.z, frame_helpers.VISION_FRAME_NAME, seconds) # Keep the gripper closed. gripper_command = RobotCommandBuilder.claw_gripper_open_fraction_command( 0.0) # Combine the arm and gripper commands into one RobotCommand command = RobotCommandBuilder.build_synchro_command( gripper_command, arm_command) # Send the request cmd_id = command_client.robot_command(command) # Wait until the arm arrives at the goal. block_until_arm_arrives(command_client, cmd_id) # Open the gripper gripper_command = RobotCommandBuilder.claw_gripper_open_fraction_command( 1.0) command = RobotCommandBuilder.build_synchro_command(gripper_command) cmd_id = command_client.robot_command(command) # Wait for the dogtoy to fall out time.sleep(1.5) # Stow the arm. stow_cmd = RobotCommandBuilder.arm_stow_command() command_client.robot_command(stow_cmd) time.sleep(1) print('Backing up and waiting...') # Back up one meter and wait for the person to throw the object again. move_cmd = RobotCommandBuilder.trajectory_command( goal_x=wait_position_rt_vision[0], goal_y=wait_position_rt_vision[1], goal_heading=wait_heading_rt_vision, frame_name=frame_helpers.VISION_FRAME_NAME, params=get_walking_params(0.5, 0.5)) end_time = 5.0 cmd_id = command_client.robot_command(command=move_cmd, end_time_secs=time.time() + end_time) # Wait until the robot reports that it is at the goal. block_for_trajectory_cmd(command_client, cmd_id, timeout_sec=5, verbose=True) lease_client.return_lease(lease)
def joint_move_example(config): """A simple example of using the Boston Dynamics API to command Spot's arm to perform joint moves.""" # See hello_spot.py for an explanation of these lines. bosdyn.client.util.setup_logging(config.verbose) sdk = bosdyn.client.create_standard_sdk('ArmJointMoveClient') robot = sdk.create_robot(config.hostname) robot.authenticate(config.username, config.password) robot.time_sync.wait_for_sync() assert robot.has_arm(), "Robot requires an arm to run this example." # Verify the robot is not estopped and that an external application has registered and holds # an estop endpoint. verify_estop(robot) robot_state_client = robot.ensure_client( RobotStateClient.default_service_name) lease_client = robot.ensure_client( bosdyn.client.lease.LeaseClient.default_service_name) lease = lease_client.acquire() try: with bosdyn.client.lease.LeaseKeepAlive(lease_client): # Now, we are ready to power on the robot. This call will block until the power # is on. Commands would fail if this did not happen. We can also check that the robot is # powered at any point. robot.logger.info( "Powering on robot... This may take a several seconds.") robot.power_on(timeout_sec=20) assert robot.is_powered_on(), "Robot power on failed." robot.logger.info("Robot powered on.") # Tell the robot to stand up. The command service is used to issue commands to a robot. # The set of valid commands for a robot depends on hardware configuration. See # SpotCommandHelper for more detailed examples on command building. The robot # command service requires timesync between the robot and the client. robot.logger.info("Commanding robot to stand...") command_client = robot.ensure_client( RobotCommandClient.default_service_name) blocking_stand(command_client, timeout_sec=10) robot.logger.info("Robot standing.") time.sleep(2.0) # Example 1: issue a single point trajectory without a time_since_reference in order to perform # a minimum time joint move to the goal obeying the default acceleration and velocity limits. sh0 = 0.0692 sh1 = -1.882 el0 = 1.652 el1 = -0.0691 wr0 = 1.622 wr1 = 1.550 traj_point = RobotCommandBuilder.create_arm_joint_trajectory_point( sh0, sh1, el0, el1, wr0, wr1) arm_joint_traj = arm_command_pb2.ArmJointTrajectory( points=[traj_point]) # Make a RobotCommand command = make_robot_command(arm_joint_traj) # Send the request cmd_id = command_client.robot_command(command) robot.logger.info('Moving arm to position 1.') # Query for feedback to determine how long the goto will take. feedback_resp = command_client.robot_command_feedback(cmd_id) robot.logger.info("Feedback for Example 1: single point goto") time_to_goal = print_feedback(feedback_resp, robot.logger) time.sleep(time_to_goal) # Example 2: Single point trajectory with maximum acceleration/velocity constraints specified such # that the solver has to modify the desired points to honor the constraints sh0 = 0.0 sh1 = -2.0 el0 = 2.6 el1 = 0.0 wr0 = -0.6 wr1 = 0.0 max_vel = wrappers_pb2.DoubleValue(value=1) max_acc = wrappers_pb2.DoubleValue(value=5) traj_point = RobotCommandBuilder.create_arm_joint_trajectory_point( sh0, sh1, el0, el1, wr0, wr1, time_since_reference_secs=1.5) arm_joint_traj = arm_command_pb2.ArmJointTrajectory( points=[traj_point], maximum_velocity=max_vel, maximum_acceleration=max_acc) # Make a RobotCommand command = make_robot_command(arm_joint_traj) # Send the request cmd_id = command_client.robot_command(command) robot.logger.info( 'Requesting a single point trajectory with unsatisfiable constraints.' ) # Query for feedback feedback_resp = command_client.robot_command_feedback(cmd_id) robot.logger.info( "Feedback for Example 2: planner modifies trajectory") time_to_goal = print_feedback(feedback_resp, robot.logger) time.sleep(time_to_goal) # Example 3: Single point trajectory with default acceleration/velocity constraints and # time_since_reference_secs large enough such that the solver can plan a solution to the # points that also satisfies the constraints. sh0 = 0.0692 sh1 = -1.882 el0 = 1.652 el1 = -0.0691 wr0 = 1.622 wr1 = 1.550 traj_point = RobotCommandBuilder.create_arm_joint_trajectory_point( sh0, sh1, el0, el1, wr0, wr1, time_since_reference_secs=1.5) arm_joint_traj = arm_command_pb2.ArmJointTrajectory( points=[traj_point]) # Make a RobotCommand command = make_robot_command(arm_joint_traj) # Send the request cmd_id = command_client.robot_command(command) robot.logger.info( 'Requesting a single point trajectory with satisfiable constraints.' ) # Query for feedback feedback_resp = command_client.robot_command_feedback(cmd_id) robot.logger.info("Feedback for Example 3: unmodified trajectory") time_to_goal = print_feedback(feedback_resp, robot.logger) time.sleep(time_to_goal) # ----- Do a two-point joint move trajectory ------ # First stow the arm. # Build the stow command using RobotCommandBuilder stow = RobotCommandBuilder.arm_stow_command() # Issue the command via the RobotCommandClient command_client.robot_command(stow) robot.logger.info("Stow command issued.") time.sleep(2.0) # First point position sh0 = -1.5 sh1 = -0.8 el0 = 1.7 el1 = 0.0 wr0 = 0.5 wr1 = 0.0 # First point time (seconds) first_point_t = 2.0 # Build the proto for the trajectory point. traj_point1 = RobotCommandBuilder.create_arm_joint_trajectory_point( sh0, sh1, el0, el1, wr0, wr1, first_point_t) # Second point position sh0 = 1.0 sh1 = -0.2 el0 = 1.3 el1 = -1.3 wr0 = -1.5 wr1 = 1.5 # Second point time (seconds) second_point_t = 4.0 # Build the proto for the second trajectory point. traj_point2 = RobotCommandBuilder.create_arm_joint_trajectory_point( sh0, sh1, el0, el1, wr0, wr1, second_point_t) # Optionally, set the maximum allowable velocity in rad/s that a joint is allowed to # travel at. Also set the maximum allowable acceleration in rad/s^2 that a joint is # allowed to accelerate at. If these values are not set, a default will be used on # the robot. # Note that if these values are set too low and the trajectories are too aggressive # in terms of time, the desired joint angles will not be hit at the specified time. # Some other ways to help the robot actually hit the specified trajectory is to # increase the time between trajectory points, or to only specify joint position # goals without specifying velocity goals. max_vel = wrappers_pb2.DoubleValue(value=2.5) max_acc = wrappers_pb2.DoubleValue(value=15) # Build up a proto. arm_joint_traj = arm_command_pb2.ArmJointTrajectory( points=[traj_point1, traj_point2], maximum_velocity=max_vel, maximum_acceleration=max_acc) # Make a RobotCommand command = make_robot_command(arm_joint_traj) # Send the request cmd_id = command_client.robot_command(command) robot.logger.info('Moving arm along 2-point joint trajectory.') # Query for feedback to determine exactly what the planned trajectory is. feedback_resp = command_client.robot_command_feedback(cmd_id) robot.logger.info("Feedback for 2-point joint trajectory") print_feedback(feedback_resp, robot.logger) # Wait until the move completes before powering off. block_until_arm_arrives(command_client, cmd_id, second_point_t + 3.0) # Power the robot off. By specifying "cut_immediately=False", a safe power off command # is issued to the robot. This will attempt to sit the robot before powering off. robot.power_off(cut_immediately=False, timeout_sec=20) assert not robot.is_powered_on(), "Robot power off failed." robot.logger.info("Robot safely powered off.") finally: # If we successfully acquired a lease, return it. lease_client.return_lease(lease)
def _stow(self): self._start_robot_command('stow', RobotCommandBuilder.arm_stow_command())
def hello_arm(config): """A simple example of using the Boston Dynamics API to command Spot's arm.""" # See hello_spot.py for an explanation of these lines. bosdyn.client.util.setup_logging(config.verbose) sdk = bosdyn.client.create_standard_sdk('StowUnstowClient') robot = sdk.create_robot(config.hostname) robot.authenticate(config.username, config.password) robot.time_sync.wait_for_sync() assert robot.has_arm(), "Robot requires an arm to run this example." # Verify the robot is not estopped and that an external application has registered and holds # an estop endpoint. verify_estop(robot) lease_client = robot.ensure_client(bosdyn.client.lease.LeaseClient.default_service_name) lease = lease_client.acquire() try: with bosdyn.client.lease.LeaseKeepAlive(lease_client): # Now, we are ready to power on the robot. This call will block until the power # is on. Commands would fail if this did not happen. We can also check that the robot is # powered at any point. robot.logger.info("Powering on robot... This may take a several seconds.") robot.power_on(timeout_sec=20) assert robot.is_powered_on(), "Robot power on failed." robot.logger.info("Robot powered on.") # Tell the robot to stand up. The command service is used to issue commands to a robot. # The set of valid commands for a robot depends on hardware configuration. See # SpotCommandHelper for more detailed examples on command building. The robot # command service requires timesync between the robot and the client. robot.logger.info("Commanding robot to stand...") command_client = robot.ensure_client(RobotCommandClient.default_service_name) blocking_stand(command_client, timeout_sec=10) robot.logger.info("Robot standing.") time.sleep(2.0) # Unstow the arm unstow = RobotCommandBuilder.arm_ready_command() # Issue the command via the RobotCommandClient command_client.robot_command(unstow) robot.logger.info("Unstow command issued.") time.sleep(3.0) # Stow the arm # Build the stow command using RobotCommandBuilder stow = RobotCommandBuilder.arm_stow_command() # Issue the command via the RobotCommandClient command_client.robot_command(stow) robot.logger.info("Stow command issued.") time.sleep(3.0) # Power the robot off. By specifying "cut_immediately=False", a safe power off command # is issued to the robot. This will attempt to sit the robot before powering off. robot.power_off(cut_immediately=False, timeout_sec=20) assert not robot.is_powered_on(), "Robot power off failed." robot.logger.info("Robot safely powered off.") finally: # If we successfully acquired a lease, return it. lease_client.return_lease(lease)