Skip to content

Added Swerve Drive Controller Package #1694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: master
Choose a base branch
from

Conversation

nitin2606
Copy link
Contributor

Description
This PR introduces the swerve_drive_controller, a new controller for swerve drive robots with four independently steerable wheels, enabling omnidirectional motion in ROS 2. It complements controllers like diff_drive_controller by supporting advanced mobile robot platforms.

Features

Supports geometry_msgs/msg/Twist or TwistStamped velocity inputs (x, y linear; z angular).
Publishes raw nav_msgs/msg/Odometry for user-defined post-processing.
Publishes /tf transforms (optional, if enable_odom_tf=true).
Configurable via YAML for wheel geometry and kinematic constraints.
Changes
Added swerve_drive_controller package (src/, include/, test/).
Exported as a pluginlib plugin (swerve_drive_controller_plugin.xml).
Updated ros2_controllers CMakeLists.txt and package.xml.
Included gtest tests (test/test_swerve_drive_controller.cpp) and config (test/config/test_swerve_drive_controller.yaml).

Copy link
Contributor

@christophfroehlich christophfroehlich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for your contribution. Could you please fix the failing tests? A very quick first review below.

Do you mind add a brief section in the kinematics section of the docs, even in a new PR to get it merged faster? Thanks!

@nitin2606
Copy link
Contributor Author

I'll make changes and push.

@christophfroehlich
Copy link
Contributor

do you mind cherry-picking the changes to the docs in a separate PR? Splitting this up would help to reviewing things.

@nitin2606
Copy link
Contributor Author

do you mind cherry-picking the changes to the docs in a separate PR? Splitting this up would help to reviewing things.

I have raised a separate PR for changes in docs. PR #1712

Copy link
Member

@Maverobot Maverobot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi there, thanks for your contribution! I've started reviewing the changes and have left a few comments. I will try to find time to work through it and will follow up once I'm done.

Copy link
Contributor

mergify bot commented Jun 24, 2025

This pull request is in conflict. Could you fix it @nitin2606?

Copy link
Contributor

mergify bot commented Jul 22, 2025

This pull request is in conflict. Could you fix it @nitin2606?

Copy link

codecov bot commented Jul 22, 2025

Codecov Report

❌ Patch coverage is 18.28299% with 514 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.89%. Comparing base (a01fd0b) to head (71dd2bc).

Files with missing lines Patch % Lines
...e_drive_controller/src/swerve_drive_controller.cpp 4.07% 305 Missing and 1 partial ⚠️
...e_controller/test/test_swerve_drive_controller.cpp 33.59% 154 Missing and 16 partials ⚠️
...e_drive_controller/src/swerve_drive_kinematics.cpp 7.31% 38 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1694      +/-   ##
==========================================
- Coverage   85.98%   82.89%   -3.10%     
==========================================
  Files         129      134       +5     
  Lines       13112    13740     +628     
  Branches     1144     1216      +72     
==========================================
+ Hits        11275    11390     +115     
- Misses       1469     1966     +497     
- Partials      368      384      +16     
Flag Coverage Δ
unittests 82.89% <18.28%> (-3.10%) ⬇️

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

Files with missing lines Coverage Δ
...werve_drive_controller/swerve_drive_controller.hpp 100.00% <100.00%> (ø)
...troller/test/test_load_swerve_drive_controller.cpp 100.00% <100.00%> (ø)
...e_drive_controller/src/swerve_drive_kinematics.cpp 7.31% <7.31%> (ø)
...e_controller/test/test_swerve_drive_controller.cpp 33.59% <33.59%> (ø)
...e_drive_controller/src/swerve_drive_controller.cpp 4.07% <4.07%> (ø)

... and 1 file with indirect coverage changes

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

Copy link
Contributor

