Joint Trajectory Controller#
The Joint Trajectory Controller commands trajectories across multiple joints simultaneously. Trajectories are specified as a sequence of waypoints : each with a target time and optionally positions, velocities, and accelerations : and the controller interpolates between them using cubic splines to produce smooth motion.
This controller is required for:
Planned trajectories coming from MoveIt
Playback of pre-defined motions
Overview#
Parameter |
Value |
|---|---|
Controller type |
|
ROS 2 node name |
|
Command interfaces |
|
State interfaces |
|
Topics#
Direction |
Topic |
Type |
Description |
|---|---|---|---|
Subscribes |
|
|
Fire-and-forget trajectory commands |
Publishes |
|
|
Internal state published at the controller manager update rate |
Actions#
Action |
Type |
Description |
|---|---|---|
|
|
Primary interface for sending trajectories with execution monitoring and result feedback |
Services#
Service |
Type |
Description |
|---|---|---|
|
|
Query the expected controller state at any future time point |
Key Features#
Spline interpolation : cubic splines are used by default to produce smooth, continuous joint motion between waypoints. When velocities and accelerations are provided alongside positions, a quintic spline is used for higher-order continuity.
Flexible command interfaces : supports
position,velocity,acceleration, andeffortcommand interfaces. The active interface is selected per controller instance via thecommand_interfacesparameter.Trajectory replacement : a new trajectory can be sent at any time and will seamlessly replace the current one, with the controller splicing in from the present state to avoid discontinuities.
Partial joint goals : when
allow_partial_joints_goalis enabled, a trajectory that only specifies a subset of the controller’s joints is accepted; unspecified joints hold their last commanded state.Tolerance checking : path tolerances (per-point), goal tolerances (at the end of the trajectory), and a goal time tolerance are all configurable per joint. Violations abort the trajectory and report a failure result on the action.
Open-loop and closed-loop control : with
open_loop_control: truethe controller interpolates purely from the last commanded state, which avoids integrating sensor noise; with closed-loop control it re-seeds interpolation from the measured joint state at each update cycle.
How it Works#
Trajectory reception#
Trajectories arrive either through the follow_joint_trajectory action (recommended : provides feedback and a result) or the joint_trajectory topic (fire-and-forget). Both paths feed the same internal trajectory queue.
Interpolation#
At each control update the controller determines the current desired state by evaluating the active spline at the elapsed time. If the incoming waypoints include only positions, a cubic spline is fit; if velocities are also present, the spline matches first derivatives at each knot; if accelerations are included, a quintic spline matches second derivatives as well.
Command generation#
The interpolated desired state is forwarded to the hardware command interfaces. In position mode the desired position is written directly. In effort mode the controller runs an internal PID loop : using the per-joint gains : on the position (and optionally velocity) error to produce an effort command.
Tolerance monitoring#
After each update the controller compares the actual joint state against the desired state. If any joint exceeds its configured path tolerance the trajectory is aborted immediately. Once the final waypoint’s time has elapsed, the controller checks goal tolerances and the goal time window and reports success or failure back through the action result.
Configuration Examples#
Position Command Mode#
Used by the default leg controllers. The controller commands joint positions directly; no PID gains are needed at this level since the actuator’s own position loop handles tracking.
${LEG_SIDE_PREFIX}_position_controller:
ros__parameters:
type: joint_trajectory_controller/JointTrajectoryController
open_loop_control: true
joints:
- ${LEG_SIDE_PREFIX}_1_joint
- ${LEG_SIDE_PREFIX}_2_joint
- ${LEG_SIDE_PREFIX}_3_joint
- ${LEG_SIDE_PREFIX}_length_joint
- ${LEG_SIDE_PREFIX}_4_joint
- ${LEG_SIDE_PREFIX}_5_joint
command_interfaces:
- position
state_interfaces:
- position
constraints:
goal_time: 0.6
stopped_velocity_tolerance: 5.0
${LEG_SIDE_PREFIX}_1_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_2_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_3_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_4_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_5_joint: {goal: 0.02}
Effort Command Mode#
Commands joint efforts (torques) rather than positions. The controller closes its own PID loop on position error and outputs effort commands, so per-joint gains are required. Both position and velocity state interfaces are used for feedback.
${LEG_SIDE_PREFIX}_jtc_effort_controller:
ros__parameters:
type: joint_trajectory_controller/JointTrajectoryController
open_loop_control: true
joints:
- ${LEG_SIDE_PREFIX}_1_joint
- ${LEG_SIDE_PREFIX}_2_joint
- ${LEG_SIDE_PREFIX}_3_joint
- ${LEG_SIDE_PREFIX}_length_joint
- ${LEG_SIDE_PREFIX}_4_joint
- ${LEG_SIDE_PREFIX}_5_joint
command_interfaces:
- effort
state_interfaces:
- position
- velocity
constraints:
goal_time: 0.6
stopped_velocity_tolerance: 5.0
${LEG_SIDE_PREFIX}_1_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_2_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_3_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_4_joint: {goal: 0.02}
${LEG_SIDE_PREFIX}_5_joint: {goal: 0.02}
gains:
${LEG_SIDE_PREFIX}_1_joint: {p: 100.0, d: 0.0, i: 0.0, i_clamp_min: -1.0, i_clamp_max: 1.0}
${LEG_SIDE_PREFIX}_2_joint: {p: 250.0, d: 0.0, i: 0.0, i_clamp_min: -1.0, i_clamp_max: 1.0}
${LEG_SIDE_PREFIX}_3_joint: {p: 350.0, d: 0.0, i: 10.0, i_clamp_min: -5.0, i_clamp_max: 5.0}
${LEG_SIDE_PREFIX}_4_joint: {p: 75.0, d: 0.0, i: 0.0, i_clamp_min: -1.0, i_clamp_max: 1.0}
${LEG_SIDE_PREFIX}_5_joint: {p: 150.0, d: 0.0, i: 0.0, i_clamp_min: -1.0, i_clamp_max: 1.0}
${LEG_SIDE_PREFIX}_length_joint: {p: 3000.0, d: 10.0, i: 3.0, i_clamp_min: -1.0, i_clamp_max: 1.0}