Skip to content

Allow setting payload inertia matrix via set_payload service #1808

Open
srvald wants to merge 4 commits into
UniversalRobots:mainfrom
srvald:set_payload_inertia
Open

Allow setting payload inertia matrix via set_payload service #1808
srvald wants to merge 4 commits into
UniversalRobots:mainfrom
srvald:set_payload_inertia

Conversation

@srvald

@srvald srvald commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the driver-side changes to support the extended SetPayload service,
which now accepts a full geometry_msgs/Inertia payload (mass, center of gravity,
and 6-component inertia tensor) and a transition_time field.

This enables use of the robot's set_target_payload(m, cog, inertia, transition_time)
URScript function instead of the simpler set_payload(m, cog) (DEPRECATED).

Note: This PR depends on the updated ur_msgs/SetPayload.srv (ros-industrial/ur_msgs#42) and on the
setTargetPayload() addition to ur_client_library (UniversalRobots/Universal_Robots_Client_Library#515).

Breaking changes

The set_payload service request format changes (driven by the ur_msgs update).
Any existing callers must be updated to use geometry_msgs/Inertia instead of
separate mass and cog fields.

Changes

ur_controllers

  • Added PAYLOAD_INERTIA_IXX/IYY/IZZ/IXY/IXZ/IYZ and PAYLOAD_TRANSITION_TIME
    entries to the CommandInterfaces enum in gpio_controller.hpp
  • Added PAYLOAD_STATE_INERTIA_* entries to the StateInterfaces enum
  • Extended command_interface_configuration() and state_interface_configuration()
    with the new payload interfaces
  • Updated setPayload() callback to pass inertia and transition_time to the
    command interfaces
  • Extended waitForPayloadRtdeMatch() to verify inertia components and to wait
    for transition_time to elapse before checking RTDE feedback

ur_robot_driver

  • Added payload_inertia_, payload_transition_time_ and rtde_payload_inertia_ members to hardware_interface.hpp
  • Added inertia and transition_time command interfaces and payload state interfaces
    (backed by RTDE feedback) to export_state_interfaces() and
    export_command_interfaces() in hardware_interface.cpp
  • Updated checkAsyncIO() to call setTargetPayload() instead of setPayload().
  • Added payload_inertia to rtde_output_recipe.txt
  • Updated ur.ros2_control.xacro with the new payload command and state interfaces
  • Added integration_test_payload.py and registered it in CMakeLists.txt

Test

Open one terminal and launch the ur_ros2_driver by:

ros2 launch ur_robot_driver ur_control.launch.py ur_type:=<robot_type> robot_ip:=<robot_ip>

Then in another terminal execute:

ros2 service call /io_and_status_controller/set_payload ur_msgs/srv/SetPayload '{payload: {m: 0.01, com: {x: 0.2, y: 0.1, z: 0.3}, ixx: 0.01, ixy: 0.0, ixz: 0.03, iyy: 0.01, iyz: 0.02, izz: 0.01}, transition_time: 1.0}'

It will successfully set the new changes.

Design notes

geometry_msgs/Inertia was chosen because it encapsulates mass, center of gravity,
and the full inertia tensor in a single standard ROS type, resulting in a cleaner API.

This is a breaking change: the previous mass (float32) and cog (Vector3) fields
are replaced by geometry_msgs/Inertia payload. A backwards-compatible alternative
would be to keep mass and cog and add individual float64 fields for the inertia
components (ixx, iyy, izz, ixy, ixz, iyz) and transition_time.
If this approach is preferred, then I'll update the implementation, which will mean that the SetPayload.srv will be:

float32 mass  
geometry_msgs/Vector3 cog  
float64 ixx  
float64 iyy  
float64 izz  
float64 ixy  
float64 ixz  
float64 iyz  
float64 transition_time  
---  
bool success  

Related issues

Closes #1711


Note

Medium Risk
Breaking SetPayload API and changes how robot payload is applied (setTargetPayload); incorrect inertia or timing could affect dynamics and motion, though scope is limited to payload configuration.

Overview
Extends set_payload so callers can set a full tool payload (mass, center of gravity, inertia tensor, and optional ramp time) instead of mass/COG only, using UR’s set_target_payload path rather than deprecated set_payload.

GPIOController maps the updated SetPayload request (geometry_msgs/Inertia + transition_time) onto new ros2_control command interfaces for inertia components and transition time, and waitForPayloadRtdeMatch now compares RTDE payload_inertia feedback (with tolerances) and sleeps for transition_time before verification when enabled.

URPositionHardwareInterface wires matching command/state GPIOs, reads payload_inertia from RTDE, and triggers setTargetPayload once all payload fields are written. ur.ros2_control.xacro and rtde_output_recipe.txt are updated accordingly.

Adds integration_test_payload.py (mass/COG-only, full inertia, transition time, sequential updates). Breaking: existing SetPayload clients must adopt the new ur_msgs request shape; depends on ur_msgs and ur_client_library companion PRs.

Reviewed by Cursor Bugbot for commit ae33e9e. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread ur_robot_driver/src/hardware_interface.cpp

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit ae33e9e. Configure here.

readData(data_package_buffer_, "tcp_offset", tcp_offset_);
readData(data_package_buffer_, "payload", rtde_payload_mass_);
readData(data_package_buffer_, "payload_cog", rtde_payload_cog_);
readData(data_package_buffer_, "payload_inertia", rtde_payload_inertia_);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RTDE read throws missing inertia

High Severity

The driver always reads payload_inertia from each RTDE packet and throws if the field is absent. Controllers or PolyScope builds that negotiate RTDE without that output can fail during read() instead of degrading payload-inertia verification only.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ae33e9e. Configure here.


if (transition_time > 0.0) {
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(transition_time * 1000)));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transition wait starts too early

Medium Severity

With verify_payload_on_set enabled, waitForPayloadRtdeMatch sleeps for the full transition_time only after async success returns, not from when the robot actually starts the transition. Early async completion plus delayed script execution can make RTDE checks run before inertia values settle, causing false verification failures.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ae33e9e. Configure here.

PAYLOAD_STATE_INERTIA_IXY = 78,
PAYLOAD_STATE_INERTIA_IXZ = 79,
PAYLOAD_STATE_INERTIA_IYZ = 80,
PAYLOAD_STATE_TRANSITION_TIME = 81,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid payload state enum index

Low Severity

PAYLOAD_STATE_TRANSITION_TIME is defined as index 81, but state_interface_configuration() only registers payload state interfaces through index 80. There is no matching state interface, so using this enum would index past the claimed interfaces.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ae33e9e. Configure here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Payload mass, cog and inertial matrix

2 participants