Skip to content

Commit 1e27976

Browse files
authored
Allocate memory for components and handles (#207)
* introducing handles Signed-off-by: Karsten Knese <[email protected]> * component interfaces & tests Signed-off-by: Karsten Knese <[email protected]> * linters Signed-off-by: Karsten Knese <[email protected]> * import resource manager Signed-off-by: Karsten Knese <[email protected]> * correct year Signed-off-by: Karsten Knese <[email protected]> * import handles from loaded components Signed-off-by: Karsten Knese <[email protected]> * wip / debug Signed-off-by: Karsten Knese <[email protected]> * parse components Signed-off-by: Karsten Knese <[email protected]> * changes after rebase Signed-off-by: Karsten Knese <[email protected]> * component parser as shared library Signed-off-by: Karsten Knese <[email protected]> * validate urdf configuratin Signed-off-by: Karsten Knese <[email protected]> * documentation Signed-off-by: Karsten Knese <[email protected]> * remove default constructor Signed-off-by: Karsten Knese <[email protected]>
1 parent be2ead3 commit 1e27976

File tree

18 files changed

+959
-84
lines changed

18 files changed

+959
-84
lines changed

controller_manager/CMakeLists.txt

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ find_package(rclcpp REQUIRED)
2121

2222
add_library(controller_manager SHARED
2323
src/controller_manager.cpp
24+
src/resource_manager.cpp
2425
)
2526
target_include_directories(controller_manager PRIVATE include)
2627
ament_target_dependencies(controller_manager
@@ -65,6 +66,11 @@ if(BUILD_TESTING)
6566
target_include_directories(test_controller PRIVATE include)
6667
target_link_libraries(test_controller controller_manager)
6768
target_compile_definitions(test_controller PRIVATE "CONTROLLER_MANAGER_BUILDING_DLL")
69+
pluginlib_export_plugin_description_file(
70+
controller_interface test/test_controller/test_controller.xml)
71+
install(TARGETS test_controller
72+
DESTINATION lib
73+
)
6874

6975
ament_add_gmock(
7076
test_controller_manager
@@ -101,11 +107,25 @@ if(BUILD_TESTING)
101107
test_robot_hardware
102108
)
103109

104-
pluginlib_export_plugin_description_file(controller_interface test/test_controller.xml)
105-
106-
install(TARGETS test_controller
110+
add_library(test_components SHARED
111+
test/test_components/test_actuator.cpp
112+
test/test_components/test_sensor.cpp
113+
test/test_components/test_system.cpp)
114+
ament_target_dependencies(test_components
115+
hardware_interface
116+
pluginlib)
117+
install(TARGETS test_components
107118
DESTINATION lib
108119
)
120+
pluginlib_export_plugin_description_file(
121+
hardware_interface test/test_components/test_components.xml)
122+
123+
ament_add_gmock(
124+
test_resource_manager
125+
test/test_resource_manager.cpp
126+
)
127+
target_include_directories(test_resource_manager PRIVATE include src)
128+
target_link_libraries(test_resource_manager controller_manager)
109129
endif()
110130

111131
ament_export_libraries(
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <memory>
16+
#include <string>
17+
#include <vector>
18+
#include <unordered_map>
19+
#include <utility>
20+
21+
#include "hardware_interface/components/actuator.hpp"
22+
#include "hardware_interface/components/actuator_interface.hpp"
23+
#include "hardware_interface/components/sensor.hpp"
24+
#include "hardware_interface/components/sensor_interface.hpp"
25+
#include "hardware_interface/components/system.hpp"
26+
#include "hardware_interface/components/system_interface.hpp"
27+
#include "hardware_interface/component_parser.hpp"
28+
#include "hardware_interface/hardware_info.hpp"
29+
30+
#include "pluginlib/class_loader.hpp"
31+
32+
#include "./resource_manager.hpp"
33+
34+
namespace controller_manager
35+
{
36+
37+
class ResourceStorage
38+
{
39+
static constexpr const char * pkg_name = "hardware_interface";
40+
41+
static constexpr const char * actuator_interface_name =
42+
"hardware_interface::components::ActuatorInterface";
43+
static constexpr const char * sensor_interface_name =
44+
"hardware_interface::components::SensorInterface";
45+
static constexpr const char * system_interface_name =
46+
"hardware_interface::components::SystemInterface";
47+
48+
public:
49+
ResourceStorage()
50+
: actuator_loader_(pkg_name, actuator_interface_name),
51+
sensor_loader_(pkg_name, sensor_interface_name),
52+
system_loader_(pkg_name, system_interface_name)
53+
{}
54+
55+
template<class HardwareT, class HardwareInterfaceT>
56+
void initialize_hardware(
57+
const hardware_interface::HardwareInfo & hardware_info,
58+
pluginlib::ClassLoader<HardwareInterfaceT> & loader,
59+
std::vector<HardwareT> & container)
60+
{
61+
// hardware_class_type has to match class name in plugin xml description
62+
// TODO(karsten1987) extract package from hardware_class_type
63+
// e.g.: <package_vendor>/<system_type>
64+
auto interface = std::unique_ptr<HardwareInterfaceT>(
65+
loader.createUnmanagedInstance(hardware_info.hardware_class_type));
66+
HardwareT actuator(std::move(interface));
67+
container.emplace_back(std::move(actuator));
68+
}
69+
70+
template<class HardwareT>
71+
void import_state_interfaces(HardwareT & hardware)
72+
{
73+
auto interfaces = hardware.export_state_interfaces();
74+
for (auto i = 0u; i < interfaces.size(); ++i) {
75+
auto key = interfaces[i].get_name() + "/" + interfaces[i].get_interface_name();
76+
state_interface_map_.emplace(
77+
std::make_pair(key, std::move(interfaces[i])));
78+
}
79+
}
80+
81+
template<class HardwareT>
82+
void import_command_interfaces(HardwareT & hardware)
83+
{
84+
auto interfaces = hardware.export_command_interfaces();
85+
for (auto i = 0u; i < interfaces.size(); ++i) {
86+
auto key = interfaces[i].get_name() + "/" + interfaces[i].get_interface_name();
87+
command_interface_map_.emplace(
88+
std::make_pair(key, std::move(interfaces[i])));
89+
}
90+
}
91+
92+
void initialize_actuator(const hardware_interface::HardwareInfo & hardware_info)
93+
{
94+
initialize_hardware<hardware_interface::components::Actuator,
95+
hardware_interface::components::ActuatorInterface>(
96+
hardware_info, actuator_loader_, actuators_);
97+
if (hardware_interface::return_type::OK != actuators_.back().configure(hardware_info)) {
98+
throw std::runtime_error(std::string("failed to configure ") + hardware_info.name);
99+
}
100+
import_state_interfaces(actuators_.back());
101+
import_command_interfaces(actuators_.back());
102+
}
103+
104+
void initialize_sensor(const hardware_interface::HardwareInfo & hardware_info)
105+
{
106+
initialize_hardware<hardware_interface::components::Sensor,
107+
hardware_interface::components::SensorInterface>(
108+
hardware_info, sensor_loader_, sensors_);
109+
sensors_.back().configure(hardware_info);
110+
import_state_interfaces(sensors_.back());
111+
}
112+
113+
void initialize_system(const hardware_interface::HardwareInfo & hardware_info)
114+
{
115+
initialize_hardware<hardware_interface::components::System,
116+
hardware_interface::components::SystemInterface>(
117+
hardware_info, system_loader_, systems_);
118+
systems_.back().configure(hardware_info);
119+
import_state_interfaces(systems_.back());
120+
import_command_interfaces(systems_.back());
121+
}
122+
123+
// hardware plugins
124+
pluginlib::ClassLoader<hardware_interface::components::ActuatorInterface> actuator_loader_;
125+
pluginlib::ClassLoader<hardware_interface::components::SensorInterface> sensor_loader_;
126+
pluginlib::ClassLoader<hardware_interface::components::SystemInterface> system_loader_;
127+
128+
std::vector<hardware_interface::components::Actuator> actuators_;
129+
std::vector<hardware_interface::components::Sensor> sensors_;
130+
std::vector<hardware_interface::components::System> systems_;
131+
132+
std::unordered_map<std::string, hardware_interface::StateInterface> state_interface_map_;
133+
std::unordered_map<std::string, hardware_interface::CommandInterface> command_interface_map_;
134+
};
135+
136+
ResourceManager::~ResourceManager() = default;
137+
138+
ResourceManager::ResourceManager(const std::string & urdf, bool validate_interfaces)
139+
: resource_storage_(std::make_unique<ResourceStorage>())
140+
{
141+
const std::string system_type = "system";
142+
const std::string sensor_type = "sensor";
143+
const std::string actuator_type = "actuator";
144+
145+
auto hardware_info = hardware_interface::parse_control_resources_from_urdf(urdf);
146+
147+
for (const auto & hardware : hardware_info) {
148+
if (hardware.type == actuator_type) {
149+
resource_storage_->initialize_actuator(hardware);
150+
}
151+
if (hardware.type == sensor_type) {
152+
resource_storage_->initialize_sensor(hardware);
153+
}
154+
if (hardware.type == system_type) {
155+
resource_storage_->initialize_system(hardware);
156+
}
157+
}
158+
159+
auto validate_storage = [this, &hardware_info]() -> void
160+
{
161+
std::vector<std::string> missing_state_keys = {};
162+
std::vector<std::string> missing_command_keys = {};
163+
164+
for (const auto & hardware : hardware_info) {
165+
for (const auto & joint : hardware.joints) {
166+
for (const auto & state_interface : joint.state_interfaces) {
167+
if (!state_interface_exists(joint.name + "/" + state_interface.name)) {
168+
missing_state_keys.emplace_back(joint.name + "/" + state_interface.name);
169+
}
170+
}
171+
for (const auto & command_interface : joint.command_interfaces) {
172+
if (!command_interface_exists(joint.name + "/" + command_interface.name)) {
173+
missing_state_keys.emplace_back(joint.name + "/" + command_interface.name);
174+
}
175+
}
176+
}
177+
for (const auto & sensor : hardware.sensors) {
178+
for (const auto & state_interface : sensor.state_interfaces) {
179+
if (!state_interface_exists(sensor.name + "/" + state_interface.name)) {
180+
missing_state_keys.emplace_back(sensor.name + "/" + state_interface.name);
181+
}
182+
}
183+
}
184+
}
185+
186+
if (!missing_state_keys.empty() || !missing_command_keys.empty()) {
187+
std::string err_msg = "wrong state or command interface configuration.\n";
188+
err_msg += "missing state interfaces:\n";
189+
for (const auto & missing_key : missing_state_keys) {
190+
err_msg += missing_key + "\t";
191+
}
192+
err_msg += "\nmissing command interfaces:\n";
193+
for (const auto & missing_key : missing_command_keys) {
194+
err_msg += missing_key + "\t";
195+
}
196+
197+
throw std::runtime_error(err_msg);
198+
}
199+
};
200+
201+
// throw on missing state and command interfaces, not specified keys are being ignored
202+
if (validate_interfaces) {
203+
validate_storage();
204+
}
205+
}
206+
207+
std::vector<std::string> ResourceManager::state_interface_keys() const
208+
{
209+
std::vector<std::string> keys;
210+
for (const auto & item : resource_storage_->state_interface_map_) {
211+
keys.push_back(std::get<0>(item));
212+
}
213+
return keys;
214+
}
215+
216+
bool ResourceManager::state_interface_exists(const std::string & key) const
217+
{
218+
return resource_storage_->state_interface_map_.find(key) !=
219+
resource_storage_->state_interface_map_.end();
220+
}
221+
222+
std::vector<std::string> ResourceManager::command_interface_keys() const
223+
{
224+
std::vector<std::string> keys;
225+
for (const auto & item : resource_storage_->command_interface_map_) {
226+
keys.push_back(std::get<0>(item));
227+
}
228+
return keys;
229+
}
230+
231+
bool ResourceManager::command_interface_exists(const std::string & key) const
232+
{
233+
return resource_storage_->command_interface_map_.find(key) !=
234+
resource_storage_->command_interface_map_.end();
235+
}
236+
237+
size_t ResourceManager::actuator_interfaces_size() const
238+
{
239+
return resource_storage_->actuators_.size();
240+
}
241+
242+
size_t ResourceManager::sensor_interfaces_size() const
243+
{
244+
return resource_storage_->sensors_.size();
245+
}
246+
247+
size_t ResourceManager::system_interfaces_size() const
248+
{
249+
return resource_storage_->systems_.size();
250+
}
251+
} // namespace controller_manager

0 commit comments

Comments
 (0)