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 interface for warning, error and report #20

Draft
wants to merge 28 commits into
base: change_interface_export_variant
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a94d670
move creation of stateinterfaces to systeminterface
mamueluth Dec 7, 2023
c6002b8
store description in state_interface and provide functions for
mamueluth Dec 8, 2023
bb33010
return correct name for InterfaceDescription
mamueluth Dec 11, 2023
d32972c
move parsing of interface description to component parser
mamueluth Dec 11, 2023
bda8f5d
adjusted actuator- and sensor_interface as well
mamueluth Dec 12, 2023
30f9a24
add first tests
mamueluth Dec 18, 2023
bbdc3ca
adjust sensor_interface getting/setting and add tests
mamueluth Dec 18, 2023
8189306
add more tests
mamueluth Dec 18, 2023
64b5c6b
first steps towards variants and storing of value in handle, missing:
mamueluth Dec 19, 2023
e36f48b
add variant support
mamueluth Dec 19, 2023
ee81291
adjusted resource manager to work with shared_ptr adapt actuator,sensor
mamueluth Dec 20, 2023
54a86ca
cleanup
mamueluth Dec 20, 2023
c645b37
fix failing tests
mamueluth Dec 20, 2023
bcf9cf2
change rest of component_interface test and mark what should be removed
mamueluth Dec 21, 2023
7224ef8
code review suggestions and:
mamueluth Jan 23, 2024
c5e7430
undo prefix_ -> prefix (HWInfo) and Command-/StateIntefaceSharedPtr
mamueluth Jan 26, 2024
3f55818
merge parser functions
mamueluth Jan 26, 2024
d4d423a
export_interfaces_2() virtual for custom interface export
mamueluth Jan 29, 2024
da354d8
use unordered map and adjust tests
mamueluth Jan 29, 2024
da326fd
make states and commands of component interfaces private
mamueluth Feb 1, 2024
c5001ea
add migration guide for
mamueluth Apr 10, 2024
c98a1c4
update writing a hardware component
mamueluth Apr 11, 2024
3d0b364
Fix RST syntax and some typos (#18)
christophfroehlich Apr 18, 2024
9710a4c
add changes for chainable controllers (epxport of rerference interfaces)
mamueluth Apr 22, 2024
33710bb
rename export_state/command_interface_2 to export_state/commad_interf…
mamueluth May 22, 2024
726870c
adapt to new changes and remove some rebase artefacts
mamueluth Jul 25, 2024
265f66d
fix test failures
mamueluth Jul 26, 2024
2f45ebf
add interface for warning, error and report
mamueluth Jan 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
#ifndef CONTROLLER_INTERFACE__CHAINABLE_CONTROLLER_INTERFACE_HPP_
#define CONTROLLER_INTERFACE__CHAINABLE_CONTROLLER_INTERFACE_HPP_

#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "controller_interface/controller_interface_base.hpp"
Expand Down Expand Up @@ -57,10 +59,11 @@ class ChainableControllerInterface : public ControllerInterfaceBase
bool is_chainable() const final;

CONTROLLER_INTERFACE_PUBLIC
std::vector<hardware_interface::StateInterface> export_state_interfaces() final;
std::vector<std::shared_ptr<hardware_interface::StateInterface>> export_state_interfaces() final;

CONTROLLER_INTERFACE_PUBLIC
std::vector<hardware_interface::CommandInterface> export_reference_interfaces() final;
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> export_reference_interfaces()
final;

CONTROLLER_INTERFACE_PUBLIC
bool set_chained_mode(bool chained_mode) final;
Expand Down Expand Up @@ -135,7 +138,11 @@ class ChainableControllerInterface : public ControllerInterfaceBase

/// Storage of values for reference interfaces
std::vector<std::string> exported_reference_interface_names_;
// BEGIN (Handle export change): for backward compatibility
std::vector<double> reference_interfaces_;
// END
std::unordered_map<std::string, std::shared_ptr<hardware_interface::CommandInterface>>
reference_interfaces_ptrs_;

private:
/// A flag marking if a chainable controller is currently preceded by another controller.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,16 @@ class ControllerInterface : public controller_interface::ControllerInterfaceBase
* \returns empty list.
*/
CONTROLLER_INTERFACE_PUBLIC
std::vector<hardware_interface::StateInterface> export_state_interfaces() final;
std::vector<std::shared_ptr<hardware_interface::StateInterface>> export_state_interfaces() final;

/**
* Controller has no reference interfaces.
*
* \returns empty list.
*/
CONTROLLER_INTERFACE_PUBLIC
std::vector<hardware_interface::CommandInterface> export_reference_interfaces() final;
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> export_reference_interfaces()
final;

/**
* Controller is not chainable, therefore no chained mode can be set.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
* \returns list of command interfaces for preceding controllers.
*/
CONTROLLER_INTERFACE_PUBLIC
virtual std::vector<hardware_interface::CommandInterface> export_reference_interfaces() = 0;
virtual std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
export_reference_interfaces() = 0;

/**
* Export interfaces for a chainable controller that can be used as state interface by other
Expand All @@ -230,7 +231,8 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
* \returns list of state interfaces for preceding controllers.
*/
CONTROLLER_INTERFACE_PUBLIC
virtual std::vector<hardware_interface::StateInterface> export_state_interfaces() = 0;
virtual std::vector<std::shared_ptr<hardware_interface::StateInterface>>
export_state_interfaces() = 0;

/**
* Set chained mode of a chainable controller. This method triggers internal processes to switch
Expand Down
88 changes: 63 additions & 25 deletions controller_interface/src/chainable_controller_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,53 +44,91 @@ return_type ChainableControllerInterface::update(
return ret;
}

std::vector<hardware_interface::StateInterface>
std::vector<std::shared_ptr<hardware_interface::StateInterface>>
ChainableControllerInterface::export_state_interfaces()
{
auto state_interfaces = on_export_state_interfaces();
std::vector<std::shared_ptr<hardware_interface::StateInterface>> state_interfaces_ptrs_vec;
state_interfaces_ptrs_vec.reserve(state_interfaces.size());

// check if the names of the controller state interfaces begin with the controller's name
for (const auto & interface : state_interfaces)
for (auto & interface : state_interfaces)
{
if (interface.get_prefix_name() != get_node()->get_name())
{
RCLCPP_FATAL(
get_node()->get_logger(),
"The name of the interface '%s' does not begin with the controller's name. This is "
"mandatory for state interfaces. No state interface will be exported. Please "
"correct and recompile the controller with name '%s' and try again.",
interface.get_name().c_str(), get_node()->get_name());
state_interfaces.clear();
break;
std::string error_msg =
"The prefix of the interface '" + interface.get_prefix_name() +
"' does not equal the controller's name '" + get_node()->get_name() +
"'. This is mandatory for state interfaces. No state interface will be exported. Please "
"correct and recompile the controller with name '" +
get_node()->get_name() + "' and try again.";
throw std::runtime_error(error_msg);
}

state_interfaces_ptrs_vec.push_back(
std::make_shared<hardware_interface::StateInterface>(interface));
}

return state_interfaces;
return state_interfaces_ptrs_vec;
}

std::vector<hardware_interface::CommandInterface>
std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
ChainableControllerInterface::export_reference_interfaces()
{
auto reference_interfaces = on_export_reference_interfaces();
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> reference_interfaces_ptrs_vec;
reference_interfaces_ptrs_vec.reserve(reference_interfaces.size());

// BEGIN (Handle export change): for backward compatibility
// check if the "reference_interfaces_" variable is resized to number of interfaces
if (reference_interfaces_.size() != reference_interfaces.size())
{
// TODO(destogl): Should here be "FATAL"? It is fatal in terms of controller but not for the
// framework
std::string error_msg =
"The internal storage for reference values 'reference_interfaces_' variable has size '" +
std::to_string(reference_interfaces_.size()) + "', but it is expected to have the size '" +
std::to_string(reference_interfaces.size()) +
"' equal to the number of exported reference interfaces. Please correct and recompile the "
"controller with name '" +
get_node()->get_name() + "' and try again.";
throw std::runtime_error(error_msg);
}
// END

// check if the names of the reference interfaces begin with the controller's name
for (const auto & interface : reference_interfaces)
const auto ref_interface_size = reference_interfaces.size();
for (auto & interface : reference_interfaces)
{
if (interface.get_prefix_name() != get_node()->get_name())
{
RCLCPP_FATAL(
get_node()->get_logger(),
"The name of the interface '%s' does not begin with the controller's name. This is "
"mandatory "
" for reference interfaces. No reference interface will be exported. Please correct and "
"recompile the controller with name '%s' and try again.",
interface.get_name().c_str(), get_node()->get_name());
reference_interfaces.clear();
break;
std::string error_msg = "The name of the interface " + interface.get_name() +
" does not begin with the controller's name. This is mandatory for "
"reference interfaces. Please "
"correct and recompile the controller with name " +
get_node()->get_name() + " and try again.";
throw std::runtime_error(error_msg);
}

std::shared_ptr<hardware_interface::CommandInterface> interface_ptr =
std::make_shared<hardware_interface::CommandInterface>(std::move(interface));
reference_interfaces_ptrs_vec.push_back(interface_ptr);
reference_interfaces_ptrs_.insert(std::make_pair(interface_ptr->get_name(), interface_ptr));
}

return reference_interfaces;
if (reference_interfaces_ptrs_.size() != ref_interface_size)
{
std::string error_msg =
"The internal storage for reference ptrs 'reference_interfaces_ptrs_' variable has size '" +
std::to_string(reference_interfaces_ptrs_.size()) +
"', but it is expected to have the size '" + std::to_string(ref_interface_size) +
"' equal to the number of exported reference interfaces. Please correct and recompile the "
"controller with name '" +
get_node()->get_name() + "' and try again.";
throw std::runtime_error(error_msg);
}

return reference_interfaces_ptrs_vec;
}

bool ChainableControllerInterface::set_chained_mode(bool chained_mode)
Expand Down Expand Up @@ -129,8 +167,8 @@ ChainableControllerInterface::on_export_state_interfaces()
std::vector<hardware_interface::StateInterface> state_interfaces;
for (size_t i = 0; i < exported_state_interface_names_.size(); ++i)
{
state_interfaces.emplace_back(hardware_interface::StateInterface(
get_node()->get_name(), exported_state_interface_names_[i], &state_interfaces_values_[i]));
state_interfaces.emplace_back(
get_node()->get_name(), exported_state_interface_names_[i], &state_interfaces_values_[i]);
}
return state_interfaces;
}
Expand Down
6 changes: 4 additions & 2 deletions controller_interface/src/controller_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ ControllerInterface::ControllerInterface() : ControllerInterfaceBase() {}

bool ControllerInterface::is_chainable() const { return false; }

std::vector<hardware_interface::StateInterface> ControllerInterface::export_state_interfaces()
std::vector<std::shared_ptr<hardware_interface::StateInterface>>
ControllerInterface::export_state_interfaces()
{
return {};
}

std::vector<hardware_interface::CommandInterface> ControllerInterface::export_reference_interfaces()
std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
ControllerInterface::export_reference_interfaces()
{
return {};
}
Expand Down
31 changes: 18 additions & 13 deletions controller_interface/test/test_chainable_controller_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "test_chainable_controller_interface.hpp"

#include <gmock/gmock.h>
#include <memory>

using ::testing::IsEmpty;
using ::testing::SizeIs;
Expand Down Expand Up @@ -48,10 +49,10 @@ TEST_F(ChainableControllerInterfaceTest, export_state_interfaces)
auto exported_state_interfaces = controller.export_state_interfaces();

ASSERT_THAT(exported_state_interfaces, SizeIs(1));
EXPECT_EQ(exported_state_interfaces[0].get_prefix_name(), TEST_CONTROLLER_NAME);
EXPECT_EQ(exported_state_interfaces[0].get_interface_name(), "test_state");
EXPECT_EQ(exported_state_interfaces[0]->get_prefix_name(), TEST_CONTROLLER_NAME);
EXPECT_EQ(exported_state_interfaces[0]->get_interface_name(), "test_state");

EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE);
EXPECT_EQ(exported_state_interfaces[0]->get_value(), EXPORTED_STATE_INTERFACE_VALUE);
}

TEST_F(ChainableControllerInterfaceTest, export_reference_interfaces)
Expand All @@ -68,10 +69,10 @@ TEST_F(ChainableControllerInterfaceTest, export_reference_interfaces)
auto reference_interfaces = controller.export_reference_interfaces();

ASSERT_THAT(reference_interfaces, SizeIs(1));
EXPECT_EQ(reference_interfaces[0].get_prefix_name(), TEST_CONTROLLER_NAME);
EXPECT_EQ(reference_interfaces[0].get_interface_name(), "test_itf");
EXPECT_EQ(reference_interfaces[0]->get_prefix_name(), TEST_CONTROLLER_NAME);
EXPECT_EQ(reference_interfaces[0]->get_interface_name(), "test_itf");

EXPECT_EQ(reference_interfaces[0].get_value(), INTERFACE_VALUE);
EXPECT_EQ(reference_interfaces[0]->get_value(), INTERFACE_VALUE);
}

TEST_F(ChainableControllerInterfaceTest, interfaces_prefix_is_not_node_name)
Expand All @@ -88,10 +89,15 @@ TEST_F(ChainableControllerInterfaceTest, interfaces_prefix_is_not_node_name)
controller.set_name_prefix_of_reference_interfaces("some_not_correct_interface_prefix");

// expect empty return because interface prefix is not equal to the node name
auto reference_interfaces = controller.export_reference_interfaces();
ASSERT_THAT(reference_interfaces, IsEmpty());
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> exported_reference_interfaces;
EXPECT_THROW(
{ exported_reference_interfaces = controller.export_reference_interfaces(); },
std::runtime_error);
ASSERT_THAT(exported_reference_interfaces, IsEmpty());
// expect empty return because interface prefix is not equal to the node name
auto exported_state_interfaces = controller.export_state_interfaces();
std::vector<std::shared_ptr<hardware_interface::StateInterface>> exported_state_interfaces;
EXPECT_THROW(
{ exported_state_interfaces = controller.export_state_interfaces(); }, std::runtime_error);
ASSERT_THAT(exported_state_interfaces, IsEmpty());
}

Expand All @@ -114,8 +120,7 @@ TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
EXPECT_FALSE(controller.is_in_chained_mode());

// Fail setting chained mode
EXPECT_EQ(reference_interfaces[0].get_value(), INTERFACE_VALUE);
EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE);
EXPECT_EQ(reference_interfaces[0]->get_value(), INTERFACE_VALUE);

EXPECT_FALSE(controller.set_chained_mode(true));
EXPECT_FALSE(controller.is_in_chained_mode());
Expand All @@ -124,11 +129,11 @@ TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
EXPECT_FALSE(controller.is_in_chained_mode());

// Success setting chained mode
reference_interfaces[0].set_value(0.0);
reference_interfaces[0]->set_value(0.0);

EXPECT_TRUE(controller.set_chained_mode(true));
EXPECT_TRUE(controller.is_in_chained_mode());
EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE_IN_CHAINMODE);
EXPECT_EQ(exported_state_interfaces[0]->get_value(), EXPORTED_STATE_INTERFACE_VALUE_IN_CHAINMODE);

controller.configure();
EXPECT_TRUE(controller.set_chained_mode(false));
Expand Down
29 changes: 21 additions & 8 deletions controller_manager/src/controller_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,15 +751,28 @@ controller_interface::return_type ControllerManager::configure_controller(
get_logger(),
"Controller '%s' is chainable. Interfaces are being exported to resource manager.",
controller_name.c_str());
auto state_interfaces = controller->export_state_interfaces();
auto ref_interfaces = controller->export_reference_interfaces();
if (ref_interfaces.empty() && state_interfaces.empty())
std::vector<std::shared_ptr<hardware_interface::StateInterface>> state_interfaces;
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> ref_interfaces;
try
{
// TODO(destogl): Add test for this!
RCLCPP_ERROR(
get_logger(),
"Controller '%s' is chainable, but does not export any state or reference interfaces.",
controller_name.c_str());
state_interfaces = controller->export_state_interfaces();
ref_interfaces = controller->export_reference_interfaces();
if (ref_interfaces.empty() && state_interfaces.empty())
{
// TODO(destogl): Add test for this!
RCLCPP_ERROR(
get_logger(),
"Controller '%s' is chainable, but does not export any reference interfaces. Did you "
"override the on_export_method() correctly?",
controller_name.c_str());
return controller_interface::return_type::ERROR;
}
}
catch (const std::runtime_error & e)
{
RCLCPP_FATAL(
get_logger(), "Creation of the reference interfaces failed with following error: %s",
e.what());
return controller_interface::return_type::ERROR;
}
resource_manager_->import_controller_reference_interfaces(controller_name, ref_interfaces);
Expand Down
Loading