Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
80cd7bb
Towards selective starting and stoping of hardware components. Cleani…
destogl Jul 10, 2021
dcfa12c
Move Lifecycle of hardware componnet to the bottom for better overview.
destogl Aug 27, 2021
4557a30
Use the same nomenclature as for controllers. 'start' -> 'activate'; …
destogl Jul 17, 2021
85afb4b
Add selective starting and stopping of hardware resources.
destogl Jul 17, 2021
ae50446
Use lifecycle_msgs/State in ListHardwareCompoents for state represent…
destogl Aug 27, 2021
6c9ae01
Simplify repeatable code in methods.
destogl Aug 29, 2021
eb1ce5e
Add HW shutdown structure into ResouceManager.
destogl Aug 29, 2021
36e1c4a
Fill out service callback in CM and add parameter for auto-configure.
destogl Aug 29, 2021
ef7ab05
Move claimed_command_itf_map to ResourceStorage from ResourceManager.
destogl Aug 29, 2021
802c48a
Do not automatically configure hardware in RM.
destogl Aug 29, 2021
5c30673
Lifecycle and claiming in Resource Manager is working.
destogl Aug 31, 2021
655e8a0
Extend controller manger to support HW lifecycle.
destogl Sep 1, 2021
315cc14
Add also available and claimed status into list compoentns service ou…
destogl Sep 7, 2021
f9687bc
Add SetHardwareComponentState service.
destogl Sep 17, 2021
a479ff3
Make all output in services debug-output.
destogl Sep 20, 2021
354b850
Remove specific services for hardware lifecycle management and leave …
destogl Nov 3, 2021
af76420
fix typo
destogl Nov 3, 2021
e9c18bc
Fix formatting.
destogl Nov 3, 2021
8213312
Make init_resource_manager less stateful.
destogl Nov 27, 2021
0c64f00
Supress compile warning on unused test constants.
destogl Nov 27, 2021
184403c
Fix formatting.
destogl Nov 27, 2021
6c11ff8
Address comments from review.
destogl Dec 1, 2021
48d737d
Merge branch 'master' into services-for-hardware-lifecycle
destogl Dec 3, 2021
4f24378
Fixup generic system tests.
destogl Dec 3, 2021
4f0b031
Optimize tests of generic system per review comment.
destogl Dec 3, 2021
91001c7
Optimize tests of RM
destogl Dec 3, 2021
8d9796b
Correct formatting.
destogl Dec 3, 2021
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
8 changes: 8 additions & 0 deletions controller_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ if(BUILD_TESTING)
target_include_directories(test_spawner_unspawner PRIVATE include)
target_link_libraries(test_spawner_unspawner controller_manager test_controller)
ament_target_dependencies(test_spawner_unspawner ros2_control_test_assets)

ament_add_gmock(
test_hardware_management_srvs
test/test_hardware_management_srvs.cpp
)
target_include_directories(test_hardware_management_srvs PRIVATE include)
target_link_libraries(test_hardware_management_srvs controller_manager test_controller)
ament_target_dependencies(test_hardware_management_srvs ros2_control_test_assets)
endif()

# Install Python modules
Expand Down
101 changes: 93 additions & 8 deletions controller_manager/src/controller_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
#include <vector>

#include "controller_interface/controller_interface.hpp"
#include "controller_manager_msgs/msg/hardware_components_state.hpp"
#include "hardware_interface/types/lifecycle_state_names.hpp"
#include "lifecycle_msgs/msg/state.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/state.hpp"

namespace controller_manager
{
Expand Down Expand Up @@ -74,10 +77,7 @@ ControllerManager::ControllerManager(
throw std::runtime_error("Unable to initialize resource manager, no robot description found.");
}

resource_manager_->load_urdf(robot_description);

// TODO(all): Here we should start only "auto-start" resources
resource_manager_->start_components();
init_resource_manager(robot_description);

init_services();
}
Expand All @@ -95,6 +95,32 @@ ControllerManager::ControllerManager(
init_services();
}

