def payload_spot(config): """A simple example of using the Boston Dynamics API to communicate payload configs with spot. First registers a payload then lists all payloads on robot, including newly registered payload. """ sdk = bosdyn.client.create_standard_sdk('PayloadSpotClient') sdk.load_app_token(config.app_token) robot = sdk.create_robot(config.hostname) # Authenticate robot before being able to use it robot.authenticate(config.username, config.password) # Create a payload registration client payload_registration_client = robot.ensure_client( PayloadRegistrationClient.default_service_name) # Create a payload payload = payload_protos.Payload() payload.GUID = '78b076a2-b4ba-491d-a099-738928c4410c' payload_secret = 'secret' payload.name = 'Client Registered Payload Ex' payload.description = 'This payload was created and registered by the payloads.py client example.' payload.label_prefix.append("test_payload") payload.is_authorized = False payload.is_enabled = False payload.is_noncompute_payload = False payload.version.major_version = 1 payload.version.minor_version = 1 payload.version.patch_level = 1 # Register the payload payload_registration_client.register_payload(payload, payload_secret) # Create a payload client payload_client = robot.ensure_client(PayloadClient.default_service_name) # Update the payload version version = robot_id_protos.SoftwareVersion() version.major_version = 2 version.minor_version = 2 version.patch_level = 2 payload_registration_client.update_payload_version(payload.GUID, payload_secret, version) # List all payloads payloads = payload_client.list_payloads() print(payloads)
def payload_spot(config): """A simple example of using the Boston Dynamics API to communicate payload configs with spot. First registers a payload then lists all payloads on robot, including newly registered payload. """ sdk = bosdyn.client.create_standard_sdk('PayloadSpotClient') robot = sdk.create_robot(config.hostname) # Authenticate robot before being able to use it robot.authenticate(config.username, config.password) # Create a payload registration client payload_registration_client = robot.ensure_client( PayloadRegistrationClient.default_service_name) # Create a payload payload = payload_protos.Payload() payload.GUID = '78b076a2-b4ba-491d-a099-738928c4410c' payload_secret = 'secret' payload.name = 'Client Registered Payload Ex #1' payload.description = 'This payload was created and registered by the payloads.py client example.' payload.label_prefix.append("test_payload") payload.is_authorized = False payload.is_enabled = False payload.is_noncompute_payload = False payload.version.major_version = 1 payload.version.minor_version = 1 payload.version.patch_level = 1 # note: this field is not required, but highly recommended payload.mount_frame_name = payload_protos.MOUNT_FRAME_GRIPPER_PAYLOAD # Register the payload payload_registration_client.register_payload(payload, payload_secret) # Create a payload client payload_client = robot.ensure_client(PayloadClient.default_service_name) # Update the payload version version = robot_id_protos.SoftwareVersion() version.major_version = 2 version.minor_version = 2 version.patch_level = 2 payload_registration_client.update_payload_version(payload.GUID, payload_secret, version) # List all payloads payloads = payload_client.list_payloads() print('\n\nPayload Listing\n' + '-' * 40) print(payloads) # Use the PayloadRegistrationKeepAlive to register a payload # Create a payload payload = payload_protos.Payload() payload.GUID = '7c49e4f7-9cb9-497a-849f-114360fa9bbf' payload_secret = 'secret' payload.name = 'Client Registered Payload Ex #2' payload.description = 'This payload was created and registered by the payloads.py using a PayloadRegistrationKeepAlive.' payload.label_prefix.append("test_payload") payload.is_authorized = False payload.is_enabled = False payload.is_noncompute_payload = False payload.version.major_version = 3 payload.version.minor_version = 2 payload.version.patch_level = 1 # note: this field is not required, but highly recommended payload.mount_frame_name = payload_protos.MOUNT_FRAME_GRIPPER_PAYLOAD # Create and start the keep alive keep_alive = PayloadRegistrationKeepAlive(payload_registration_client, payload, payload_secret) keep_alive.start() # List all payloads payloads = payload_client.list_payloads() print('\n\nPayload Listing\n' + '-' * 40) print(payloads) print('\n\n\nDon\'t forget to clean up these registrations in the Spot payloads webpage!')
from bosdyn.client.util import GrpcServiceRunner, setup_logging from bosdyn.client.fault import FaultClient from bosdyn.client.image_service_helpers import VisualImageSource, CameraBaseImageServicer, CameraInterface from bosdyn.api import image_pb2 from bosdyn.api import image_service_pb2_grpc from bosdyn.api import service_fault_pb2 # Ricoh Theta from ricoh_theta import Theta # Payload Registration import bosdyn.api.payload_pb2 as payload_protos # Create a virtual payload. PLACEHOLDER_PAYLOAD = payload_protos.Payload() PLACEHOLDER_PAYLOAD.name = 'Ricoh Theta Image Service' PLACEHOLDER_PAYLOAD.description = 'This is currently a virtual/weightless payload defined for the software service only. \ Please define weight and dimensions if the Ricoh Theta is mounted to Spot.' # See https://dev.bostondynamics.com/docs/payload/configuring_payload_software#registering-payloads for more information. DIRECTORY_NAME = 'ricoh-theta-image-service' AUTHORITY = 'robot-ricoh-theta' SERVICE_TYPE = 'bosdyn.api.ImageService' _LOGGER = logging.getLogger(__name__) # Define ServiceFaultIds for possible faults that will be thrown by the Ricoh Theta image service. CAMERA_SETUP_FAULT = service_fault_pb2.ServiceFault( fault_id=service_fault_pb2.ServiceFaultId(fault_name='Ricoh Theta Initialization Failure',
def self_register_payload(config): """A simple example of using the Boston Dynamics API to self register from a payload. This function represents code that would run directly on a payload to set itself up. It registers a payload (itself) without access to a pre-existing app token or credentials. """ # Create an sdk and robot instance. sdk = bosdyn.client.create_standard_sdk('SelfRegisterPayloadExampleClient') robot = sdk.create_robot(config.hostname) # Since we are not using an auth token, we do not yet have access to the directory service. # As a result, we cannot look up the Payload Registration Service by service name. Instead, # we need to manually establish the channel with the authority of the Payload Registration # Service. kPayloadRegistrationAuthority = 'payload-registration.spot.robot' payload_registration_channel = robot.ensure_secure_channel( kPayloadRegistrationAuthority) # Create a payload registration client. payload_registration_client = robot.ensure_client( PayloadRegistrationClient.default_service_name, channel=payload_registration_channel) # Populate a payload proto definition with the details of this payload # Secret does not need to be human readable. payload = payload_protos.Payload() payload.GUID = config.guid payload.name = config.name payload.description = config.description payload.label_prefix.append('default configuration') payload.is_authorized = False # is_authorized must be false at registration time payload.is_enabled = False # is_enabled must be false at registration time payload.is_noncompute_payload = False # Populate the mount part of the payload configuration. payload.mount_tform_payload.position.x = 0 payload.mount_tform_payload.position.y = 0 payload.mount_tform_payload.position.z = 0 payload.mount_tform_payload.rotation.x = 0 payload.mount_tform_payload.rotation.y = 0 payload.mount_tform_payload.rotation.z = 0 payload.mount_tform_payload.rotation.w = 0 payload.mass_volume_properties.total_mass = 10 payload.mass_volume_properties.com_pos_rt_payload.x = 0 payload.mass_volume_properties.com_pos_rt_payload.y = 0 payload.mass_volume_properties.com_pos_rt_payload.z = 0 payload.mass_volume_properties.moi_tensor.xx = 0 payload.mass_volume_properties.moi_tensor.yy = 0 payload.mass_volume_properties.moi_tensor.zz = 0 payload.mass_volume_properties.moi_tensor.xy = 0 payload.mass_volume_properties.moi_tensor.xz = 0 payload.mass_volume_properties.moi_tensor.yz = 0 bb = payload.mass_volume_properties.bounding_box.add() bb.box.size.x = 1 bb.box.size.y = 1 bb.box.size.z = 1 bb.frame_name_tform_box.position.x = 0 bb.frame_name_tform_box.position.y = 0 bb.frame_name_tform_box.position.z = 0 bb.frame_name_tform_box.rotation.x = 0 bb.frame_name_tform_box.rotation.y = 0 bb.frame_name_tform_box.rotation.z = 0 bb.frame_name_tform_box.rotation.w = 1.0 bb.frame_name = "payload" # Populate preset configuration. preset_conf = payload.preset_configurations.add() preset_conf.preset_name = "Preset1" preset_conf.description = "Preset1 Description" # Populate the mount part of the payload configuration. preset_conf.mount_tform_payload.position.x = 1.1 preset_conf.mount_tform_payload.position.y = 1.1 preset_conf.mount_tform_payload.position.z = 1.1 preset_conf.mount_tform_payload.rotation.x = 1.1 preset_conf.mount_tform_payload.rotation.y = 1.1 preset_conf.mount_tform_payload.rotation.z = 1.1 preset_conf.mount_tform_payload.rotation.w = 1.1 # Populate the mass volume part of the payload configuration. preset_conf.mass_volume_properties.total_mass = 10.1 preset_conf.mass_volume_properties.com_pos_rt_payload.x = 1.1 preset_conf.mass_volume_properties.com_pos_rt_payload.y = 1.1 preset_conf.mass_volume_properties.com_pos_rt_payload.z = 1.1 preset_conf.mass_volume_properties.moi_tensor.xx = 1.1 preset_conf.mass_volume_properties.moi_tensor.yy = 1.1 preset_conf.mass_volume_properties.moi_tensor.zz = 1.1 preset_conf.mass_volume_properties.moi_tensor.xy = 1.1 preset_conf.mass_volume_properties.moi_tensor.xz = 1.1 preset_conf.mass_volume_properties.moi_tensor.yz = 1.1 bb = preset_conf.mass_volume_properties.bounding_box.add() bb.box.size.x = 1.1 bb.box.size.y = 1.1 bb.box.size.z = 1.1 bb.frame_name_tform_box.position.x = 1.1 bb.frame_name_tform_box.position.y = 1.1 bb.frame_name_tform_box.position.z = 1.1 bb.frame_name_tform_box.rotation.x = 1.1 bb.frame_name_tform_box.rotation.y = 1.1 bb.frame_name_tform_box.rotation.z = 1.1 bb.frame_name_tform_box.rotation.w = 1.1 bb.frame_name = "payload" joint_limit = preset_conf.mass_volume_properties.joint_limits.add() joint_limit.label = 'fr' joint_limit.hy.extend( [1.34, 1.35, 1.4, 1.5, 1.6, 1.65, 1.8, 1.9, 2.0, 2.2, 2.3, 5.0]) joint_limit.hx.extend([ -5.0, -0.85, -0.79, -0.73, -0.65, -0.46, -0.45, -0.49, -0.46, -0.44, -0.41, -1.5 ]) joint_limit = preset_conf.mass_volume_properties.joint_limits.add() joint_limit.label = 'fl' joint_limit.hy.extend( [1.34, 1.35, 1.4, 1.5, 1.6, 1.65, 1.8, 1.9, 2.0, 2.2, 2.3, 5.0]) joint_limit.hx.extend( [5.0, 0.85, 0.79, 0.73, 0.65, 0.46, 0.45, 0.49, 0.46, 0.44, 0.41, 1.5]) # Populate the label prefixes of the payload configuration. preset_conf.label_prefix.append('self registered') preset_conf.label_prefix.append('preset #1') # Register the payload. try: payload_registration_client.register_payload(payload, secret=config.secret) except PayloadAlreadyExistsError: print( "Payload config for {} already exists. Continuing with pre-existing configuration." .format(payload.GUID)) # Wait here until the admin authorizes the payload print( 'An admin MUST authorize (and optionally enable) the payload from the web UI before continuing...' ) while True: sleep(1) try: payload_registration_client.get_payload_auth_token( config.guid, config.secret) except PayloadNotAuthorizedError: continue break print('Payload has been authorized by admin.') return True
def define_payload(guid, name, description): """Return an arbitrary bosdyn.api.Payload object.""" # Populate the fields specified by the input arguments. # Secret does not need to be human readable. payload = payload_protos.Payload() payload.GUID = guid payload.name = name # Payload description will be overwritten by preset description if a non-default preset is # selected at operator authorization time. payload.description = description # Specify other top level fields with sample values. payload.label_prefix.append('default configuration') payload.is_authorized = False # is_authorized must be false at registration time payload.is_enabled = False # is_enabled must be false at registration time payload.is_noncompute_payload = False # Specify the location of the payload by populating mount_tform_payload with sample values. # This values will be used if the "default" payload configuration is selected at operator # authorization time, else they will be overwritten by the selected payload preset values. payload.mount_tform_payload.position.x = 0 # Aligned with forward-most bolt of mounting rails payload.mount_tform_payload.position.y = 0 # Centered along robot y-axis payload.mount_tform_payload.position.z = 0.1 # 0.1 m above robot's back # Identity quaternion (no rotation relative to mount frame) payload.mount_tform_payload.rotation.x = 0 payload.mount_tform_payload.rotation.y = 0 payload.mount_tform_payload.rotation.z = 0 payload.mount_tform_payload.rotation.w = 1 # Specify the physical properties of the payload with sample values. # These values will be used if the "default" payload configuration is selected at operator # authorization time, else they will be overwritten by the selected payload preset values. payload.mass_volume_properties.total_mass = 10 # Center of mass at origin of payload frame payload.mass_volume_properties.com_pos_rt_payload.x = 0 payload.mass_volume_properties.com_pos_rt_payload.y = 0 payload.mass_volume_properties.com_pos_rt_payload.z = 0 payload.mass_volume_properties.moi_tensor.xx = 0.06 # [kg*m^2] payload.mass_volume_properties.moi_tensor.yy = 0.06 payload.mass_volume_properties.moi_tensor.zz = 0.06 payload.mass_volume_properties.moi_tensor.xy = 0 payload.mass_volume_properties.moi_tensor.xz = 0 payload.mass_volume_properties.moi_tensor.yz = 0 bb = payload.mass_volume_properties.bounding_box.add() bb.box.size.x = 0.2 bb.box.size.y = 0.16 # Width of payload rails bb.box.size.z = 0.2 bb.frame_name_tform_box.position.x = 0 bb.frame_name_tform_box.position.y = 0 bb.frame_name_tform_box.position.z = 0 bb.frame_name_tform_box.rotation.x = 0 bb.frame_name_tform_box.rotation.y = 0 bb.frame_name_tform_box.rotation.z = 0 bb.frame_name_tform_box.rotation.w = 1.0 bb.frame_name = "payload" # Specify possible payload configurations by populating preset configs with sample values. # For example, define Preset1 as the same payload mounted on the center of the robot preset_conf_center = payload.preset_configurations.add() preset_conf_center.preset_name = "Preset1" preset_conf_center.description = "Preset1: Center-mounted configuration." # Specify the location of the payload under this possible configuration. preset_conf_center.mount_tform_payload.position.x = -0.2075 # Centered on robot back preset_conf_center.mount_tform_payload.position.y = 0 # Centered on robot back preset_conf_center.mount_tform_payload.position.z = 0.1 # 0.1 m above top surface # Identity quaternion (no rotation relative to mount frame) preset_conf_center.mount_tform_payload.rotation.x = 0 preset_conf_center.mount_tform_payload.rotation.y = 0 preset_conf_center.mount_tform_payload.rotation.z = 0 preset_conf_center.mount_tform_payload.rotation.w = 1 # Specify the physical properties of the payload under this possible configuration. preset_conf_center.mass_volume_properties.CopyFrom(payload.mass_volume_properties) # Specify joint limits for the front legs under this configuration joint_limit = preset_conf_center.mass_volume_properties.joint_limits.add() joint_limit.label = 'fr' joint_limit.hy.extend([1.34, 1.35, 1.4, 1.5, 1.6, 1.65, 1.8, 1.9, 2.0, 2.2, 2.3, 5.0]) joint_limit.hx.extend( [-5.0, -0.85, -0.79, -0.73, -0.65, -0.46, -0.45, -0.49, -0.46, -0.44, -0.41, -1.5]) joint_limit = preset_conf_center.mass_volume_properties.joint_limits.add() joint_limit.label = 'fl' joint_limit.hy.extend([1.34, 1.35, 1.4, 1.5, 1.6, 1.65, 1.8, 1.9, 2.0, 2.2, 2.3, 5.0]) joint_limit.hx.extend([5.0, 0.85, 0.79, 0.73, 0.65, 0.46, 0.45, 0.49, 0.46, 0.44, 0.41, 1.5]) # Populate the label prefixes of the payload configuration. preset_conf_center.label_prefix.append('self registered') preset_conf_center.label_prefix.append('preset #1') # Define Preset2 as the same payload mounted on the rear of the robot preset_conf_rear = payload.preset_configurations.add() preset_conf_rear.preset_name = "Preset2" preset_conf_rear.description = "Preset2: Rear-mounted configuration" # Specify the location of the payload under this possible configuration. preset_conf_rear.mount_tform_payload.position.x = -0.415 # Aligned with rear-most bolt of mounting rails preset_conf_rear.mount_tform_payload.position.y = 0 # Centered on robot back preset_conf_rear.mount_tform_payload.position.z = 0.1 # 0.1 m above top surface # Rotate the payload 180 degrees about the z axis preset_conf_rear.mount_tform_payload.rotation.x = 0 preset_conf_rear.mount_tform_payload.rotation.y = 0 preset_conf_rear.mount_tform_payload.rotation.z = 1 preset_conf_rear.mount_tform_payload.rotation.w = 0 # Specify the physical properties of the payload under this possible configuration. preset_conf_rear.mass_volume_properties.CopyFrom(payload.mass_volume_properties) # Populate the label prefixes of the payload configuration. preset_conf_rear.label_prefix.append('self registered') preset_conf_rear.label_prefix.append('preset #2') return payload
def define_payload(guid, name, description): """Return an arbitrary bosdyn.api.Payload object.""" # Populate the fields specified by the input arguments. # Secret does not need to be human readable. payload = payload_protos.Payload() payload.GUID = guid payload.name = name # Payload description will be overwritten by preset description if a non-default preset is # selected at operator authorization time. payload.description = description # Specify other top level fields with filler values. payload.label_prefix.append('default configuration') payload.is_authorized = False # is_authorized must be false at registration time payload.is_enabled = False # is_enabled must be false at registration time payload.is_noncompute_payload = False # Specify the location of the payload by populating mount_tform_payload with filler values. # This values will be used if the "default" payload configuration is selected at operator # authorization time, else they will be overwritten by the selected payload preset values. payload.mount_tform_payload.position.x = 0 payload.mount_tform_payload.position.y = 0 payload.mount_tform_payload.position.z = 0 payload.mount_tform_payload.rotation.x = 0 payload.mount_tform_payload.rotation.y = 0 payload.mount_tform_payload.rotation.z = 0 payload.mount_tform_payload.rotation.w = 0 # Specify the physical properties of the payload with filler values. # These values will be used if the "default" payload configuration is selected at operator # authorization time, else they will be overwritten by the selected payload preset values. payload.mass_volume_properties.total_mass = 10 payload.mass_volume_properties.com_pos_rt_payload.x = 0 payload.mass_volume_properties.com_pos_rt_payload.y = 0 payload.mass_volume_properties.com_pos_rt_payload.z = 0 payload.mass_volume_properties.moi_tensor.xx = 0 payload.mass_volume_properties.moi_tensor.yy = 0 payload.mass_volume_properties.moi_tensor.zz = 0 payload.mass_volume_properties.moi_tensor.xy = 0 payload.mass_volume_properties.moi_tensor.xz = 0 payload.mass_volume_properties.moi_tensor.yz = 0 bb = payload.mass_volume_properties.bounding_box.add() bb.box.size.x = 1 bb.box.size.y = 1 bb.box.size.z = 1 bb.frame_name_tform_box.position.x = 0 bb.frame_name_tform_box.position.y = 0 bb.frame_name_tform_box.position.z = 0 bb.frame_name_tform_box.rotation.x = 0 bb.frame_name_tform_box.rotation.y = 0 bb.frame_name_tform_box.rotation.z = 0 bb.frame_name_tform_box.rotation.w = 1.0 bb.frame_name = "payload" # Specify possible payload configurations by populating preset configs with filler values. preset_conf = payload.preset_configurations.add() preset_conf.preset_name = "Preset1" preset_conf.description = "Preset1 Description" # Specify the location of the payload under this possible configuration. preset_conf.mount_tform_payload.position.x = 1.1 preset_conf.mount_tform_payload.position.y = 1.1 preset_conf.mount_tform_payload.position.z = 1.1 preset_conf.mount_tform_payload.rotation.x = 1.1 preset_conf.mount_tform_payload.rotation.y = 1.1 preset_conf.mount_tform_payload.rotation.z = 1.1 preset_conf.mount_tform_payload.rotation.w = 1.1 # Specify the physical properties of the payload under this possible configuration. preset_conf.mass_volume_properties.total_mass = 10.1 preset_conf.mass_volume_properties.com_pos_rt_payload.x = 1.1 preset_conf.mass_volume_properties.com_pos_rt_payload.y = 1.1 preset_conf.mass_volume_properties.com_pos_rt_payload.z = 1.1 preset_conf.mass_volume_properties.moi_tensor.xx = 1.1 preset_conf.mass_volume_properties.moi_tensor.yy = 1.1 preset_conf.mass_volume_properties.moi_tensor.zz = 1.1 preset_conf.mass_volume_properties.moi_tensor.xy = 1.1 preset_conf.mass_volume_properties.moi_tensor.xz = 1.1 preset_conf.mass_volume_properties.moi_tensor.yz = 1.1 bb = preset_conf.mass_volume_properties.bounding_box.add() bb.box.size.x = 1.1 bb.box.size.y = 1.1 bb.box.size.z = 1.1 bb.frame_name_tform_box.position.x = 1.1 bb.frame_name_tform_box.position.y = 1.1 bb.frame_name_tform_box.position.z = 1.1 bb.frame_name_tform_box.rotation.x = 1.1 bb.frame_name_tform_box.rotation.y = 1.1 bb.frame_name_tform_box.rotation.z = 1.1 bb.frame_name_tform_box.rotation.w = 1.1 bb.frame_name = "payload" # Specify the joint limits of the payload under this possible configuration. joint_limit = preset_conf.mass_volume_properties.joint_limits.add() joint_limit.label = 'fr' joint_limit.hy.extend( [1.34, 1.35, 1.4, 1.5, 1.6, 1.65, 1.8, 1.9, 2.0, 2.2, 2.3, 5.0]) joint_limit.hx.extend([ -5.0, -0.85, -0.79, -0.73, -0.65, -0.46, -0.45, -0.49, -0.46, -0.44, -0.41, -1.5 ]) joint_limit = preset_conf.mass_volume_properties.joint_limits.add() joint_limit.label = 'fl' joint_limit.hy.extend( [1.34, 1.35, 1.4, 1.5, 1.6, 1.65, 1.8, 1.9, 2.0, 2.2, 2.3, 5.0]) joint_limit.hx.extend( [5.0, 0.85, 0.79, 0.73, 0.65, 0.46, 0.45, 0.49, 0.46, 0.44, 0.41, 1.5]) # Populate the label prefixes of the payload configuration. preset_conf.label_prefix.append('self registered') preset_conf.label_prefix.append('preset #1') return payload