Tutorial 4: Robot Execution — Connecting curobo_ros to Your Robot¶
🟡 Difficulty: Intermediate ⏱️ Estimated Time: 20-30 minutes
Overview¶
curobo_ros separates trajectory planning from trajectory execution. The planner generates a collision-free JointTrajectory — a robot driver then executes it. This tutorial explains how execution works, how to test with the built-in emulator, and how the Doosan M1013 driver is connected.
The Execution Pipeline¶
generate_trajectory service
│ JointTrajectory (positions, velocities, accelerations, timestamps)
▼
RobotContext ←── Strategy pattern: ghost / emulator / doosan / ur5e
│
├─► GhostStrategy → /trajectory (RViz preview, always active)
│
└─► Active Strategy
├─ EmulatorStrategy → /emulator/joint_states (JointState, progressive)
└─ DoosanControl → /leeloo/execute_trajectory (JointTrajectory, full)
The active strategy is selected at runtime. All strategies share the same interface — generate_trajectory never needs to know which robot is connected.
Available Strategies¶
Strategy |
Status |
Output Topic |
Description |
|---|---|---|---|
|
Always active |
|
RViz preview only, no execution |
|
Implemented |
|
Software emulator, progressive execution |
|
Implemented |
|
Real Doosan M1013 via driver |
|
Placeholder |
— |
Not yet implemented |
Section 1: Ghost Mode (Visualization Only)¶
Ghost mode is the default. Trajectories are displayed in RViz as a “preview robot” but nothing executes. It is always running in parallel, regardless of the active strategy.
ros2 param set /unified_planner robot_type "ghost"
ros2 service call /unified_planner/set_robot_strategy std_srvs/srv/Trigger
ros2 service call /unified_planner/generate_trajectory curobo_msgs/srv/TrajectoryGeneration \
"{target_pose: {position: {x: 0.5, y: 0.2, z: 0.3}, orientation: {w: 1.0}}}"
The preview robot in RViz (/preview/ namespace) shows the planned trajectory immediately.
Section 2: Emulator (Test Without Hardware)¶
The emulator replays the trajectory by publishing JointState messages progressively at the planned timestep. The main robot in RViz moves step by step, simulating real execution.
Switch to Emulator¶
ros2 param set /unified_planner robot_type "emulator"
ros2 service call /unified_planner/set_robot_strategy std_srvs/srv/Trigger
Response:
success: true
message: "Strategy switched from 'ghost' to 'emulator'"
Generate and Execute¶
# 1. Plan
ros2 service call /unified_planner/generate_trajectory curobo_msgs/srv/TrajectoryGeneration \
"{target_pose: {position: {x: 0.5, y: 0.2, z: 0.3}, orientation: {w: 1.0}}}"
# 2. Execute
ros2 action send_goal /unified_planner/execute_trajectory curobo_msgs/action/SendTrajectory "{}"
Feedback during execution:
step_progression: 0.25 # 25% complete
Result:
success: true
message: 'Trajectory executed successfully'
What the Emulator Publishes¶
Topic |
Type |
Description |
|---|---|---|
|
|
Current simulated joint positions, updated at each trajectory timestep |
The emulator reads back its own joint states as the “current robot position” for the next planning cycle.
Section 3: Real Robot — Doosan M1013¶
How the Doosan Driver Works¶
The Doosan strategy connects curobo_ros to the Doosan ROS driver (dsr_robot package). The interface is trajectory-based:
curobo_ros generates a
JointTrajectorywith positions, velocities, accelerations, and timestamps for every waypointThe strategy publishes the full trajectory to
/leeloo/execute_trajectoryThe Doosan driver executes it via velocity control — it follows each waypoint with the specified velocity and acceleration profile
The driver publishes execution progress on
/leeloo/trajectory_state(aFloat32from 0.0 to 1.0)curobo_ros reads this progress to report feedback through the
execute_trajectoryaction
curobo_ros
└─ DoosanControl
├── publishes → /leeloo/execute_trajectory (JointTrajectory)
└── subscribes ← /leeloo/trajectory_state (Float32, 0.0→1.0)
Doosan Driver (dsr_robot)
├── subscribes ← /leeloo/execute_trajectory
├── executes via velocity control
└── publishes → /dsr01/joint_states (JointState, current positions)
Note: The topic prefix
leeloois the name of the specific Doosan M1013 in the Lab-CORO. If your robot uses a different prefix, the driver configuration must be updated accordingly.
Joint State Remapping¶
The Doosan driver publishes joints in a non-standard order. The DoosanControl strategy handles this remapping internally:
Driver order: [j1, j2, j3, j4, j5, j6] (indices 0,1,4,2,3,5)
cuRobo order: [j1, j2, j5, j3, j4, j6]
This is transparent — you never need to handle it manually.
Prerequisites¶
Before using the Doosan strategy:
The
dsr_robotROS2 driver must be running and connected to the robotThe driver must be publishing to
/dsr01/joint_statesThe driver must be subscribed to
/leeloo/execute_trajectory
# Verify driver is running
ros2 topic hz /dsr01/joint_states # Should show ~100 Hz
# Verify execution topic exists
ros2 topic list | grep execute_trajectory
Switch to Doosan¶
ros2 param set /unified_planner robot_type "doosan_m1013"
ros2 service call /unified_planner/set_robot_strategy std_srvs/srv/Trigger
Generate and Execute¶
# 1. Plan
ros2 service call /unified_planner/generate_trajectory curobo_msgs/srv/TrajectoryGeneration \
"{target_pose: {position: {x: 0.5, y: 0.0, z: 0.4}, orientation: {w: 1.0}}}"
# 2. Execute
ros2 action send_goal /unified_planner/execute_trajectory curobo_msgs/action/SendTrajectory "{}"
Safety: Always verify the trajectory in ghost or emulator mode before executing on the real robot. Make sure the workspace is clear.
Section 4: Switching Strategies¶
All switches follow the same pattern:
# Check current strategy
ros2 service call /unified_planner/get_robot_strategy std_srvs/srv/Trigger
# Switch
ros2 param set /unified_planner robot_type "<strategy>"
ros2 service call /unified_planner/set_robot_strategy std_srvs/srv/Trigger
On switch:
The current robot is stopped immediately
Any trajectory in progress is cancelled
The new strategy initializes its topics and subscriptions
Section 5: Adding a New Robot (UR5e Pattern)¶
The UR5e driver is not yet implemented, but the architecture follows the same pattern as Doosan. Any new robot strategy must:
Subscribe to the robot’s joint state topic to read current positions
Publish a
JointTrajectory(or equivalent) to the robot driverTrack execution progress and report it via
get_progression()
The control mode depends on the robot driver — the Doosan uses position + velocity + acceleration per waypoint with time_from_start. A UR5e would likely use the same JointTrajectory format via the ur_robot_driver package.
Troubleshooting¶
Strategy switch fails with ur5e¶
ur5e is a placeholder. Use emulator for testing without hardware.
Robot doesn’t move after execute_trajectory¶
Verify the strategy is active:
ros2 service call /unified_planner/get_robot_strategy std_srvs/srv/TriggerFor emulator: check
/emulator/joint_statesis publishing —ros2 topic hz /emulator/joint_statesFor Doosan: check the driver is running and
/leeloo/execute_trajectoryhas a subscriber —ros2 topic info /leeloo/execute_trajectory
Doosan executes but position is wrong¶
Check that robot_config_file matches the physical robot (joint limits, kinematics). Verify /dsr01/joint_states matches the robot’s actual pose before planning.