Skip to content

robotiq_description: command the gripper opening in metres #82

Description

@ebarnett3

The shipped 2F descriptions model the driven joint as the revolute knuckle, so gripper_cmd goals and /joint_states are in radians against gripper_closed_position. That is the wrong parameterization for a parallel gripper: what callers want is the jaw opening, and every consumer that needs it converts radians back to millimetres on its own.

Parallel grippers are normally modelled as a slider, with the linkage as passive joints for visuals. Franka's hand is the reference shape — finger_joint1 is type="prismatic" in metres, finger_joint2 is a <passive_joint> in the SRDF, and its group states are metres. This description is revolute because it was modelled on the visible knuckle rather than on the useful quantity.

Why it matters

  • The MCP server carries its own radians<->mm map (mcp/gripper_mcp/units.py), whose docstring already calls itself a stopgap. It cannot even own the calibration: robot_description.py reads the command joint and gripper_closed_position out of the driver's URDF at runtime so the two agree on "closed".
  • The tsf_demo consumers work in mm end to end — grip-width thresholds, opening as a model feature for object recognition — and bypass the ROS driver entirely, opening the serial port with pyRobotiqGripper to call position_mm().
  • That makes three definitions of one conversion: the driver's, the MCP's, and pyRobotiqGripper's.

Plan

  1. Read side, additive, no URDF change. Publish the opening in metres on the GripperStatus message from Publish object_status (gOBJ) and motor_current so clients can read them #74. This is what the MCP actually needs and it needs no description work at all; it can land first and on its own.
  2. Command side. Add a prismatic command joint in metres per model, on a dummy child link, and re-point the existing mimics from the knuckle joint to it. The relation is exactly linear, so a plain <mimic multiplier="..." offset="..."/> covers it — offset is already used in robotiq_2f_140.xacro. Do not chain mimics; resolution is single-level in both robot_state_publisher and ros2_control.
  3. Keep the radians joint for one release, behind an opt-out xacro flag, so consumers migrate on their own schedule. Humble's retirement on 2027-05-31 is a natural sunset. Both command interfaces start NaN and ros2_control claims command interfaces exclusively, so an unclaimed one is never written — "the non-NaN one wins" is a direct read of what the controller manager handed out, not a heuristic. Two claimed at once is a configuration error to report.
  4. Derive, do not duplicate. The metres mapping comes from the SDK (units::openingFromRegister / openingToRegister); the radians one is derived from it, not a second independent mapping off gPO. Otherwise this reintroduces exactly the duplication Consume the SDK's SI conversions #70 exists to remove.

Knock-ons

The driver reads info_.joints.at(0) and is already joint-name agnostic, so the rename costs it nothing. What changes is the scale source: gripper_closed_position (one number) becomes a DeviceProfile. That parameter shape is shared with #44, #45 and #46, so it should be settled once.

Acceptance criterion: all six DeviceProfile fields come from the description, the count band included. The SDK's arithmetic is already parameterized — openingFromRegister / openingToRegister work off profile.registerPositionRange(), so a hardcoded band cannot exist inside the conversions — but profiles::k2F85 hardcodes openPosition 3 and closedPosition 230. A driver that passes the shipped profile has moved the hardcoding to another repo rather than removed it.

Those two counts are installation state, not model constants: non-standard fingertips are common and meet before the linkage runs out of travel, so the closed end lands below 230 (robotiq/grippers#34 has the detail and the bench test that confirms it). Today gripper_scaling.hpp hardcodes 3 and 230 for every model and takes gripper_closed_position as its only position parameter, so an installation whose fingers meet early gets compressed feedback and intermediate commands that overshoot — a half-closed command reaches for count 116 when half the real travel is nearer 101.

The pattern already exists in the driver: gripper_min_speed / gripper_max_speed arrive as <hardware> parameters rather than from k2F85, because the description is the authority on the installation. openPosition / closedPosition should arrive the same way, with the shipped profile as the fallback for anyone who has not measured. DeviceProfile is a plain struct with public members, so the driver can construct one from parameters and the SDK needs no change.

The failure mode is quiet: the band inherits k2F85 while the parameterization is designed around opening, speed and force, and nobody notices until a gripper with custom tips goes to the wrong place.

Numbers that are silently in the wrong unit once the command joint is metres:

Where Today In metres
goal_tolerance: 0.02 (both controller configs) 0.02 rad, about 2 mm 0.02 m is 20 mm, a quarter of the stroke
trigger_joint_command_threshold: 0.02 (topic-based sim) 0.02 rad 0.02 m is 23% of the stroke
max_velocity: 0.5 / max_effort: 50.0 rad/s m/s
initial_value on the position state interface ${gripper_closed_position} 0.0
<limit velocity="0.5" effort="50"> per joint rad/s m/s
GRIPPER_JOINTS in robotiq_control.launch.py joint names already a map, just new names

Gazebo drops a link with no inertial, so the dummy link needs a token one or an xacro:unless sim_gazebo. The extra joint also appears in the MoveIt Setup Assistant's joint list and in /joint_states; a chain-based group or an SRDF that names joints explicitly will not pick it up, but it is worth a comment in the xacro and a line in the README.

The description tests are already parameterized on (model, joint), so a rename flows through them; test_ros2_control_urdf.py has a mimic-joint test to extend.

Blocks

#70 item 3, and with it the MCP's units.py / robot_description.py.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions