Universal_Robots_ROS2_Driver icon indicating copy to clipboard operation
Universal_Robots_ROS2_Driver copied to clipboard

Hardware interface for sending motion primitives to the robot via the Instruction Executor instead of trajectories

Open mathias31415 opened this issue 11 months ago • 5 comments

This PR extends the ur_robot_driver package with a hardware interface for sending motion primitives to the robot via the Instruction Executor instead of traditional trajectory execution.

To reuse the state interface functionalities of the original hardware interface in the new motion_primitive_ur_driver, these functionalities have been refactored into a shared helper file: stateinterface_helper.hpp.

The implementation uses the motion_primitives_forward_controller, which is planned to be integrated into the ros2_controllers repository. (ros-controls/ros2_controllers#1636)

Motion primitives are received by the controller using the MotionPrimitive.msg from the industrial_robot_motion_interfaces package. A modified version of this message is used here, which includes additional helper types:

  • STOP_MOTION: Interrupts current robot motion and clears the motion queue.
  • MOTION_SEQUENCE_START and MOTION_SEQUENCE_END: Define a sequence block—primitives between these markers are grouped and executed as a single, blended motion sequence. This enables smooth transitions between individual primitives, unlike executing them one by one.

This implementation also depends on a pending Pull Request in the Universal_Robots_Client_Library. This PR extends the Instruction Executor with support for movec commands, which is required for executing circular Cartesian motions within this driver.

I'd appreciate any feedback or suggestions – thanks in advance!

mathias31415 avatar Apr 11 '25 11:04 mathias31415

Thank you for your contribution! I'll have a look at this hopefully soon.

urfeex avatar Apr 11 '25 12:04 urfeex

Just a high-level question while I go through this implementation: Why did you decide to add that functionality to another hardware interface rather than integrating it into the existing one?

Integrating it would allow to switch between modes during runtime, which is especially useful e.g. when users want to use freedrive mode in between.

We already have multiple modes in our current hardware interface calling different methods from the write() function depending on the operation mode.

urfeex avatar May 08 '25 10:05 urfeex

There's no specific reason for that, it's simply how I started implementing it. But you're probably right that it would be more elegant to integrate it into the existing hardware interface.

mathias31415 avatar May 21 '25 06:05 mathias31415

@urfeex I've now integrated the motion_primitives_ur_driver into the hardware_interface, which allows switching modes during operation. I'm happy to receive any feedback on this!

During the integration, I encountered the following issue:

Both the hardware_interface implementation and the InstructionExecutor (used to execute motion primitives) depend on a callback that is triggered when a trajectory is completed. In the current setup, the UR driver's callback function is overwritten, which means only one of these callbacks can be active at any given time.

To solve this, I register the InstructionExecutor's callback when motion primitives mode is activated, and restore the hardware_interface's callback when the mode is deactivated. To enable this mechanism, I added a method registerTrajDoneCallback() to the InstructionExecutor in the ur_client_library:

void urcl::InstructionExecutor::registerTrajDoneCallback()
{
  driver_->registerTrajectoryDoneCallback(
      std::bind(&InstructionExecutor::trajDoneCallback, this, std::placeholders::_1));
}

Let me know if you have any suggestions for a cleaner solution.

mathias31415 avatar Jun 02 '25 14:06 mathias31415

And one more question: I’ve documented everything a bit in README_MotionPrimitive.md. Should I integrate that into README.md? Or put it somewhere else? Or should I just leave it as it is?

mathias31415 avatar Jun 02 '25 15:06 mathias31415

@mathias31415 regarding b4f4dec, please let's keep that back for a follow-up PR.

urfeex avatar Jul 29 '25 07:07 urfeex

@mathias31415 could you please fix the merge conflicts for this?

urfeex avatar Oct 31 '25 17:10 urfeex

Codecov Report

:x: Patch coverage is 0% with 289 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 15.31%. Comparing base (1b121b7) to head (20d0bfe). :warning: Report is 507 commits behind head on main.

Files with missing lines Patch % Lines
ur_robot_driver/src/hardware_interface.cpp 0.00% 289 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##            main    #1341       +/-   ##
==========================================
+ Coverage   3.59%   15.31%   +11.72%     
==========================================
  Files         13       34       +21     
  Lines        947     3873     +2926     
  Branches     152      482      +330     
==========================================
+ Hits          34      593      +559     
- Misses       843     3263     +2420     
+ Partials      70       17       -53     
Flag Coverage Δ
unittests 15.31% <0.00%> (+11.72%) :arrow_up:

Flags with carried forward coverage won't be shown. Click here to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov[bot] avatar Nov 03 '25 07:11 codecov[bot]