# ros2_controllers is a catalogue of ready-made controllers for ros2_control

> ros2_controllers collects the general purpose robot controllers and sensor broadcasters that accompany the ros2_control framework, from a joint trajectory controller to diff drive, mecanum and steering variants, and it publishes them per ROS 2 distribution with binary builds. It is Apache-2.0 licensed and its default branch tracks Rolling.

**ros-controls/ros2_controllers** — Generic robotic controllers to accompany ros2_control

- Repository: https://github.com/ros-controls/ros2_controllers
- Website: https://control.ros.org
- Stars: 850 · Forks: 545
- Language: C++
- License: Apache-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/ros-controls-ros2-controllers

## A bag of general purpose controllers, not a robot

ros2_controllers is the collection of commonly used, generalised controllers for the ros2_control framework, and the README states they are ready to use with many robots as well as with MoveIt2 and Nav2.

The scope is worth being precise about. This is not a robot description repository and not a driver. It is the layer that sits between a hardware interface and a motion command, and it is deliberately generic. A joint trajectory controller moves named joints along a trajectory regardless of whether they are wheels, legs or a gripper. A diff drive controller turns velocity commands into wheel commands regardless of the chassis.

The primary language is C++, and the licence is Apache-2.0, which is the usual choice for ROS 2 core packages and the one most downstream vendors are comfortable with.

The project is hosted under the ros-controls organisation and its homepage is control.ros.org, which is also where the documentation for each distribution lives. The repository is not archived and the last push was on 2026-10-19, so it is a living repository rather than a frozen one.

The alternative to using it is writing a controller plugin yourself against the ros2_control interfaces. That is a reasonable amount of work for a simple wheel controller, and a large amount of work for the state broadcasting and trajectory handling that this repository already implements and tests.

## Twenty packages, split into three families

The top level directory is a good index of what the repository contains, because every controller is its own package.

The motion side starts with joint_trajectory_controller and forward_command_controller, which are the two ends of the spectrum, a trajectory follower and a direct passthrough of commands. Then there is pid_controller for the simple proportional integral derivative case, and motion_primitives_controllers for controllers built from composed motion primitives rather than a single behaviour.

The base drive controllers cover the usual chassis shapes. diff_drive_controller handles the two wheel differential drive, mecanum_drive_controller and omni_wheel_drive_controller cover the omnidirectional variants, and there are three steering implementations: tricycle_controller, tricycle_steering_controller, bicycle_steering_controller and ackermann_steering_controller. A shared steering_controllers_library sits underneath the steering ones, and chained_filter_controller and admittance_controller handle the more specialised cases of filtering a command chain and of compliant control.

The gripper case has its own package in parallel_gripper_controller, and rqt_joint_trajectory_controller provides a runtime interface for inspecting and manipulating trajectory goals.

Then there is a second family, the broadcasters, and the third is the metapackage ros2_controllers that pulls the set together, alongside ros2_controllers_test_nodes for testing the stack.

A final outlier is gpio_controllers, which is not about motion at all.

## The broadcasters are the half of the repository nobody advertises

Look again at the directory names and a second family appears, one package per sensor or state source: joint_state_broadcaster, pose_broadcaster, imu_sensor_broadcaster, gps_sensor_broadcaster, magnetometer_broadcaster, range_sensor_broadcaster, force_torque_sensor_broadcaster, battery_state_broadcaster and state_interfaces_broadcaster.

These are the packages that publish the state of the robot onto the ROS graph, and they are where a new user gets the most value for the least work. A joint_state_broadcaster publishes the positions, velocities and efforts of every joint in the system, which is what MoveIt2, Nav2, RViz and most visualisation and planning tools expect to find. Without it you are not really using ros2_control in a way the rest of the ecosystem understands.

The same applies to the sensor broadcasters, though with a caveat. Each one is tied to a specific hardware interface, so publishing an IMU means your IMU driver has to expose the interface the broadcaster expects. The mapping from sensor to broadcaster is not automatic, and the README does not document which interface each broadcaster requires.

state_interfaces_broadcaster is the general case, and it is worth checking whether the specific broadcaster you need exists before you assume you must write one, since a generic broadcaster may cover a sensor that has no dedicated package.

## Five branches, because ROS 2 ships in five flavours

The build status table in the README is the most informative part of the document, and it exists because ROS 2 is versioned by distribution and the packages have to exist for each of them.

There are five rows. Rolling and Lyrical both build from the master branch, while Kilted, Jazzy and Humble have their own branches of the same name. Each row carries a binary build badge, a semi-binary build badge, a build.ros2.org status for the development job and for the released binary package, and a link to that distribution's documentation on control.ros.org.

The documentation link matters more than it looks. The controllers index for Rolling, Lyrical, Kilted, Jazzy and Humble are separate pages, and a controller's parameters and topic names can differ between distributions. Reading the Rolling documentation while running Humble is how people end up copying a parameter that does not exist in their installed version.

The two build variants, binary and semi-binary, are a ROS 2 packaging distinction that affects how the package is delivered. A binary package ships prebuilt artefacts, a semi-binary one ships sources that are compiled locally, which is the common case when the package depends on hardware specific libraries that cannot be distributed as binaries.

