Skip to content

Commit 2540431

Browse files
authored
Merge branch 'master' into add/hw_components/update_rate
2 parents 84d00da + 723c869 commit 2540431

File tree

25 files changed

+1675
-243
lines changed

25 files changed

+1675
-243
lines changed

controller_interface/include/controller_interface/chainable_controller_interface.hpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef CONTROLLER_INTERFACE__CHAINABLE_CONTROLLER_INTERFACE_HPP_
1616
#define CONTROLLER_INTERFACE__CHAINABLE_CONTROLLER_INTERFACE_HPP_
1717

18+
#include <string>
1819
#include <vector>
1920

2021
#include "controller_interface/controller_interface_base.hpp"
@@ -55,6 +56,9 @@ class ChainableControllerInterface : public ControllerInterfaceBase
5556
CONTROLLER_INTERFACE_PUBLIC
5657
bool is_chainable() const final;
5758

59+
CONTROLLER_INTERFACE_PUBLIC
60+
std::vector<hardware_interface::StateInterface> export_state_interfaces() final;
61+
5862
CONTROLLER_INTERFACE_PUBLIC
5963
std::vector<hardware_interface::CommandInterface> export_reference_interfaces() final;
6064

@@ -65,16 +69,27 @@ class ChainableControllerInterface : public ControllerInterfaceBase
6569
bool is_in_chained_mode() const final;
6670

6771
protected:
68-
/// Virtual method that each chainable controller should implement to export its chainable
69-
/// interfaces.
72+
/// Virtual method that each chainable controller should implement to export its read-only
73+
/// chainable interfaces.
74+
/**
75+
* Each chainable controller implements this methods where all its state(read only) interfaces are
76+
* exported. The method has the same meaning as `export_state_interfaces` method from
77+
* hardware_interface::SystemInterface or hardware_interface::ActuatorInterface.
78+
*
79+
* \returns list of StateInterfaces that other controller can use as their inputs.
80+
*/
81+
virtual std::vector<hardware_interface::StateInterface> on_export_state_interfaces();
82+
83+
/// Virtual method that each chainable controller should implement to export its read/write
84+
/// chainable interfaces.
7085
/**
7186
* Each chainable controller implements this methods where all input (command) interfaces are
7287
* exported. The method has the same meaning as `export_command_interface` method from
7388
* hardware_interface::SystemInterface or hardware_interface::ActuatorInterface.
7489
*
7590
* \returns list of CommandInterfaces that other controller can use as their outputs.
7691
*/
77-
virtual std::vector<hardware_interface::CommandInterface> on_export_reference_interfaces() = 0;
92+
virtual std::vector<hardware_interface::CommandInterface> on_export_reference_interfaces();
7893

7994
/// Virtual method that each chainable controller should implement to switch chained mode.
8095
/**
@@ -114,7 +129,12 @@ class ChainableControllerInterface : public ControllerInterfaceBase
114129
virtual return_type update_and_write_commands(
115130
const rclcpp::Time & time, const rclcpp::Duration & period) = 0;
116131

132+
/// Storage of values for state interfaces
133+
std::vector<std::string> exported_state_interface_names_;
134+
std::vector<double> state_interfaces_values_;
135+
117136
/// Storage of values for reference interfaces
137+
std::vector<std::string> exported_reference_interface_names_;
118138
std::vector<double> reference_interfaces_;
119139

120140
private:

controller_interface/include/controller_interface/controller_interface.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ class ControllerInterface : public controller_interface::ControllerInterfaceBase
4242
CONTROLLER_INTERFACE_PUBLIC
4343
bool is_chainable() const final;
4444

45+
/**
46+
* A non-chainable controller doesn't export any state interfaces.
47+
*
48+
* \returns empty list.
49+
*/
50+
CONTROLLER_INTERFACE_PUBLIC
51+
std::vector<hardware_interface::StateInterface> export_state_interfaces() final;
52+
4553
/**
4654
* Controller has no reference interfaces.
4755
*

controller_interface/include/controller_interface/controller_interface_base.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,20 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
224224
CONTROLLER_INTERFACE_PUBLIC
225225
virtual std::vector<hardware_interface::CommandInterface> export_reference_interfaces() = 0;
226226

227+
/**
228+
* Export interfaces for a chainable controller that can be used as state interface by other
229+
* controllers.
230+
*
231+
* \returns list of state interfaces for preceding controllers.
232+
*/
233+
CONTROLLER_INTERFACE_PUBLIC
234+
virtual std::vector<hardware_interface::StateInterface> export_state_interfaces() = 0;
235+
227236
/**
228237
* Set chained mode of a chainable controller. This method triggers internal processes to switch
229238
* a chainable controller to "chained" mode and vice-versa. Setting controller to "chained" mode
230-
* usually involves disabling of subscribers and other external interfaces to avoid potential
231-
* concurrency in input commands.
239+
* usually involves the usage of the controller's reference interfaces by the other
240+
* controllers
232241
*
233242
* \returns true if mode is switched successfully and false if not.
234243
*/

