-
Notifications
You must be signed in to change notification settings - Fork 438
Add VDA5050 Safety State Broadcaster #1958
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
base: master
Are you sure you want to change the base?
Add VDA5050 Safety State Broadcaster #1958
Conversation
christophfroehlich
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First (very superficially) review
vda5050_safety_state_broadcaster/test/vda5050_safety_state_broadcaster_params.yaml
Show resolved
Hide resolved
50ca35f to
317e7ea
Compare
Co-authored-by: Christoph Fröhlich <[email protected]>
christophfroehlich
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI fails because of the API breaking changes of the realtime_publisher.
I have a general question, shouldn't we use data_type bool for state_interfaces here? Or at least support both?
...te_broadcaster/include/vda5050_safety_state_broadcaster/vda5050_safety_state_broadcaster.hpp
Outdated
Show resolved
Hide resolved
| /** | ||
| * @brief Safely converts a double value to bool, treating NaN as false. | ||
| * @param value The double value to convert. | ||
| * @return true if value is not NaN and not zero, false otherwise. | ||
| */ | ||
| bool safe_double_to_bool(double value) const | ||
| { | ||
| if (std::isnan(value)) | ||
| { | ||
| return false; | ||
| } | ||
| return value != 0.0; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we stay with double values, should we place this somewhere else? controller_interface/helpers for example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, I would rather use the logic to support boolean interfaces too based on the get_data_type method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added bool support with the get_data_type method as @saikishor recommended.
I’ve kept safe_double_to_bool for now because it's still necessary to handle NaN cases and the conversion logic for existing double-based interfaces. Regarding moving it to controller_interface/helpers: I agree it could be a useful utility for other broadcasters. I’m happy to move it there (or to a common header) if you think it's generic enough for the wider framework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saikishor where would this fit best?
Co-authored-by: Christoph Fröhlich <[email protected]>
Co-authored-by: Christoph Fröhlich <[email protected]>
Co-authored-by: Christoph Fröhlich <[email protected]>
…broadcaster/vda5050_safety_state_broadcaster.hpp Co-authored-by: Christoph Fröhlich <[email protected]>
saikishor
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looking pretty good. Some nitpicks
| fieldViolation_interfaces: { | ||
| type: string_array, | ||
| default_value: [], | ||
| description: "names of interfaces that are used to acknowledge field violation events by setting the interface to 1.0.", | ||
| } | ||
| eStop_manual_interfaces: { | ||
| type: string_array, | ||
| default_value: [], | ||
| description: "names of interfaces that are used to manually acknowledge eStop events by setting the interface to 1.0.", | ||
| } | ||
| eStop_remote_interfaces: { | ||
| type: string_array, | ||
| default_value: [], | ||
| description: "names of interfaces that are used to remotely acknowledge eStop events by setting the interface to 1.0.", | ||
| } | ||
| eStop_autoack_interfaces: { | ||
| type: string_array, | ||
| default_value: [], | ||
| description: "names of interfaces that are used to autoacknowledge eStop events by setting the interface to 1.0.", | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's place then under the namesapce interfaces or eStop_Interfaces or emergency_stop_interfaces and remove the interfaces prefixes in the naming
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved the three E-Stop types under a nested eStop_interfaces namespace (e.g., eStop_interfaces.manual, eStop_interfaces.remote, etc.) and removed the repetitive prefixes.
I’ve kept fieldViolation_interfaces at the top level because it is logically distinct from the Emergency Stop handling in the VDA5050 specification. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Thanks for the change. Regarding your comment, does it make sense like interfaces.fieldViolation and then interfaces.eStop.* ?
What do you think?. Just throwing an idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Thanks for the change. Regarding your comment, does it make sense like interfaces.fieldViolation and then interfaces.eStop.* ?
What do you think?. Just throwing an idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I'm not a big fan of deep nesting because it makes the C++ access verbose, but I agree that grouping them under a unified interfaces namespace looks much cleaner in the YAML. I've implemented it as interfaces.field_violation and interfaces.e_stop.*. Thanks for the suggestion!
| /** | ||
| * @brief Safely converts a double value to bool, treating NaN as false. | ||
| * @param value The double value to convert. | ||
| * @return true if value is not NaN and not zero, false otherwise. | ||
| */ | ||
| bool safe_double_to_bool(double value) const | ||
| { | ||
| if (std::isnan(value)) | ||
| { | ||
| return false; | ||
| } | ||
| return value != 0.0; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, I would rather use the logic to support boolean interfaces too based on the get_data_type method
vda5050_safety_state_broadcaster/src/vda5050_safety_state_broadcaster.cpp
Outdated
Show resolved
Hide resolved
| if (safe_double_to_bool( | ||
| state_interfaces_[itf_idx].get_optional().value_or(kUninitializedValue))) | ||
| { | ||
| fieldViolation_value = true; | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to also support boolean interfaces here based on the type you get from get_data_type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
vda5050_safety_state_broadcaster/src/vda5050_safety_state_broadcaster.cpp
Outdated
Show resolved
Hide resolved
I updated the APIs for realtime_publisher and LoanedStateInterface. I ran the tests locally on jazzy and rolling.
Yes, thanks @christophfroehlich for the suggestion. I added bool support with the |
Co-authored-by: Sai Kishor Kothakota <[email protected]>
Co-authored-by: Sai Kishor Kothakota <[email protected]>
Co-authored-by: Sai Kishor Kothakota <[email protected]>
Co-authored-by: Sai Kishor Kothakota <[email protected]>
|
Thank you @YaraShahin . I'll take a look. |
…dcaster.cpp Co-authored-by: Sai Kishor Kothakota <[email protected]>
christophfroehlich
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates. Some comments in the code, and please consider failing tests, like that from clang
/home/runner/work/ros2_controllers/ros2_controllers/.work/target_ws/src/ros2_controllers/vda5050_safety_state_broadcaster/src/vda5050_safety_state_broadcaster.cpp:211:27: error: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Werror,-Wsign-conversion]
211 | state_interfaces_[itf_idx].get_name().c_str());
| ~~~~~~~~~~~~~~~~~ ^~~~~~~
| std::shared_ptr<vda5050_safety_state_broadcaster::ParamListener> param_listener_; | ||
| std::shared_ptr<rclcpp::Publisher<control_msgs::msg::VDA5050SafetyState>> | ||
| vda5050_safety_state_publisher_; | ||
| control_msgs::msg::VDA5050SafetyState safety_state_msg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick, but we typically mark member variables as such
| control_msgs::msg::VDA5050SafetyState safety_state_msg; | |
| control_msgs::msg::VDA5050SafetyState safety_state_msg_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. I did the change in the latest commit along with the necessary corresponding changes in cpp.
| /** | ||
| * @brief Safely converts a double value to bool, treating NaN as false. | ||
| * @param value The double value to convert. | ||
| * @return true if value is not NaN and not zero, false otherwise. | ||
| */ | ||
| bool safe_double_to_bool(double value) const | ||
| { | ||
| if (std::isnan(value)) | ||
| { | ||
| return false; | ||
| } | ||
| return value != 0.0; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saikishor where would this fit best?
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #1958 +/- ##
==========================================
+ Coverage 84.79% 84.88% +0.08%
==========================================
Files 151 156 +5
Lines 14607 14822 +215
Branches 1266 1285 +19
==========================================
+ Hits 12386 12581 +195
- Misses 1763 1777 +14
- Partials 458 464 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
This Pull Request introduces the VDA5050 Safety State Broadcaster, a controller for publishing safety state information in ROS 2. The broadcaster reads safety-related state interfaces from hardware and exposes them in standardized ROS messages, as defined by the VDA5050 standard, for easy integration with VDA5050-based fleet management systems, safety monitoring, and higher-level decision-making nodes.
Dependency: This PR depends on control_msgs#266 which introduces the
VDA5050SafetyStatemessage.Features
Standardized Safety Output: Publishes a
control_msgs::msg::VDA5050SafetyStatemessage representing the current safety state of the system: field violation and E-stop status.Flexible Interface Support: Reads from configurable state interfaces covering field violation, manual E-stop, remote E-stop, and auto-acknowledged E-stop, ensuring full compatibility with the VDA5050 schema.
Parameterization: Fully configurable through YAML using generate_parameter_library.
Published Topic
~/vda5050_safety_state(control_msgs::msg::VDA5050SafetyState) — publishes the combined safety state: field violation and prioritized E-stop status.Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
To send us a pull request, please:
colcon testandpre-commit run(requires you to install pre-commit bypip3 install pre-commit)