-
Notifications
You must be signed in to change notification settings - Fork 386
[HardwareComponentInterface] Add get state and command interface handle methods #2831
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?
[HardwareComponentInterface] Add get state and command interface handle methods #2831
Conversation
81b73e1 to
3472e37
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2831 +/- ##
==========================================
- Coverage 89.55% 89.40% -0.16%
==========================================
Files 152 152
Lines 18087 18126 +39
Branches 1470 1474 +4
==========================================
+ Hits 16198 16205 +7
- Misses 1301 1329 +28
- Partials 588 592 +4
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
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.
You suggest storing the interface handles once inside the hardware components, instead of having to lookup the maps at every set/get call?
Yes, this way the users will be able to cache the command interfaces and will be able to implement the logic they want. I think this way we have less execution time, so you might not need to do a lookup everytime. |
|
However, I'm rethinking some part of API right now. I'll update with more API |
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.
The API seems to be very useful from the user perspective, but I'm not sure about the compiler optimization I commented below..
hardware_interface/include/hardware_interface/hardware_component_interface.hpp
Show resolved
Hide resolved
|
Thanks @saikishor! This should address #2816 |
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.
Pull Request Overview
This PR enhances the HardwareComponentInterface by adding methods to retrieve state and command interface handles, along with overloaded getter/setter methods that accept handles directly. These additions enable caching of interface handles to improve performance by avoiding repeated map lookups during interface access operations.
Key Changes:
- Added
get_state_interface_handle()andget_command_interface_handle()methods to retrieve interface handles by name - Introduced overloaded
get_state(),set_state(),get_command(), andset_command()methods that accept interface handles directly - Added
get_value()methods in theHandleclass that use output parameters instead of return values for better performance with large data types
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| hardware_interface/include/hardware_interface/hardware_component_interface.hpp | Added handle retrieval methods and handle-based getter/setter overloads with ensure_get/ensure_set parameters for state and command interfaces |
| hardware_interface/include/hardware_interface/handle.hpp | Added get_value() methods with output parameters to support thread-safe value retrieval without copying return values |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @param lock The lock to access the value. | ||
| * @param value The variable to store the retrieved value. | ||
| * @return true if the value is retrieved successfully, false otherwise. | ||
| * @note The method is thread-safe and non-blocking. |
Copilot
AI
Nov 19, 2025
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.
The documentation states the method is 'non-blocking', but the method uses std::shared_lock which can block if a writer holds the mutex. Consider clarifying this as 'non-blocking only if the lock is successfully acquired' or removing the non-blocking claim.
| * @note The method is thread-safe and non-blocking. | |
| * @note The method is thread-safe and non-blocking only if the lock is already acquired. | |
| * Acquiring the lock itself may block if a writer holds the mutex. |
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.
Why do we expose this method in the interface? I would make it protected. The Handle should be a thread save entity in my point of view and locking/unlocking should be handled internally. I think exposing of bool get_value(T & value) const should be enough or am i missing something?
And am i mistaken or is the function actually thradunsafe because if you create mutex_2 lock it with some std::shared_lock<std::shared_mutex> lock2(handle_mutex_, std::try_to_lock); and pass it i would break thread safety or not?
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.
Why not, this is useful to avoid the copies and then you want to do it in a thread safe approach right?. Moreover, it has similar schema as set_value method
And am i mistaken or is the function actually thradunsafe because if you create mutex_2 lock it with some std::shared_lockstd::shared_mutex lock2(handle_mutex_, std::try_to_lock); and pass it i would break thread safety or not?
If you do that and if it doesn't own the lock, it would enter the condition !lock.owns_lock() immediately and then returns
| * @tparam T The type of the value to be retrieved. | ||
| * @param value The variable to store the retrieved value. | ||
| * @return true if the value is retrieved successfully, false otherwise. | ||
| * @note The method is thread-safe and non-blocking. |
Copilot
AI
Nov 19, 2025
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.
The documentation incorrectly states the method is 'non-blocking'. The method uses std::try_to_lock which makes it non-blocking in terms of lock acquisition, but it returns false if the lock cannot be acquired rather than guaranteeing non-blocking behavior. The documentation should clarify that the method attempts to acquire the lock without blocking and returns false if unsuccessful.
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.
Come onnnnn copilot 😅😅
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 has a point in being more specific what "retrieved successfully" means?
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 don't think so. Atleast, I wrote it as per my understanding
hardware_interface/include/hardware_interface/hardware_component_interface.hpp
Outdated
Show resolved
Hide resolved
hardware_interface/include/hardware_interface/hardware_component_interface.hpp
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <[email protected]>
| * @param lock The lock to access the value. | ||
| * @param value The variable to store the retrieved value. | ||
| * @return true if the value is retrieved successfully, false otherwise. | ||
| * @note The method is thread-safe and non-blocking. |
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.
Why do we expose this method in the interface? I would make it protected. The Handle should be a thread save entity in my point of view and locking/unlocking should be handled internally. I think exposing of bool get_value(T & value) const should be enough or am i missing something?
And am i mistaken or is the function actually thradunsafe because if you create mutex_2 lock it with some std::shared_lock<std::shared_mutex> lock2(handle_mutex_, std::try_to_lock); and pass it i would break thread safety or not?
hardware_interface/include/hardware_interface/hardware_component_interface.hpp
Show resolved
Hide resolved
| } | ||
| if (ensure_set) | ||
| { | ||
| std::unique_lock<std::shared_mutex> lock(interface_handle->get_mutex()); |
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 think id rather move this to the handle. have a blocking and a non blocking method where the blocking grantees to set the value and the non blocking is the current.
Then in the user code we can just directly call the Shared pointer instance and call either the blocking or non blocking method
| */ | ||
| template <typename T> | ||
| void set_state(const std::string & interface_name, const T & value) | ||
| void set_state(const std::string & interface_name, const T & value, bool ensure_set = true) |
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 know it is written in the comment but i think ensure_set masks a bit the fact that we now have a different api.
I would maybe just distinguish on api level
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.
creating different API is sometimes confusing for beginners, better to have one API and add proper documentation for the users to understand. With VSCode, you can understand the args while coding from the docs
| * \return True if the value was retrieved successfully, false otherwise. | ||
| */ | ||
| template <typename T> | ||
| bool get_state( |
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.
For get_state basically the same reasoning applies as for set_state
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 modified a bit
This PR adds a few new methods that could be really helpful if we want to catch the information of the exported interfaces to improve the performance of the setting and getting of handles