controller_interface/src/chainable_controller_interface.cpp

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,35 @@ return_type ChainableControllerInterface::update(
4444
return ret;
4545
}
4646

47-
std::vector<hardware_interface::CommandInterface>
48-
ChainableControllerInterface::export_reference_interfaces()
47+
std::vector<hardware_interface::StateInterface>
48+
ChainableControllerInterface::export_state_interfaces()
4949
{
50-
auto reference_interfaces = on_export_reference_interfaces();
50+
auto state_interfaces = on_export_state_interfaces();
5151

52-
// check if the "reference_interfaces_" variable is resized to number of interfaces
53-
if (reference_interfaces_.size() != reference_interfaces.size())
52+
// check if the names of the controller state interfaces begin with the controller's name
53+
for (const auto & interface : state_interfaces)
5454
{
55-
// TODO(destogl): Should here be "FATAL"? It is fatal in terms of controller but not for the
56-
// framework
57-
RCLCPP_FATAL(
58-
get_node()->get_logger(),
59-
"The internal storage for reference values 'reference_interfaces_' variable has size '%zu', "
60-
"but it is expected to have the size '%zu' equal to the number of exported reference "
61-
"interfaces. No reference interface will be exported. Please correct and recompile "
62-
"the controller with name '%s' and try again.",
63-
reference_interfaces_.size(), reference_interfaces.size(), get_node()->get_name());
64-
reference_interfaces.clear();
55+
if (interface.get_prefix_name() != get_node()->get_name())
56+
{
57+
RCLCPP_FATAL(
58+
get_node()->get_logger(),
59+
"The name of the interface '%s' does not begin with the controller's name. This is "
60+
"mandatory for state interfaces. No state interface will be exported. Please "
61+
"correct and recompile the controller with name '%s' and try again.",
62+
interface.get_name().c_str(), get_node()->get_name());
63+
state_interfaces.clear();
64+
break;
65+
}
6566
}
6667

68+
return state_interfaces;
69+
}
70+
71+
std::vector<hardware_interface::CommandInterface>
72+
ChainableControllerInterface::export_reference_interfaces()
73+
{
74+
auto reference_interfaces = on_export_reference_interfaces();
75+
6776
// check if the names of the reference interfaces begin with the controller's name
6877
for (const auto & interface : reference_interfaces)
6978
{
@@ -113,4 +122,30 @@ bool ChainableControllerInterface::is_in_chained_mode() const { return in_chaine
113122

114123
bool ChainableControllerInterface::on_set_chained_mode(bool /*chained_mode*/) { return true; }
115124

125+
std::vector<hardware_interface::StateInterface>
126+
ChainableControllerInterface::on_export_state_interfaces()
127+
{
128+
state_interfaces_values_.resize(exported_state_interface_names_.size(), 0.0);
129+
std::vector<hardware_interface::StateInterface> state_interfaces;
130+
for (size_t i = 0; i < exported_state_interface_names_.size(); ++i)
131+
{
132+
state_interfaces.emplace_back(hardware_interface::StateInterface(
133+
get_node()->get_name(), exported_state_interface_names_[i], &state_interfaces_values_[i]));
134+
}
135+
return state_interfaces;
136+
}
137+
138+
std::vector<hardware_interface::CommandInterface>
139+
ChainableControllerInterface::on_export_reference_interfaces()
140+
{
141+
reference_interfaces_.resize(exported_reference_interface_names_.size(), 0.0);
142+
std::vector<hardware_interface::CommandInterface> reference_interfaces;
143+
for (size_t i = 0; i < exported_reference_interface_names_.size(); ++i)
144+
{
145+
reference_interfaces.emplace_back(hardware_interface::CommandInterface(
146+
get_node()->get_name(), exported_reference_interface_names_[i], &reference_interfaces_[i]));
147+
}
148+
return reference_interfaces;
149+
}
150+
116151
} // namespace controller_interface

controller_interface/src/controller_interface.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ ControllerInterface::ControllerInterface() : ControllerInterfaceBase() {}
2828

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

31+
std::vector<hardware_interface::StateInterface> ControllerInterface::export_state_interfaces()
32+
{
33+
return {};
34+
}
35+
3136
std::vector<hardware_interface::CommandInterface> ControllerInterface::export_reference_interfaces()
3237
{
3338
return {};

controller_interface/test/test_chainable_controller_interface.cpp

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
#include <gmock/gmock.h>
1818

19+
using ::testing::IsEmpty;
20+
using ::testing::SizeIs;
21+
1922
TEST_F(ChainableControllerInterfaceTest, default_returns)
2023
{
2124
TestableChainableControllerInterface controller;
@@ -31,7 +34,7 @@ TEST_F(ChainableControllerInterfaceTest, default_returns)
3134
EXPECT_FALSE(controller.is_in_chained_mode());
3235
}
3336

34-
TEST_F(ChainableControllerInterfaceTest, export_reference_interfaces)
37+
TEST_F(ChainableControllerInterfaceTest, export_state_interfaces)
3538
{
3639
TestableChainableControllerInterface controller;
3740

@@ -42,16 +45,16 @@ TEST_F(ChainableControllerInterfaceTest, export_reference_interfaces)
4245
controller_interface::return_type::OK);
4346
ASSERT_NO_THROW(controller.get_node());
4447

45-
auto reference_interfaces = controller.export_reference_interfaces();
48+
auto exported_state_interfaces = controller.export_state_interfaces();
4649

47-
ASSERT_EQ(reference_interfaces.size(), 1u);
48-
EXPECT_EQ(reference_interfaces[0].get_prefix_name(), TEST_CONTROLLER_NAME);
49-
EXPECT_EQ(reference_interfaces[0].get_interface_name(), "test_itf");
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");
5053

51-
EXPECT_EQ(reference_interfaces[0].get_value(), INTERFACE_VALUE);
54+
EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE);
5255
}
5356

54-
TEST_F(ChainableControllerInterfaceTest, reference_interfaces_storage_not_correct_size)
57+
TEST_F(ChainableControllerInterfaceTest, export_reference_interfaces)
5558
{
5659
TestableChainableControllerInterface controller;
5760

@@ -62,13 +65,16 @@ TEST_F(ChainableControllerInterfaceTest, reference_interfaces_storage_not_correc
6265
controller_interface::return_type::OK);
6366
ASSERT_NO_THROW(controller.get_node());
6467

65-
// expect empty return because storage is not resized
66-
controller.reference_interfaces_.clear();
6768
auto reference_interfaces = controller.export_reference_interfaces();
68-
ASSERT_TRUE(reference_interfaces.empty());
69+
70+
ASSERT_THAT(reference_interfaces, SizeIs(1));
71+
EXPECT_EQ(reference_interfaces[0].get_prefix_name(), TEST_CONTROLLER_NAME);
72+
EXPECT_EQ(reference_interfaces[0].get_interface_name(), "test_itf");
73+
74+
EXPECT_EQ(reference_interfaces[0].get_value(), INTERFACE_VALUE);
6975
}
7076

71-
TEST_F(ChainableControllerInterfaceTest, reference_interfaces_prefix_is_not_node_name)
77+
TEST_F(ChainableControllerInterfaceTest, interfaces_prefix_is_not_node_name)
7278
{
7379
TestableChainableControllerInterface controller;
7480

@@ -83,7 +89,10 @@ TEST_F(ChainableControllerInterfaceTest, reference_interfaces_prefix_is_not_node
8389

8490
// expect empty return because interface prefix is not equal to the node name
8591
auto reference_interfaces = controller.export_reference_interfaces();
86-
ASSERT_TRUE(reference_interfaces.empty());
92+
ASSERT_THAT(reference_interfaces, IsEmpty());
93+
// expect empty return because interface prefix is not equal to the node name
94+
auto exported_state_interfaces = controller.export_state_interfaces();
95+
ASSERT_THAT(exported_state_interfaces, IsEmpty());
8796
}
8897

8998
TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
@@ -98,12 +107,15 @@ TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
98107
ASSERT_NO_THROW(controller.get_node());
99108

100109
auto reference_interfaces = controller.export_reference_interfaces();
101-
ASSERT_EQ(reference_interfaces.size(), 1u);
110+
ASSERT_THAT(reference_interfaces, SizeIs(1));
111+
auto exported_state_interfaces = controller.export_state_interfaces();
112+
ASSERT_THAT(exported_state_interfaces, SizeIs(1));
102113

103114
EXPECT_FALSE(controller.is_in_chained_mode());
104115

105116
// Fail setting chained mode
106117
EXPECT_EQ(reference_interfaces[0].get_value(), INTERFACE_VALUE);
118+
EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE);
107119

108120
EXPECT_FALSE(controller.set_chained_mode(true));
109121
EXPECT_FALSE(controller.is_in_chained_mode());
@@ -116,6 +128,7 @@ TEST_F(ChainableControllerInterfaceTest, setting_chained_mode)
116128

117129
EXPECT_TRUE(controller.set_chained_mode(true));
118130
EXPECT_TRUE(controller.is_in_chained_mode());
131+
EXPECT_EQ(exported_state_interfaces[0].get_value(), EXPORTED_STATE_INTERFACE_VALUE_IN_CHAINMODE);
119132

120133
controller.configure();
121134
EXPECT_TRUE(controller.set_chained_mode(false));
@@ -147,27 +160,31 @@ TEST_F(ChainableControllerInterfaceTest, test_update_logic)
147160
controller_interface::return_type::OK);
148161
ASSERT_NO_THROW(controller.get_node());
149162

