Tuning Joint PID Controllers in Gazebo for Stable Robot Motion
Learn how to implement and tune PID controllers in Gazebo to eliminate joint jitter and achieve stable robot motion using SDF plugins and ROS 2.
12 Jul 2025, 17:04 UTC

The Challenge of Joint Stability in Simulation
When simulating robot joints in Gazebo, a common failure is the "jittering" or "exploding" joint—where a limb oscillates violently or flies apart upon simulation start. This typically happens because the PID (Proportional-Integral-Derivative) gains are mismatched with the physics engine's step size or the model's inertia. The goal is to achieve a smooth transition to a target position without excessive overshoot or steady-state error.
Prerequisites
- Gazebo Classic (v11) or Ignition Gazebo installed.
- A robot model defined in SDF (Simulation Description Format) with defined joints.
- ROS 2 (Humble or later) if using the
gazebo_ros_controlplugin for parameter tuning. - Basic understanding of PID: P (Proportional) drives the joint toward the target, I (Integral) removes steady-state error, and D (Derivative) dampens the motion to prevent overshoot.
Implementing the PID Plugin
To control a joint, you must attach a plugin to the model in the SDF file. This plugin intercepts the physics loop to apply forces based on the error between the current and desired joint state.
Add the following configuration within the <model> tags of your SDF. This example assumes a ROS 2 interface for a single joint:
<plugin name="gazebo_ros_joint_pose_trajectory" filename="libgazebo_ros_joint_pose_trajectory.so">
<ros>
<namespace>/my_robot</namespace>
</ros>
<joint_name>arm_joint_1</joint_name>
<pid_gains>
<p>100.0</p>
<i>0.1</i>
<d>10.0</d>
</pid_gains>
<update_rate>100</update_rate>
</plugin>
Step-by-Step Tuning Procedure
Tuning should be performed incrementally to avoid simulation crashes. Follow this sequence:
- Isolate the Joint: Set all gains (P, I, D) to 0.0. Ensure the joint is not fighting gravity or other constraints.
- Increase P (Proportional): Slowly increase the P gain until the joint moves toward the target but exhibits significant oscillation. This establishes the basic responsiveness.
- Introduce D (Derivative): Increase the D gain to dampen the oscillations. The D term acts as a "brake," slowing the joint as it approaches the target to reduce overshoot.
- Fine-tune I (Integral): If the joint stops slightly short of the target (steady-state error), add a small amount of I gain. Use this sparingly; too much I gain causes "integral windup," leading to slow, large oscillations.
Diagnostic Decision Matrix
Use the following table to diagnose behavior during your tuning process:
| Observed Behavior | Likely Cause | Corrective Action |
|---|---|---|
| Joint does not move or is sluggish | P gain too low | Increase P incrementally |
| High-frequency jitter/vibration | P gain too high or Step Size too large | Decrease P or decrease max_step_size in .world file |
| Large overshoot and slow settling | D gain too low | Increase D gain |
| Joint drifts away from target over time | I gain too low or external force (gravity) | Increase I gain or add gravity compensation |
Verification and Testing
To verify the controller's performance, run the simulation and use a plotting tool like rqt_plot to compare the commanded position vs. the actual position.
Verification Command:
Run this in a terminal with access to your ROS 2 environment (permissions: user level):
ros2 topic echo /my_robot/arm_joint_1/state
Check that the position value converges to your target value within a reasonable tolerance (e.g., < 0.01 radians) without sustained oscillation.
Limitations and Risks
- Real-time Starvation: Setting the
<update_rate>too high (e.g., > 1000Hz) can starve the Gazebo physics thread, causing the simulation to lag or "stutter" even if your CPU is powerful. - Inertia Mismatch: Gains tuned for a massless joint will fail immediately once you add a heavy mesh or link. Always tune gains after defining the final
<inertial>properties of the link. - Version Drift: If migrating from Gazebo Classic to Ignition/Gazebo Sim, note that the plugin API changes. You will need to move from SDF
<plugin>blocks to the new System plugin architecture.
Rollback Strategy
Since this operation modifies the SDF configuration file, rollback is performed by reverting the XML changes. If the simulation becomes unstable (crashes on launch), delete the <plugin> block or reset the <pid_gains> to 0.0 to restore the model to a passive state.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.