Skip to content

Add missing controller async parameter declarations - #3481

Open
Nibanovic wants to merge 3 commits into
ros-controls:masterfrom
b-robotized-forks:fix/async-controller-param-declaration
Open

Add missing controller async parameter declarations#3481
Nibanovic wants to merge 3 commits into
ros-controls:masterfrom
b-robotized-forks:fix/async-controller-param-declaration

Conversation

@Nibanovic

Copy link
Copy Markdown
Contributor

Description

Setting async_parameters key in controller config does not apply cpu_affinity or thread_priority config, as per the documentation

This config:

example_controller:
  ros__parameters:
      type: joint_trajectory_controller/JointTrajectoryController
      is_async: true
      async_parameters:
        scheduling_policy: detached
        thread_priority: 70
        cpu_affinity: [2, 3]

Results in these logs:

[INFO] [1784294876.480348261] [controller_manager]: Configuring controller: 'example_controller'
[INFO] [1784294876.480486086] [example_controller]: Starting async handler with scheduler priority: 50   # <-- this is default!
[INFO] [1784294876.480659950] [example_controller]: No specific joint names are used for command interfaces. Using 'joints' parameter.

When this is expected:

[INFO] [1784294876.480348261] [controller_manager]: Configuring controller: 'example_controller'
[INFO] [1784294876.480486086] [example_controller]: Starting async handler with scheduler priority: 70
[INFO] [1784294876.480659950] [example_controller]: No specific joint names are used for command interfaces. Using 'joints' parameter.
[WARN] [1784294876.480661020] [AsyncFunctionHandler]: Async worker thread is successfully pinned to the requested CPU cores! 

Solution:

Declare the parameters in question automatically, here

Not sure why this is not declared automatically. Probably at some point rclcpp does not automatically declare parameters set for nodes, so these configs get ignored.

And no one seemed to be pinning async controllers to any of the cores 😄

Is this user-facing behavior change?

yep, now when you put the parameters described in the docs, they actually get applied.

Did you use Generative AI?

Nah

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.54%. Comparing base (e4ebcc3) to head (2014c57).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3481      +/-   ##
==========================================
+ Coverage   89.51%   89.54%   +0.02%     
==========================================
  Files         164      164              
  Lines       21270    21275       +5     
  Branches     1656     1659       +3     
==========================================
+ Hits        19040    19050      +10     
+ Misses       1530     1527       -3     
+ Partials      700      698       -2     
Flag Coverage Δ
unittests 89.54% <100.00%> (+0.02%) ⬆️

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

Files with missing lines Coverage Δ
...roller_interface/src/controller_interface_base.cpp 85.35% <100.00%> (+0.45%) ⬆️

... and 2 files with indirect coverage changes

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

Comment thread controller_interface/src/controller_interface_base.cpp Outdated
Comment on lines +103 to +109

auto_declare<int>("async_parameters.thread_priority", 50);
auto_declare<std::string>("async_parameters.scheduling_policy", "synchronized");
auto_declare<std::vector<int64_t>>("async_parameters.cpu_affinity", std::vector<int64_t>());
auto_declare<int>("async_parameters.execution_rate", impl_->ctrl_itf_params_.update_rate);
auto_declare<bool>("async_parameters.wait_until_initial_trigger", true);
auto_declare<bool>("async_parameters.print_warnings", true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe, it is wiser to add declare_parameters method to the asyncParams and then handle it in the realtime_tools, this way any new parameter need not be reflected again and again here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah, that is a good catch. Added a commit for this

@Nibanovic

Copy link
Copy Markdown
Contributor Author

As per this comment, moved parameter declaraion to realtime_tools/async_function_handler_params.hpp

To sum up, this is the merging order:

  1. declare missing Async parameters realtime_tools#556, to declare the parameters
  2. This MR to call the declaration function from controller_interface_base.cpp
  3. finally, Add thread renaming for components #3482, to parameterize renaming of threads

Nice to have, on this topic:

Printing CPU cores we pin threads on PR: ros-controls/realtime_tools#551

Comment thread controller_interface/src/controller_interface_base.cpp Outdated
Comment on lines +103 to +104
realtime_tools::AsyncFunctionHandlerParams::declare(
impl_->node_, "async_parameters.", impl_->ctrl_itf_params_.update_rate);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not use async_params_.declare?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I figured the parameters are a property of the node that declares them, and this should only be a utility function. Also for loading parameters from yaml.

So it goes something like this:

  1. in init, node is just being created, so we declare the parameters. There is no async_params_ member yet.
  2. after init, parameters are loaded from yaml file
  3. then in configure(), the parameters are read and stored in async_params_.

that is why declare() is a static function, and not tied to the async_params_ instance. The instance does not even exist in init, so we might miss param setting from yaml.

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.

3 participants