163+
EXPECT_FALSE(controller.set_chained_mode(false));
150164
EXPECT_FALSE(controller.is_in_chained_mode());
151165

152166
// call update and update it from subscriber because not in chained mode
153167
ASSERT_EQ(
154168
controller.update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01)),
155169
controller_interface::return_type::OK);
156170
ASSERT_EQ(controller.reference_interfaces_[0], INTERFACE_VALUE_INITIAL_REF - 1);
171+
ASSERT_EQ(controller.state_interfaces_values_[0], EXPORTED_STATE_INTERFACE_VALUE + 1);
157172

158173
// Provoke error in update from subscribers - return ERROR and update_and_write_commands not exec.
159174
controller.set_new_reference_interface_value(INTERFACE_VALUE_SUBSCRIBER_ERROR);
160175
ASSERT_EQ(
161176
controller.update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01)),
162177
controller_interface::return_type::ERROR);
163178
ASSERT_EQ(controller.reference_interfaces_[0], INTERFACE_VALUE_INITIAL_REF - 1);
179+
ASSERT_EQ(controller.state_interfaces_values_[0], EXPORTED_STATE_INTERFACE_VALUE + 1);
164180

165181
// Provoke error from update - return ERROR, but reference interface is updated and not reduced
166182
controller.set_new_reference_interface_value(INTERFACE_VALUE_UPDATE_ERROR);
167183
ASSERT_EQ(
168184
controller.update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01)),
169185
controller_interface::return_type::ERROR);
170186
ASSERT_EQ(controller.reference_interfaces_[0], INTERFACE_VALUE_UPDATE_ERROR);
187+
ASSERT_EQ(controller.state_interfaces_values_[0], EXPORTED_STATE_INTERFACE_VALUE + 1);
171188

172189
controller.reference_interfaces_[0] = 0.0;
173190

@@ -181,6 +198,8 @@ TEST_F(ChainableControllerInterfaceTest, test_update_logic)
181198
controller.update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01)),
182199
controller_interface::return_type::OK);
183200
ASSERT_EQ(controller.reference_interfaces_[0], -1.0);
201+
ASSERT_EQ(
202+
controller.state_interfaces_values_[0], EXPORTED_STATE_INTERFACE_VALUE_IN_CHAINMODE + 1);
184203

185204
// Provoke error from update - return ERROR, but reference interface is updated directly
186205
controller.set_new_reference_interface_value(INTERFACE_VALUE_SUBSCRIBER_ERROR);
@@ -189,4 +208,6 @@ TEST_F(ChainableControllerInterfaceTest, test_update_logic)
189208
controller.update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01)),
190209
controller_interface::return_type::ERROR);
191210
ASSERT_EQ(controller.reference_interfaces_[0], INTERFACE_VALUE_UPDATE_ERROR);
211+
ASSERT_EQ(
212+
controller.state_interfaces_values_[0], EXPORTED_STATE_INTERFACE_VALUE_IN_CHAINMODE + 1);
192213
}

0 commit comments

Comments
 (0)