Skip to content

Commit 19ecefc

Browse files
committed
Extend resource manager to manage reference interfaces from controllers.
1 parent 04f0451 commit 19ecefc

File tree

3 files changed

+149
-3
lines changed

3 files changed

+149
-3
lines changed

hardware_interface/include/hardware_interface/resource_manager.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,28 @@ class HARDWARE_INTERFACE_PUBLIC ResourceManager
112112
*/
113113
bool state_interface_is_available(const std::string & name) const;
114114

115+
/// Add controllers' reference interfaces to resource manager.
116+
/**
117+
* Interface for transferring management of reference interfaces to resource manager.
118+
* When chaining controllers, reference interfaces are used as command interface of preceding
119+
* controllers.
120+
* Therefore, they should be managed in the same way as command interface of hardware.
121+
*
122+
* \param[in] interfaces list of controller's reference interfaces as CommandInterfaces.
123+
* \return list of added reference interfaces
124+
*/
125+
std::vector<std::string> import_controller_reference_interfaces(
126+
std::vector<CommandInterface> & interfaces);
127+
128+
/// Remove controllers reference interfaces from resource manager.
129+
/**
130+
* Remove reference interfaces from resource manager, i.e., resource storage.
131+
* The interfaces will be deleted from all internal maps and lists.
132+
*
133+
* \param[in] interface_names list of interface names that will be deleted from resource manager.
134+
*/
135+
void remove_controller_reference_interfaces(const std::vector<std::string> & interface_names);
136+
115137
/// Checks whether a command interface is already claimed.
116138
/**
117139
* Any command interface can only be claimed by a single instance.

hardware_interface/src/resource_manager.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ class ResourceStorage
213213
{
214214
available_command_interfaces_.erase(found_it);
215215
RCUTILS_LOG_DEBUG_NAMED(
216-
"resource_manager", "(hardware '%s'): '%s' command removed from available list",
216+
"resource_manager",
217+
"(hardware '%s'): '%s' command interface removed from available list",
217218
hardware.get_name().c_str(), interface.c_str());
218219
}
219220
else
@@ -267,6 +268,7 @@ class ResourceStorage
267268
// TODO(destogl): change this - deimport all things if there is there are interfaces there
268269
// deimport_non_movement_command_interfaces(hardware);
269270
// deimport_state_interfaces(hardware);
271+
// use remove_command_interfaces(hardware);
270272
}
271273
return result;
272274
}
@@ -421,6 +423,11 @@ class ResourceStorage
421423
void import_command_interfaces(HardwareT & hardware)
422424
{
423425
auto interfaces = hardware.export_command_interfaces();
426+
hardware_info_map_[hardware.get_name()].command_interfaces = add_command_interfaces(interfaces);
427+
}
428+
429+
std::vector<std::string> add_command_interfaces(std::vector<CommandInterface> & interfaces)
430+
{
424431
std::vector<std::string> interface_names;
425432
interface_names.reserve(interfaces.size());
426433
for (auto & interface : interfaces)
@@ -430,9 +437,29 @@ class ResourceStorage
430437
claimed_command_interface_map_.emplace(std::make_pair(key, false));
431438
interface_names.push_back(key);
432439
}
433-
hardware_info_map_[hardware.get_name()].command_interfaces = interface_names;
434440
available_command_interfaces_.reserve(
435441
available_command_interfaces_.capacity() + interface_names.size());
442+
443+
return interface_names;
444+
}
445+
446+
void remove_command_interfaces(const std::vector<std::string> & interface_names)
447+
{
448+
for (const auto & interface : interface_names)
449+
{
450+
command_interface_map_.erase(interface);
451+
claimed_command_interface_map_.erase(interface);
452+
453+
auto found_it = std::find(
454+
available_command_interfaces_.begin(), available_command_interfaces_.end(), interface);
455+
if (found_it != available_command_interfaces_.end())
456+
{
457+
available_command_interfaces_.erase(found_it);
458+
RCUTILS_LOG_DEBUG_NAMED(
459+
"resource_manager", "'%s' command interface removed from available list",
460+
interface.c_str());
461+
}
462+
}
436463
}
437464

438465
// TODO(destogl): Propagate "false" up, if happens in initialize_hardware
@@ -608,7 +635,23 @@ bool ResourceManager::state_interface_is_available(const std::string & name) con
608635
name) != resource_storage_->available_state_interfaces_.end();
609636
}
610637

611-
// CM API
638+
std::vector<std::string> ResourceManager::import_controller_reference_interfaces(
639+
std::vector<CommandInterface> & interfaces)
640+
{
641+
auto interface_names = resource_storage_->add_command_interfaces(interfaces);
642+
resource_storage_->available_command_interfaces_.insert(
643+
resource_storage_->available_command_interfaces_.end(), interface_names.begin(),
644+
interface_names.end());
645+
return interface_names;
646+
}
647+
648+
void ResourceManager::remove_controller_reference_interfaces(
649+
const std::vector<std::string> & interface_names)
650+
{
651+
resource_storage_->remove_command_interfaces(interface_names);
652+
}
653+
654+
// CM API: Called in "update"-thread
612655
bool ResourceManager::command_interface_is_claimed(const std::string & key) const
613656
{
614657
if (!command_interface_is_available(key))

hardware_interface/test/test_resource_manager.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,3 +1197,84 @@ TEST_F(TestResourceManager, resource_availability_and_claiming_in_lifecycle)
11971197
std::bind(&hardware_interface::ResourceManager::state_interface_exists, &rm, _1), true);
11981198
}
11991199
}
1200+
1201+
TEST_F(TestResourceManager, managing_controllers_reference_interfaces)
1202+
{
1203+
hardware_interface::ResourceManager rm(ros2_control_test_assets::minimal_robot_urdf);
1204+
1205+
std::vector<std::string> FULL_REFERENCE_INTERFACE_NAMES = {
1206+
"test_controller/input1", "test_controller/input2", "test_controller/input3"};
1207+
1208+
std::vector<hardware_interface::CommandInterface> reference_interfaces;
1209+
std::vector<double> reference_interface_values = {1.0, 2.0, 3.0};
1210+
std::vector<std::string> reference_interface_names = {"input1", "input2", "input3"};
1211+
1212+
for (size_t i = 0; i < reference_interface_names.size(); ++i)
1213+
{
1214+
reference_interfaces.push_back(hardware_interface::CommandInterface(
1215+
"test_controller", reference_interface_names[i], &(reference_interface_values[i])));
1216+
}
1217+
1218+
auto ref_itf_names = rm.import_controller_reference_interfaces(reference_interfaces);
1219+
1220+
ASSERT_THAT(ref_itf_names, testing::ElementsAreArray(FULL_REFERENCE_INTERFACE_NAMES));
1221+
1222+
// check that all interfaces are imported properly
1223+
for (const auto & interface : FULL_REFERENCE_INTERFACE_NAMES)
1224+
{
1225+
EXPECT_TRUE(rm.command_interface_exists(interface));
1226+
EXPECT_TRUE(rm.command_interface_is_available(interface));
1227+
EXPECT_FALSE(rm.command_interface_is_claimed(interface));
1228+
}
1229+
1230+
// claim interfaces in a scope that deletes them after
1231+
{
1232+
auto claimed_itf1 = rm.claim_command_interface(FULL_REFERENCE_INTERFACE_NAMES[0]);
1233+
auto claimed_itf3 = rm.claim_command_interface(FULL_REFERENCE_INTERFACE_NAMES[2]);
1234+
1235+
for (const auto & interface : FULL_REFERENCE_INTERFACE_NAMES)
1236+
{
1237+
EXPECT_TRUE(rm.command_interface_exists(interface));
1238+
EXPECT_TRUE(rm.command_interface_is_available(interface));
1239+
}
1240+
EXPECT_TRUE(rm.command_interface_is_claimed(FULL_REFERENCE_INTERFACE_NAMES[0]));
1241+
EXPECT_FALSE(rm.command_interface_is_claimed(FULL_REFERENCE_INTERFACE_NAMES[1]));
1242+
EXPECT_TRUE(rm.command_interface_is_claimed(FULL_REFERENCE_INTERFACE_NAMES[2]));
1243+
1244+
// access interface value
1245+
EXPECT_EQ(claimed_itf1.get_value(), 1.0);
1246+
EXPECT_EQ(claimed_itf3.get_value(), 3.0);
1247+
1248+
claimed_itf1.set_value(11.1);
1249+
claimed_itf3.set_value(33.3);
1250+
EXPECT_EQ(claimed_itf1.get_value(), 11.1);
1251+
EXPECT_EQ(claimed_itf3.get_value(), 33.3);
1252+
1253+
EXPECT_EQ(reference_interface_values[0], 11.1);
1254+
EXPECT_EQ(reference_interface_values[1], 2.0);
1255+
EXPECT_EQ(reference_interface_values[2], 33.3);
1256+
}
1257+
1258+
// interfaces should be released now, but still managed by resource manager
1259+
for (const auto & interface : FULL_REFERENCE_INTERFACE_NAMES)
1260+
{
1261+
EXPECT_TRUE(rm.command_interface_exists(interface));
1262+
EXPECT_TRUE(rm.command_interface_is_available(interface));
1263+
EXPECT_FALSE(rm.command_interface_is_claimed(interface));
1264+
}
1265+
1266+
// Last written values should stay
1267+
EXPECT_EQ(reference_interface_values[0], 11.1);
1268+
EXPECT_EQ(reference_interface_values[1], 2.0);
1269+
EXPECT_EQ(reference_interface_values[2], 33.3);
1270+
1271+
// remove reference interfaces from resource manager
1272+
rm.remove_controller_reference_interfaces(ref_itf_names);
1273+
1274+
// they should not exist in resource manager
1275+
for (const auto & interface : FULL_REFERENCE_INTERFACE_NAMES)
1276+
{
1277+
EXPECT_FALSE(rm.command_interface_exists(interface));
1278+
EXPECT_FALSE(rm.command_interface_is_available(interface));
1279+
}
1280+
}

0 commit comments

Comments
 (0)