@Amronos Amronos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have done a rough review right now and haven't gone through the main source code properly.
Aside from my other review comments, I noticed the following:

  1. You have the GPL parameters yaml, but aren't using GPL properly anywhere in your source code.
  2. Why not make this controller a chained controller?
  3. Are you using the new APIs here? (Look at #1566 and #1830)

Copy link
Contributor

@Amronos Amronos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add my suggestions to batch on the files changed tab and commit from there. This will make it easier to review.

@nitin2606 nitin2606 requested a review from Amronos July 28, 2025 09:38
@nitin2606
Copy link
Contributor Author

@Amronos @christophfroehlich Could you please review when you get a chance?

Copy link
Contributor

@christophfroehlich christophfroehlich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To emphasize the last commit above: Please either use the github UI to accept proposed changes, or leave the conversations open so that the reviewing person can immediately check if they have been addressed or a new comment was added. Only the reviewer should manually close the conversations. This improves effectivity of the next review round.

Please fix the failing linter jobs: Install pre-commit via pre-commit install for the next commits; the current issues can be fixed with pre-commit run --all from the repo.

@nitin2606
Copy link
Contributor Author

To emphasize the last commit above: Please either use the github UI to accept proposed changes, or leave the conversations open so that the reviewing person can immediately check if they have been addressed or a new comment was added. Only the reviewer should manually close the conversations. This improves effectivity of the next review round.

Please fix the failing linter jobs: Install pre-commit via pre-commit install for the next commits; the current issues can be fixed with pre-commit run --all from the repo.

I have attempted to resolve the linter issues, but I am still encountering a persistent error reported by the pre-commit check at line 152 of the file: https://github.com/nitin2606/ros2_controllers/blob/feature/swerve-drive-controller/swerve_drive_controller/test/test_swerve_drive_controller.cpp
Could you kindly review it and help me identify the underlying issue?

Copy link
Contributor

@christophfroehlich christophfroehlich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A first review round, haven't gone over the kinematics implementation yet.

Comment on lines +166 to +169
if (!init_successful_)
{
GTEST_SKIP() << "Skipping due to on_init failure";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use gmock in our projects, please use a pattern like this

Suggested change
if (!init_successful_)
{
GTEST_SKIP() << "Skipping due to on_init failure";
}
ASSERT_TRUE(init_successful_) << "Skipping due to on_init failure";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it I'll make necessary changes


int main(int argc, char ** argv)
{
::testing::InitGoogleTest(&argc, argv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
::testing::InitGoogleTest(&argc, argv);
::testing::InitGoogleMock(&argc, argv);

odometry_message.pose.pose.orientation.y = orientation.y();
odometry_message.pose.pose.orientation.z = orientation.z();
odometry_message.pose.pose.orientation.w = orientation.w();
realtime_odometry_publisher_->unlockAndPublish();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the publisher API like in #1830

auto node = get_node();
if (!node)
{
RCLCPP_ERROR(rclcpp::get_logger("SwerveController"), "Node is null in on_init");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you always creating a new logger? Please use

Suggested change
RCLCPP_ERROR(rclcpp::get_logger("SwerveController"), "Node is null in on_init");
RCLCPP_ERROR(node->get_logger(), "Node is null in on_init");

instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applies to all occurrences

Comment on lines +608 to +611
static_assert(
!std::is_const_v<std::remove_reference_t<decltype(*command_handle)>>,
"Command handle is const!");
return std::make_unique<T>(std::ref(*command_handle), std::ref(*state_handle), name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please elaborate why you used this pattern? When should this ever be constant?
In other controllers, we use std::reference_wrapper instead of a unique ptr

std::reference_wrapper<hardware_interface::LoanedCommandInterface> velocity;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this change was suggested by one of the reviewers.

Comment on lines +114 to +119
publishe_rate: {
type: double,
default_value: 50.0, # Hz
description: "Publishing rate (Hz) of the odometry and TF messages.",
read_only: true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the publish rate. We decided to remove this from all controllers, they should publish with the update rate of the controller.
#473

return odometry_;
}

double SwerveDriveKinematics::normalize_angle(double angle)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use angles::normalize_angle from angles/angles.h instead of adding a new method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make all the mentioned changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a controller for afour wheel independent steering / drive mobile base, aka a swerve drive
5 participants