diff --git a/hardware/opentrons_hardware/firmware_bindings/constants.py b/hardware/opentrons_hardware/firmware_bindings/constants.py index 096cb580131..69ba89e153f 100644 --- a/hardware/opentrons_hardware/firmware_bindings/constants.py +++ b/hardware/opentrons_hardware/firmware_bindings/constants.py @@ -154,6 +154,9 @@ class MessageId(int, Enum): set_gripper_error_tolerance = 0x47 gripper_jaw_state_request = 0x48 gripper_jaw_state_response = 0x49 + set_gripper_jaw_holdoff_request = 0x401 + gripper_jaw_holdoff_request = 0x402 + gripper_jaw_holdoff_response = 0x403 acknowledgement = 0x50 diff --git a/hardware/opentrons_hardware/firmware_bindings/messages/message_definitions.py b/hardware/opentrons_hardware/firmware_bindings/messages/message_definitions.py index 070842001f4..8417309ca27 100644 --- a/hardware/opentrons_hardware/firmware_bindings/messages/message_definitions.py +++ b/hardware/opentrons_hardware/firmware_bindings/messages/message_definitions.py @@ -640,6 +640,35 @@ class GripperJawStateResponse(BaseMessage): # noqa: D101 ] = MessageId.gripper_jaw_state_response +@dataclass +class SetGripperJawHoldoffRequest(BaseMessage): # noqa: D101 + payload: payloads.GripperJawHoldoffPayload + payload_type: Type[ + payloads.GripperJawHoldoffPayload + ] = payloads.GripperJawHoldoffPayload + message_id: Literal[ + MessageId.set_gripper_jaw_holdoff_request + ] = MessageId.set_gripper_jaw_holdoff_request + + +@dataclass +class GripperJawHoldoffResponse(BaseMessage): # noqa: D101 + payload: payloads.GripperJawHoldoffPayload + payload_type: Type[ + payloads.GripperJawHoldoffPayload + ] = payloads.GripperJawHoldoffPayload + message_id: Literal[ + MessageId.gripper_jaw_holdoff_response + ] = MessageId.gripper_jaw_holdoff_response + + +@dataclass +class GripperJawHoldoffRequest(EmptyPayloadMessage): # noqa: D101 + message_id: Literal[ + MessageId.gripper_jaw_holdoff_request + ] = MessageId.gripper_jaw_holdoff_request + + @dataclass class GripperGripRequest(BaseMessage): # noqa: D101 payload: payloads.GripperMoveRequestPayload diff --git a/hardware/opentrons_hardware/firmware_bindings/messages/messages.py b/hardware/opentrons_hardware/firmware_bindings/messages/messages.py index 633825ed861..894eeb06e79 100644 --- a/hardware/opentrons_hardware/firmware_bindings/messages/messages.py +++ b/hardware/opentrons_hardware/firmware_bindings/messages/messages.py @@ -96,6 +96,9 @@ defs.GetMotorUsageResponse, defs.GripperJawStateRequest, defs.GripperJawStateResponse, + defs.SetGripperJawHoldoffRequest, + defs.GripperJawHoldoffRequest, + defs.GripperJawHoldoffResponse, ] diff --git a/hardware/opentrons_hardware/firmware_bindings/messages/payloads.py b/hardware/opentrons_hardware/firmware_bindings/messages/payloads.py index 1e31028957e..62244449d0e 100644 --- a/hardware/opentrons_hardware/firmware_bindings/messages/payloads.py +++ b/hardware/opentrons_hardware/firmware_bindings/messages/payloads.py @@ -527,6 +527,13 @@ class GripperJawStatePayload(EmptyPayload): state: utils.UInt8Field +@dataclass(eq=False) +class GripperJawHoldoffPayload(EmptyPayload): + """A respones carrying info about the jaw holdoff value of a gripper.""" + + holdoff_ms: utils.UInt32Field + + @dataclass(eq=False) class GripperMoveRequestPayload(AddToMoveGroupRequestPayload): """A request to move gripper.""" diff --git a/hardware/opentrons_hardware/hardware_control/gripper_settings.py b/hardware/opentrons_hardware/hardware_control/gripper_settings.py index 6012e12da49..e048a072412 100644 --- a/hardware/opentrons_hardware/hardware_control/gripper_settings.py +++ b/hardware/opentrons_hardware/hardware_control/gripper_settings.py @@ -21,6 +21,9 @@ BrushedMotorConfResponse, GripperJawStateRequest, GripperJawStateResponse, + SetGripperJawHoldoffRequest, + GripperJawHoldoffRequest, + GripperJawHoldoffResponse, ) from opentrons_hardware.firmware_bindings.utils import ( UInt8Field, @@ -100,6 +103,51 @@ async def set_error_tolerance( log.error(f"recieved error trying to set gripper error tolerance {str(error)}") +async def set_jaw_holdoff( + can_messenger: CanMessenger, + holdoff_ms: float, +) -> None: + """Set the idle holdoff value for gripper jaw.""" + error = await can_messenger.ensure_send( + node_id=NodeId.gripper_g, + message=SetGripperJawHoldoffRequest( + payload=payloads.GripperJawHoldoffPayload( + holdoff_ms=UInt32Field(int(holdoff_ms * (2**16))) + ) + ), + expected_nodes=[NodeId.gripper_g], + ) + if error != ErrorCode.ok: + log.error( + f"recieved error trying to set gripper jaw holdoff value {str(error)}" + ) + + +async def get_jaw_holdoff_ms(can_messenger: CanMessenger) -> float: + """Get the idle holdoff value for gripper jaw.""" + + def _filter(arbitration_id: ArbitrationId) -> bool: + return NodeId(arbitration_id.parts.originating_node_id) == NodeId.gripper_g + + async def _wait_for_response(reader: WaitableCallback) -> float: + """Listener for receiving messages back.""" + async for response, _ in reader: + if isinstance(response, GripperJawHoldoffResponse): + return float(response.payload.holdoff_ms.value / (2**16)) + raise StopAsyncIteration + + with WaitableCallback(can_messenger, _filter) as reader: + await can_messenger.send( + node_id=NodeId.gripper_g, + message=GripperJawHoldoffRequest(), + ) + try: + return await asyncio.wait_for(_wait_for_response(reader), 1.0) + except asyncio.TimeoutError: + log.warning("Read gripper jaw idle holdoff value timed out") + raise StopAsyncIteration + + async def get_gripper_jaw_motor_param( can_messenger: CanMessenger, ) -> DriverConfig: