Skip to content

Commit f86d274

Browse files
committed
add changes for chainable controllers (epxport of rerference interfaces)
1 parent 14e6fef commit f86d274

File tree

10 files changed

+119
-35
lines changed

10 files changed

+119
-35
lines changed

controller_interface/include/controller_interface/chainable_controller_interface.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#ifndef CONTROLLER_INTERFACE__CHAINABLE_CONTROLLER_INTERFACE_HPP_
1616
#define CONTROLLER_INTERFACE__CHAINABLE_CONTROLLER_INTERFACE_HPP_
1717

18+
#include <memory>
1819
#include <string>
20+
#include <unordered_map>
1921
#include <vector>
2022

2123
#include "controller_interface/controller_interface_base.hpp"
@@ -60,7 +62,11 @@ class ChainableControllerInterface : public ControllerInterfaceBase
6062
std::vector<hardware_interface::StateInterface> export_state_interfaces() final;
6163

6264
CONTROLLER_INTERFACE_PUBLIC
63-
std::vector<hardware_interface::CommandInterface> export_reference_interfaces() final;
65+
std::vector<hardware_interface::StateInterface> export_state_interfaces() final;
66+
67+
CONTROLLER_INTERFACE_PUBLIC
68+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> export_reference_interfaces()
69+
final;
6470

6571
CONTROLLER_INTERFACE_PUBLIC
6672
bool set_chained_mode(bool chained_mode) final;
@@ -135,7 +141,11 @@ class ChainableControllerInterface : public ControllerInterfaceBase
135141

136142
/// Storage of values for reference interfaces
137143
std::vector<std::string> exported_reference_interface_names_;
144+
// BEGIN (Handle export change): for backward compatibility
138145
std::vector<double> reference_interfaces_;
146+
// END
147+
std::unordered_map<std::string, std::shared_ptr<hardware_interface::CommandInterface>>
148+
reference_interfaces_ptrs_;
139149

140150
private:
141151
/// A flag marking if a chainable controller is currently preceded by another controller.

controller_interface/include/controller_interface/controller_interface.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ class ControllerInterface : public controller_interface::ControllerInterfaceBase
5555
* \returns empty list.
5656
*/
5757
CONTROLLER_INTERFACE_PUBLIC
58-
std::vector<hardware_interface::CommandInterface> export_reference_interfaces() final;
58+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> export_reference_interfaces()
59+
final;
5960

6061
/**
6162
* Controller is not chainable, therefore no chained mode can be set.

controller_interface/include/controller_interface/controller_interface_base.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
221221
* \returns list of command interfaces for preceding controllers.
222222
*/
223223
CONTROLLER_INTERFACE_PUBLIC
224-
virtual std::vector<hardware_interface::CommandInterface> export_reference_interfaces() = 0;
224+
virtual std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
225+
export_reference_interfaces() = 0;
225226

226227
/**
227228
* Export interfaces for a chainable controller that can be used as state interface by other

controller_interface/src/chainable_controller_interface.cpp

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,29 +68,87 @@ ChainableControllerInterface::export_state_interfaces()
6868
return state_interfaces;
6969
}
7070

71-
std::vector<hardware_interface::CommandInterface>
72-
ChainableControllerInterface::export_reference_interfaces()
71+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
72+
ChainableControllerInterface::export_state_interfaces()
7373
{
74-
auto reference_interfaces = on_export_reference_interfaces();
74+
auto state_interfaces = on_export_state_interfaces();
7575

76-
// check if the names of the reference interfaces begin with the controller's name
77-
for (const auto & interface : reference_interfaces)
76+
// check if the names of the controller state interfaces begin with the controller's name
77+
for (const auto & interface : state_interfaces)
7878
{
7979
if (interface.get_prefix_name() != get_node()->get_name())
8080
{
8181
RCLCPP_FATAL(
8282
get_node()->get_logger(),
8383
"The name of the interface '%s' does not begin with the controller's name. This is "
84-
"mandatory "
85-
" for reference interfaces. No reference interface will be exported. Please correct and "
86-
"recompile the controller with name '%s' and try again.",
84+
"mandatory for state interfaces. No state interface will be exported. Please "
85+
"correct and recompile the controller with name '%s' and try again.",
8786
interface.get_name().c_str(), get_node()->get_name());
88-
reference_interfaces.clear();
87+
state_interfaces.clear();
8988
break;
9089
}
9190
}
9291

93-
return reference_interfaces;
92+
return state_interfaces;
93+
}
94+
95+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
96+
ChainableControllerInterface::export_reference_interfaces()
97+
{
98+
auto reference_interfaces = on_export_reference_interfaces();
99+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> reference_interfaces_ptrs_vec;
100+
reference_interfaces_ptrs_vec.reserve(reference_interfaces.size());
101+
102+
// BEGIN (Handle export change): for backward compatibility
103+
// check if the "reference_interfaces_" variable is resized to number of interfaces
104+
if (reference_interfaces_.size() != reference_interfaces.size())
105+
{
106+
// TODO(destogl): Should here be "FATAL"? It is fatal in terms of controller but not for the
107+
// framework
108+
std::string error_msg =
109+
"The internal storage for reference values 'reference_interfaces_' variable has size '" +
110+
std::to_string(reference_interfaces_.size()) + "', but it is expected to have the size '" +
111+
std::to_string(reference_interfaces.size()) +
112+
"' equal to the number of exported reference interfaces. Please correct and recompile the "
113+
"controller with name '" +
114+
get_node()->get_name() + "' and try again.";
115+
throw std::runtime_error(error_msg);
116+
}
117+
// END
118+
119+
// check if the names of the reference interfaces begin with the controller's name
120+
const auto ref_interface_size = reference_interfaces.size();
121+
for (auto & interface : reference_interfaces)
122+
{
123+
if (interface.get_prefix_name() != get_node()->get_name())
124+
{
125+
std::string error_msg = "The name of the interface " + interface.get_name() +
126+
" does not begin with the controller's name. This is mandatory for "
127+
"reference interfaces. Please "
128+
"correct and recompile the controller with name " +
129+
get_node()->get_name() + " and try again.";
130+
throw std::runtime_error(error_msg);
131+
}
132+
133+
std::shared_ptr<hardware_interface::CommandInterface> interface_ptr =
134+
std::make_shared<hardware_interface::CommandInterface>(std::move(interface));
135+
reference_interfaces_ptrs_vec.push_back(interface_ptr);
136+
reference_interfaces_ptrs_.insert(std::make_pair(interface_ptr->get_name(), interface_ptr));
137+
}
138+
139+
if (reference_interfaces_ptrs_.size() != ref_interface_size)
140+
{
141+
std::string error_msg =
142+
"The internal storage for reference ptrs 'reference_interfaces_ptrs_' variable has size '" +
143+
std::to_string(reference_interfaces_ptrs_.size()) +
144+
"', but it is expected to have the size '" + std::to_string(ref_interface_size) +
145+
"' equal to the number of exported reference interfaces. Please correct and recompile the "
146+
"controller with name '" +
147+
get_node()->get_name() + "' and try again.";
148+
throw std::runtime_error(error_msg);
149+
}
150+
151+
return reference_interfaces_ptrs_vec;
94152
}
95153

96154
bool ChainableControllerInterface::set_chained_mode(bool chained_mode)

controller_interface/src/controller_interface.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ std::vector<hardware_interface::StateInterface> ControllerInterface::export_stat
2727
return {};
2828
}
2929

30-
std::vector<hardware_interface::CommandInterface> ControllerInterface::export_reference_interfaces()
30+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>>
31+
ControllerInterface::export_reference_interfaces()
3132
{
3233
return {};
3334
}

controller_interface/test/test_chainable_controller_interface.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ TEST_F(ChainableControllerInterfaceTest, export_state_interfaces)
4747

4848
auto exported_state_interfaces = controller.export_state_interfaces();
4949

50-
ASSERT_THAT(exported_state_interfaces, SizeIs(1));
51-
EXPECT_EQ(exported_state_interfaces[0].get_prefix_name(), TEST_CONTROLLER_NAME);
52-
EXPECT_EQ(exported_state_interfaces[0].get_interface_name(), "test_state");
50+
ASSERT_EQ(reference_interfaces.size(), 1u);
51+
EXPECT_EQ(reference_interfaces[0]->get_prefix_name(), TEST_CONTROLLER_NAME);
52+
EXPECT_EQ(reference_interfaces[0]->get_interface_name(), "test_itf");
5353

54-
EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE);
54+
EXPECT_EQ(reference_interfaces[0]->get_value(), INTERFACE_VALUE);
5555
}
5656

5757
TEST_F(ChainableControllerInterfaceTest, export_reference_interfaces)
@@ -114,8 +114,7 @@ TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
114114
EXPECT_FALSE(controller.is_in_chained_mode());
115115

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

120119
EXPECT_FALSE(controller.set_chained_mode(true));
121120
EXPECT_FALSE(controller.is_in_chained_mode());
@@ -124,7 +123,7 @@ TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
124123
EXPECT_FALSE(controller.is_in_chained_mode());
125124

126125
// Success setting chained mode
127-
reference_interfaces[0].set_value(0.0);
126+
reference_interfaces[0]->set_value(0.0);
128127

129128
EXPECT_TRUE(controller.set_chained_mode(true));
130129
EXPECT_TRUE(controller.is_in_chained_mode());

controller_manager/src/controller_manager.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -752,14 +752,26 @@ controller_interface::return_type ControllerManager::configure_controller(
752752
"Controller '%s' is chainable. Interfaces are being exported to resource manager.",
753753
controller_name.c_str());
754754
auto state_interfaces = controller->export_state_interfaces();
755-
auto ref_interfaces = controller->export_reference_interfaces();
756-
if (ref_interfaces.empty() && state_interfaces.empty())
755+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> interfaces;
756+
try
757757
{
758-
// TODO(destogl): Add test for this!
759-
RCLCPP_ERROR(
760-
get_logger(),
761-
"Controller '%s' is chainable, but does not export any state or reference interfaces.",
762-
controller_name.c_str());
758+
interfaces = controller->export_reference_interfaces();
759+
if (interfaces.empty() && state_interfaces.empty())
760+
{
761+
// TODO(destogl): Add test for this!
762+
RCLCPP_ERROR(
763+
get_logger(),
764+
"Controller '%s' is chainable, but does not export any reference interfaces. Did you "
765+
"override the on_export_method() correctly?",
766+
controller_name.c_str());
767+
return controller_interface::return_type::ERROR;
768+
}
769+
}
770+
catch (const std::runtime_error & e)
771+
{
772+
RCLCPP_FATAL(
773+
get_logger(), "Creation of the reference interfaces failed with following error: %s",
774+
e.what());
763775
return controller_interface::return_type::ERROR;
764776
}
765777
resource_manager_->import_controller_reference_interfaces(controller_name, ref_interfaces);

hardware_interface/include/hardware_interface/resource_manager.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
194194
* \param[in] interfaces list of controller's reference interfaces as CommandInterfaces.
195195
*/
196196
void import_controller_reference_interfaces(
197-
const std::string & controller_name, std::vector<CommandInterface> & interfaces);
197+
const std::string & controller_name,
198+
const std::vector<std::shared_ptr<hardware_interface::CommandInterface>> & interfaces);
198199