If you want to work on the controllers themselves, the README points at a contributing guide and at the pull request queue, and mentions that the project welcomes contributors regardless of background.

## The .repos files are how a workspace is pinned

The directory listing contains a large number of files with a .repos extension, and they are the mechanism for reproducing a workspace.

There are two sets. ros2_controllers.rolling.repos, ros2_controllers.lyrical.repos, ros2_controllers.kilted.repos, ros2_controllers.jazzy.repos and ros2_controllers.humble.repos cover the main release, and a parallel set named ros2_controllers-not-released.*.repos exists for each distribution, which presumably pins the repositories that are not yet part of a released package set. There are also ros_controls.*.repos files for the wider organisation.

A .repos file is a list of repositories with their branches and versions, and the point of shipping one per distribution is reproducibility. A developer or a CI job can fetch exactly the same set of source repositories that a given distribution release was built from, rather than tracking branches by hand.

That is the part of this repository that matters most for a production team. Controllers change, a robot that worked with the Humble version of a controller may not behave the same with a newer branch, and a pinned .repos file is how you find out what changed.

The README itself does not print the commands for using these files, so if you are new to the ROS 2 workspace tooling, the documentation on control.ros.org is where the workflow is described.

## When a general controller is the wrong shape for your robot

Two failure modes are worth planning for.

The first is a mechanism that does not fit the generalisation. The diff drive controller assumes a fixed wheelbase and two driven wheels. The steering controllers assume a particular steering geometry and a particular relationship between steering angle and drive velocity. A robot with an unusual configuration, a swerve chassis, a tracked vehicle or a manipulator with unusual joint coupling will end up fighting the controller's assumptions, and the usual result is a fork with modified parameters, which is the thing the repository is trying to avoid.

The second is the mismatch between a general controller and a specific robot's requirements. A robot that needs to limit joint velocity, handle a sensor with a different interface, or expose a custom state topic will need its own controller or a custom broadcaster, and the cost of maintaining that is on you.

The realistic alternative is to write a controller plugin directly against the ros2_control controller interface and use only the broadcasters from this repository, or the reverse. The split of responsibility matters: the broadcasters are nearly always reusable, while the motion controller is the part that is robot specific.

For evaluation, the practical sequence is to identify your mechanism, find the matching controller in the list above, and read that controller's documentation for your distribution before assuming the parameter names in an example config apply to you.

## Conclusion

ros2_controllers is the right starting point for a robot that fits a common configuration, because it removes the need to write a joint trajectory, diff drive or state broadcaster loop before you can even move the hardware, and it is tested against MoveIt2 and Nav2 workflows. It is the wrong choice when your mechanism is unusual enough that a stock controller does not fit, since the whole repository is a set of generalisations, and the cost of bending one of them can exceed writing your own controller in the ros2_control framework. Before adopting one, check the build status for the distribution you actually run, since the repository maintains separate branches for Humble, Jazzy, Kilted, Lyrical and Rolling, and read the controller documentation for that branch rather than the Rolling docs.

## FAQ

### What is ros2_controllers and what is it for?

It is a collection of commonly used, generalised controllers for the ros2_control framework, ready to use with many robots as well as with MoveIt2 and Nav2. The primary language is C++ and the project is licensed under Apache-2.0.

### Which ROS 2 distributions does ros2_controllers support?

The build status table lists Rolling and Lyrical building from the master branch, plus dedicated branches for Kilted, Jazzy and Humble. Each distribution has its own controller documentation on control.ros.org, and the topic list names ros2-humble, ros2-jazzy, ros2-kilted and ros2-rolling.

### What are the broadcaster packages in ros2_controllers for?

They publish robot state onto the ROS graph, one package per source: joint_state, pose, IMU, GPS, magnetometer, range sensor, force torque sensor, battery state and a generic state interfaces broadcaster. The joint state broadcaster in particular is what MoveIt2, Nav2 and visualisation tools expect to find.

### What are the .repos files in the ros2_controllers repository?

They pin the source repositories for each distribution, with ros2_controllers.rolling.repos, .lyrical, .kilted, .jazzy and .humble files alongside a parallel set of not-released files, plus ros_controls.*.repos for the wider organisation. They exist so a workspace can be reproduced exactly.

### Which ROS 2 controller should I use for a mecanum or omnidirectional chassis?

The repository provides mecanum_drive_controller and omni_wheel_drive_controller alongside the two wheel diff_drive_controller, plus tricycle, bicycle, ackermann and tricycle steering variants and a shared steering_controllers_library.

## Sources

- [Issues](https://github.com/ros-controls/ros2_controllers/issues)
- [License: Apache-2.0](https://github.com/ros-controls/ros2_controllers/blob/master/LICENSE)
- [Project website](https://control.ros.org)
- [README](https://github.com/ros-controls/ros2_controllers/blob/master/README.md)
- [ros-controls/ros2_controllers on GitHub](https://github.com/ros-controls/ros2_controllers)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ros-controls-ros2-controllers
