Skip to content
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

add a semantic command interface to "semantic_components" #1945

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

Conversation

tpoignonec
Copy link

Hi,

Is there any interest in defining a SemanticComponentCommandInterface analogous to the SemanticComponentInterface, but for hardware command interfaces?

Applications could include, among others, commonly used simple write-only devices such as LED, buzzers, beepers, etc.
It could also be used for GPIO arrays the same way the state interface can be used to read them in a standarized fashion.

This PR includes such a semantic component, as well as a basic example with a 3-channel (R/G/B) LED with two scenarios:

  • Default interface names: <name>/r, <name>/g, and <name>/b
  • Custom interface names using the following syntax:
#include "semantic_components/led_rgb_device.hpp"

std::string interface_name_r = "led/custom_r";
std::string interface_name_g = "led/custom_g";
std::string interface_name_b = "led/custom_b";

// Create LED device with custom interface names
auto led_device = std::make_unique<semantic_components::LEDRgbDevice>(
   interface_name_r, interface_name_g, interface_name_b);

Additionally, basic tests are proposed.

Copy link

codecov bot commented Dec 16, 2024

Codecov Report

Attention: Patch coverage is 94.44444% with 6 lines in your changes missing coverage. Please review.

Project coverage is 89.36%. Comparing base (f8c03cc) to head (70ec8dd).

Files with missing lines Patch % Lines
...omponents/semantic_component_command_interface.hpp 80.00% 2 Missing and 3 partials ⚠️
...ace/include/semantic_components/led_rgb_device.hpp 94.44% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1945      +/-   ##
==========================================
+ Coverage   89.35%   89.36%   +0.01%     
==========================================
  Files         130      136       +6     
  Lines       14576    14690     +114     
  Branches     1258     1264       +6     
==========================================
+ Hits        13024    13128     +104     
- Misses       1088     1090       +2     
- Partials      464      472       +8     
Flag Coverage Δ
unittests 89.36% <94.44%> (+0.01%) ⬆️

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

Files with missing lines Coverage Δ
controller_interface/test/test_led_rgb_device.cpp 100.00% <100.00%> (ø)
controller_interface/test/test_led_rgb_device.hpp 100.00% <100.00%> (ø)
...test/test_semantic_component_command_interface.cpp 100.00% <100.00%> (ø)
...test/test_semantic_component_command_interface.hpp 100.00% <100.00%> (ø)
...ace/include/semantic_components/led_rgb_device.hpp 94.44% <94.44%> (ø)
...omponents/semantic_component_command_interface.hpp 80.00% <80.00%> (ø)

... and 6 files with indirect coverage changes

@Wiktor-99
Copy link
Contributor

I've thought about it a little bit, and I'm not sure if we should add such a component when the GPIO command controller, which is very generic, is already available

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 for the PR including nice tests .
We discussed this shortly in todays WG meeting, and approve this addition.
I can understand the input @Wiktor-99, but imho

  • it is an obvious extension of an existing concept
  • it could also use joints and not only gpios

Please add it to the release_notes and some minor comments.

@tpoignonec
Copy link
Author

Great!
I do the release note and changes ASAP.

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.

LGTM overall, I just added some comments to be in line with #1940

Maybe you have to format my suggestions once again to satisfy pre-commit.

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.

Something still seems to be broken with the tests, can you have a look please?

@tpoignonec
Copy link
Author

My bad, hadn't rerun the unit tests after accepting the change suggestions (minor issue with LED constructor).
Should be fine now.

Comment on lines +37 to +42
explicit SemanticComponentCommandInterface(const std::string & name, size_t size = 0)
: name_(name)
{
interface_names_.reserve(size);
command_interfaces_.reserve(size);
}
Copy link
Member

Choose a reason for hiding this comment

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

May be we can remove this Constructor. The first one seems more intuitive

Comment on lines +40 to +52
/**
* Constructor for a LED RGB device with custom interface names.
* The constructor takes the three command interface names for the red, green, and blue channels.
*/
explicit LedRgbDevice(
const std::string & interface_r, const std::string & interface_g,
const std::string & interface_b)
: SemanticComponentCommandInterface("", 3)
{
interface_names_.emplace_back(interface_r);
interface_names_.emplace_back(interface_g);
interface_names_.emplace_back(interface_b);
}
Copy link
Member

Choose a reason for hiding this comment

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

As specified, may be this can be ruled out.

/**
* \return false by default
*/
bool set_values_from_message(const MessageInputType & /* message */) { return false; }
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
bool set_values_from_message(const MessageInputType & /* message */) { return false; }
virtual bool set_values_from_message(const MessageInputType & /* message */) = 0;

Maybe we can make it pure virtual method, so all derived methods will be forced to implement this. What do you think? @christophfroehlich

Comment on lines +73 to +79
if (interface_names_.empty())
{
for (auto i = 0u; i < interface_names_.capacity(); ++i)
{
interface_names_.emplace_back(name_ + "/" + std::to_string(i + 1));
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (interface_names_.empty())
{
for (auto i = 0u; i < interface_names_.capacity(); ++i)
{
interface_names_.emplace_back(name_ + "/" + std::to_string(i + 1));
}
}

If the interfaces are not set, then assign_loaned_command_interfaces should be getting nothing and it wouldn't make sense at all

Copy link
Author

Choose a reason for hiding this comment

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

It was done as to maintain symmetry with the SemanticComponentInterface :

virtual std::vector<std::string> get_state_interface_names()
{
if (interface_names_.empty())
{
for (auto i = 0u; i < interface_names_.capacity(); ++i)
{
interface_names_.emplace_back(name_ + "/" + std::to_string(i + 1));
}
}
return interface_names_;
}

However, it is true that the use case is debatable (in both cases).

Copy link
Member

Choose a reason for hiding this comment

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

Yup, I agree. As this is the new one that we are introducing, it is better to have it the proper way

Copy link
Author

@tpoignonec tpoignonec Jan 16, 2025

Choose a reason for hiding this comment

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

I thought a bit more about it. It is actually (kind of) OK since the assign_loaned_state_interfaces function calls the getter, so interface names are, at the latest, filled at that stage:

bool assign_loaned_state_interfaces(
std::vector<hardware_interface::LoanedStateInterface> & state_interfaces)
{
return controller_interface::get_ordered_interfaces(
state_interfaces, interface_names_, "", state_interfaces_);
}

It's not ideal, but at the same time there is no reason, in theory, to overload the assign_loaned_state_interfaces method.

The alternative would consist in assigning the default names in the constructor, but that might be tricky to manage, since this constructor is meant to be specialized by child classes that will push into the std::vector.
That would mean accessing the interface names by index from the constructor of inherited classes, since the vector would already be filled.

Copy link
Author

@tpoignonec tpoignonec Jan 17, 2025

Choose a reason for hiding this comment

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

@saikishor What about declaring the assign_loaned_state_interfaces and get_ordered_interfaces methods as final?

Copy link

@Raivias Raivias left a comment

Choose a reason for hiding this comment

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

Other than dropping the library LGTM.

…onent_command_interface.hpp

Co-authored-by: Sai Kishor Kothakota <[email protected]>
@saikishor
Copy link
Member

@tpoignonec Can you please fix the pre-commit jobs?

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.

5 participants