199200
/// Get list of reference interface of a controller.
200201
/**

hardware_interface/src/resource_manager.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ class ResourceStorage
642642
}
643643
}
644644

645-
void insert_command_interface(std::shared_ptr<CommandInterface> command_interface)
645+
void insert_command_interface(const std::shared_ptr<CommandInterface> command_interface)
646646
{
647647
const auto [it, success] = command_interface_map_.insert(
648648
std::make_pair(command_interface->get_name(), command_interface));
@@ -770,11 +770,11 @@ class ResourceStorage
770770
}
771771

772772
std::vector<std::string> add_command_interfaces(
773-
std::vector<std::shared_ptr<CommandInterface>> & interfaces)
773+
const std::vector<std::shared_ptr<CommandInterface>> & interfaces)
774774
{
775775
std::vector<std::string> interface_names;
776776
interface_names.reserve(interfaces.size());
777-
for (auto & interface : interfaces)
777+
for (const auto & interface : interfaces)
778778
{
779779
auto key = interface->get_name();
780780
insert_command_interface(interface);
@@ -1305,7 +1305,8 @@ void ResourceManager::remove_controller_exported_state_interfaces(
13051305

13061306
// CM API: Called in "callback/slow"-thread
13071307
void ResourceManager::import_controller_reference_interfaces(
1308-
const std::string & controller_name, std::vector<CommandInterface> & interfaces)
1308+
const std::string & controller_name,
1309+
const std::vector<std::shared_ptr<hardware_interface::CommandInterface>> & interfaces)
13091310
{
13101311
std::scoped_lock guard(resource_interfaces_lock_, claimed_command_interfaces_lock_);
13111312
auto interface_names = resource_storage_->add_command_interfaces(interfaces);

hardware_interface_testing/test/test_resource_manager.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,12 +1230,12 @@ TEST_F(ResourceManagerTest, managing_controllers_reference_interfaces)
12301230
CONTROLLER_NAME + "/" + REFERENCE_INTERFACE_NAMES[1],
12311231
CONTROLLER_NAME + "/" + REFERENCE_INTERFACE_NAMES[2]};
12321232

1233-
std::vector<hardware_interface::CommandInterface> reference_interfaces;
1233+
std::vector<std::shared_ptr<hardware_interface::CommandInterface>> reference_interfaces;
12341234
std::vector<double> reference_interface_values = {1.0, 2.0, 3.0};
12351235

12361236
for (size_t i = 0; i < REFERENCE_INTERFACE_NAMES.size(); ++i)
12371237
{
1238-
reference_interfaces.push_back(hardware_interface::CommandInterface(
1238+
reference_interfaces.push_back(std::make_shared<hardware_interface::CommandInterface>(
12391239
CONTROLLER_NAME, REFERENCE_INTERFACE_NAMES[i], &(reference_interface_values[i])));
12401240
}
12411241

0 commit comments

Comments
 (0)