Best practices for accessing non-controls information alongside ros2_control

I’m interested in best practices / techniques for providing additional data from a roboclaw serial interface (main battery voltage, temperature, etc) that is currently managed by a ros2 control hardware interface.

ros2_control currently calls roboclaw serial interface during read/write requests. This serial interface provides access to additional data that I would like to also publish to ROS2 (battery levels, current, temp, etc). Ideally, this additional data could be exposed for access by behavior management process, etc, and at a different frequency than the main control loop.

There are a few options:

Option 1: just read and publish the non-controls data during hardware_interface::read calls.
Bad practice, this impacts both separation of concerns, overall readability, and potentially slows down the main control loop

Option 2: Extend hardware_interface’s underlying lifecycle node base class methods (on_activate, etc) for publishing this non-controls data via a timer.
I am not sure how I feel about this, but it seems better than Option 1. Still seems to muddy the water between a specialized controls interface to hardware and other interfaces

Option 3: Independent ROS2 component provides both controls interface (via topics) and publishes additional data
I would like ros2_control to have low-level, direct access to the hardware, so I’m not a fan of this approach either.

What do you all think? Is there a recommend design choice or precedent, probably something I’m not considering?

Hi! For this purpose we use the GPIO interfaces of ros2_control.
The hardware component exports these interfaces, and you can write a simple GPIO controller to publish them, or use the /dynamic_joint_states from the join_state_broadcaster.
https://control.ros.org/rolling/doc/ros2_control_demos/example_10/doc/userdoc.html

Hi! I just implemented something like that for monitoring battery state via state interfaces and publishing it as a BatteryState message, in a hopefully ros2_control idiomatic way. I just pushed it, and want to release it in current ROS 2 distributions in the next few days: ros_battery_monitoring/battery_state_broadcaster at main · ipa320/ros_battery_monitoring · GitHub

Thanks @christophfroehlich and @ottojo for the feedback. I think I had a fundamental misunderstanding about what a hardware interface actually does…

Here’s my understanding of the “best” approach:

  1. Update interface to extract additional state information that I want to make available to controllers
  2. Create a broadcaster/controller to publish this information to ROS

One of my pain points is that I really don’t want to have to read ALL states at the same rate. I.e., maybe I only want to read battery voltage once every 30 seconds. I can of course add some logic to the read() call to handle this, but curious if there are any mechanisms to provide the hardware_interface with needs to be read? I.e., a vector of strings for each state that’s needed (allowing each controller could drive its own rate). Any practical recommendations or things that I’m missing?

This really depends on how you access your data. You wrote that you use the serial interface? This limits you to a single hardware component, because afaik you cannot connect with two processes to the same serial without an additional layer in between. (Otherwise you could write two independent hardware components running on a different update rate).

Within one hardware component, there is no ros2_control-way in doing so. I’d suggest using the time and implement a logic to poll the housekeeping data only once in a while.

1 Like