void ControllerManager::init_resource_manager(const std::string & robot_description)
{
// TODO(destogl): manage this when there is an error - CM should not die because URDF is wrong...
resource_manager_->load_urdf(robot_description);

using lifecycle_msgs::msg::State;

std::vector<std::string> autoconfigure_components = {""};
get_parameter("autoconfigure_components", autoconfigure_components);
rclcpp_lifecycle::State inactive_state(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rclcpp_lifecycle::State inactive_state(
const rclcpp_lifecycle::State inactive_state(

why do we even have to write constants like this? there should be some global consts available like rclcpp_lifecycle::State::Inactive

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the upstream library does not defines standard states fully, at least not with the ID or names. We could create defines for this or should we directly try to add this into rclcpp?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also it is not possible to set this const because of the underlying logic where no copy of state is done but in place changes are added if ID is not provided... Will comment more in corresponding PR.

State::PRIMARY_STATE_INACTIVE, hardware_interface::lifecycle_state_names::INACTIVE);
for (const auto & component : autoconfigure_components)
{
resource_manager_->set_component_state(component, inactive_state);
}

std::vector<std::string> autostart_components = {""};
get_parameter("autostart_components", autostart_components);
rclcpp_lifecycle::State active_state(
State::PRIMARY_STATE_ACTIVE, hardware_interface::lifecycle_state_names::ACTIVE);
for (const auto & component : autostart_components)
{
resource_manager_->set_component_state(component, active_state);
}
}

void ControllerManager::init_services()
{
// TODO(anyone): Due to issues with the MutliThreadedExecutor, this control loop does not rely on
Expand Down Expand Up @@ -444,7 +470,7 @@ controller_interface::return_type ControllerManager::switch_controller(
std::vector<std::string> command_interface_names = {};
if (command_interface_config.type == controller_interface::interface_configuration_type::ALL)
{
command_interface_names = resource_manager_->command_interface_keys();
command_interface_names = resource_manager_->available_command_interfaces();
}
if (
command_interface_config.type ==
Expand Down Expand Up @@ -590,7 +616,7 @@ controller_interface::return_type ControllerManager::switch_controller(
auto command_interface_config = controller.c->command_interface_configuration();
if (command_interface_config.type == controller_interface::interface_configuration_type::ALL)
{
controller.info.claimed_interfaces = resource_manager_->command_interface_keys();
controller.info.claimed_interfaces = resource_manager_->available_command_interfaces();
}
if (
command_interface_config.type ==
Expand Down Expand Up @@ -758,7 +784,7 @@ void ControllerManager::start_controllers()
std::vector<std::string> command_interface_names = {};
if (command_interface_config.type == controller_interface::interface_configuration_type::ALL)
{
command_interface_names = resource_manager_->command_interface_keys();
command_interface_names = resource_manager_->available_command_interfaces();
}
if (
command_interface_config.type ==
Expand Down Expand Up @@ -802,7 +828,7 @@ void ControllerManager::start_controllers()
std::vector<std::string> state_interface_names = {};
if (state_interface_config.type == controller_interface::interface_configuration_type::ALL)
{
state_interface_names = resource_manager_->state_interface_keys();
state_interface_names = resource_manager_->available_state_interfaces();
}
if (
state_interface_config.type == controller_interface::interface_configuration_type::INDIVIDUAL)
Expand Down Expand Up @@ -1155,6 +1181,42 @@ void ControllerManager::list_hardware_components_srv_cb(
std::lock_guard<std::mutex> guard(services_lock_);
RCLCPP_DEBUG(get_logger(), "list hardware components service locked");

auto hw_components_info = resource_manager_->get_components_status();

response->component.reserve(hw_components_info.size());

for (auto it = hw_components_info.begin(); it != hw_components_info.end(); ++it)
{
auto component = controller_manager_msgs::msg::HardwareComponentState();
component.name = it->second.name;
component.type = it->second.type;
component.class_type = it->second.class_type;
component.state.id = it->second.state.id();
component.state.label = it->second.state.label();

component.command_interfaces.reserve(it->second.command_interfaces.size());
for (const auto & interface : it->second.command_interfaces)
{
controller_manager_msgs::msg::HardwareInterface hwi;
hwi.name = interface;
hwi.is_available = resource_manager_->command_interface_is_available(interface);
hwi.is_claimed = resource_manager_->command_interface_is_claimed(interface);
component.command_interfaces.push_back(hwi);
}

component.state_interfaces.reserve(it->second.state_interfaces.size());
for (const auto & interface : it->second.state_interfaces)
{
controller_manager_msgs::msg::HardwareInterface hwi;
hwi.name = interface;
hwi.is_available = resource_manager_->state_interface_is_available(interface);
hwi.is_claimed = false;
component.state_interfaces.push_back(hwi);
}

response->component.push_back(component);
}

RCLCPP_DEBUG(get_logger(), "list hardware components service finished");
}

Expand All @@ -1171,6 +1233,7 @@ void ControllerManager::list_hardware_interfaces_srv_cb(
{
controller_manager_msgs::msg::HardwareInterface hwi;
hwi.name = state_interface_name;
hwi.is_available = resource_manager_->state_interface_is_available(state_interface_name);
hwi.is_claimed = false;
response->state_interfaces.push_back(hwi);
}
Expand All @@ -1179,6 +1242,7 @@ void ControllerManager::list_hardware_interfaces_srv_cb(
{
controller_manager_msgs::msg::HardwareInterface hwi;
hwi.name = command_interface_name;
hwi.is_available = resource_manager_->command_interface_is_available(command_interface_name);
hwi.is_claimed = resource_manager_->command_interface_is_claimed(command_interface_name);
response->command_interfaces.push_back(hwi);
}
Expand All @@ -1196,6 +1260,27 @@ void ControllerManager::set_hardware_component_state_srv_cb(

RCLCPP_DEBUG(get_logger(), "set hardware component state '%s'", request->name.c_str());

auto hw_components_info = resource_manager_->get_components_status();
if (hw_components_info.find(request->name) != hw_components_info.end())
{
rclcpp_lifecycle::State target_state(
request->target_state.id,
// the ternary operator is needed because label in State constructor cannot be an empty string
request->target_state.label.empty() ? "-" : request->target_state.label);
response->ok =
(resource_manager_->set_component_state(request->name, target_state) ==
hardware_interface::return_type::OK);
hw_components_info = resource_manager_->get_components_status();
response->state.id = hw_components_info[request->name].state.id();
response->state.label = hw_components_info[request->name].state.label();
}
else
{
RCLCPP_ERROR(
get_logger(), "hardware component with name '%s' does not exist", request->name.c_str());
response->ok = false;
}

RCLCPP_DEBUG(get_logger(), "set hardware component state service finished");
}

Expand Down
65 changes: 63 additions & 2 deletions controller_manager/test/controller_manager_test_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
constexpr auto STRICT = controller_manager_msgs::srv::SwitchController::Request::STRICT;
constexpr auto BEST_EFFORT = controller_manager_msgs::srv::SwitchController::Request::BEST_EFFORT;

const auto TEST_CM_NAME = "test_controller_manager";

class ControllerManagerFixture : public ::testing::Test
{
public:
Expand All @@ -50,8 +52,8 @@ class ControllerManagerFixture : public ::testing::Test
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
cm_ = std::make_shared<controller_manager::ControllerManager>(
std::make_unique<hardware_interface::ResourceManager>(
ros2_control_test_assets::minimal_robot_urdf),
executor_, "test_controller_manager");
ros2_control_test_assets::minimal_robot_urdf, true, true),
executor_, TEST_CM_NAME);
run_updater_ = false;
}

Expand Down Expand Up @@ -85,6 +87,65 @@ class ControllerManagerFixture : public ::testing::Test
bool run_updater_;
};

class TestControllerManagerSrvs : public ControllerManagerFixture
{
public:
TestControllerManagerSrvs() {}

void SetUp() override
{
ControllerManagerFixture::SetUp();
SetUpSrvsCMExecutor();
}

void SetUpSrvsCMExecutor()
{
update_timer_ = cm_->create_wall_timer(std::chrono::milliseconds(10), [&]() {
cm_->read();
cm_->update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01));
cm_->write();
});

executor_->add_node(cm_);

executor_spin_future_ = std::async(std::launch::async, [this]() -> void { executor_->spin(); });
// This sleep is needed to prevent a too fast test from ending before the
// executor has began to spin, which causes it to hang
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

// FIXME: This can be deleted!
void TearDown() override { executor_->cancel(); }

template <typename T>
std::shared_ptr<typename T::Response> call_service_and_wait(
rclcpp::Client<T> & client, std::shared_ptr<typename T::Request> request,
rclcpp::Executor & service_executor, bool update_controller_while_spinning = false)
{
EXPECT_TRUE(client.wait_for_service(std::chrono::milliseconds(500)));
auto result = client.async_send_request(request);
// Wait for the result.
if (update_controller_while_spinning)
{
while (service_executor.spin_until_future_complete(result, std::chrono::milliseconds(50)) !=
rclcpp::FutureReturnCode::SUCCESS)
{
cm_->update(rclcpp::Time(0), rclcpp::Duration::from_seconds(0.01));
}
}
else
{
EXPECT_EQ(
service_executor.spin_until_future_complete(result), rclcpp::FutureReturnCode::SUCCESS);
}
return result.get();
}

protected:
rclcpp::TimerBase::SharedPtr update_timer_;
std::future<void> executor_spin_future_;
};

class ControllerManagerRunner
{
public:
Expand Down
Loading