Skip to content

Commit 96098c9

Browse files
authored
Merge branch 'master' into feat/interface/remapping
2 parents b33f656 + a1ad523 commit 96098c9

File tree

3 files changed

+74
-17
lines changed

3 files changed

+74
-17
lines changed

controller_manager/include/controller_manager/controller_manager.hpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -583,14 +583,25 @@ class ControllerManager : public rclcpp::Node
583583

584584
struct SwitchParams
585585
{
586-
bool do_switch = {false};
587-
bool started = {false};
588-
rclcpp::Time init_time = {rclcpp::Time::max()};
586+
void reset()
587+
{
588+
do_switch = false;
589+
started = false;
590+
strictness = 0;
591+
activate_asap = false;
592+
}
593+
594+
bool do_switch;
595+
bool started;
589596

590597
// Switch options
591-
int strictness = {0};
592-
bool activate_asap = {false};
593-
rclcpp::Duration timeout = rclcpp::Duration{0, 0};
598+
int strictness;
599+
bool activate_asap;
600+
std::chrono::nanoseconds timeout;
601+
602+
// conditional variable and mutex to wait for the switch to complete
603+
std::condition_variable cv;
604+
std::mutex mutex;
594605
};
595606

596607
SwitchParams switch_params_;

controller_manager/src/controller_manager.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,7 @@ controller_interface::return_type ControllerManager::configure_controller(
857857

858858
void ControllerManager::clear_requests()
859859
{
860+
switch_params_.do_switch = false;
860861
deactivate_request_.clear();
861862
activate_request_.clear();
862863
// Set these interfaces as unavailable when clearing requests to avoid leaving them in available
@@ -886,7 +887,8 @@ controller_interface::return_type ControllerManager::switch_controller(
886887
return controller_interface::return_type::ERROR;
887888
}
888889

889-
switch_params_ = SwitchParams();
890+
// reset the switch param internal variables
891+
switch_params_.reset();
890892

891893
if (!deactivate_request_.empty() || !activate_request_.empty())
892894
{
@@ -1307,19 +1309,27 @@ controller_interface::return_type ControllerManager::switch_controller(
13071309
// start the atomic controller switching
13081310
switch_params_.strictness = strictness;
13091311
switch_params_.activate_asap = activate_asap;
1310-
switch_params_.init_time = rclcpp::Clock().now();
1311-
switch_params_.timeout = timeout;
1312+
if (timeout == rclcpp::Duration{0, 0})
1313+
{
1314+
RCLCPP_INFO_ONCE(get_logger(), "Switch controller timeout is set to 0, using default 1s!");
1315+
switch_params_.timeout = std::chrono::nanoseconds(1'000'000'000);
1316+
}
1317+
else
1318+
{
1319+
switch_params_.timeout = timeout.to_chrono<std::chrono::nanoseconds>();
1320+
}
13121321
switch_params_.do_switch = true;
1313-
13141322
// wait until switch is finished
13151323
RCLCPP_DEBUG(get_logger(), "Requested atomic controller switch from realtime loop");
1316-
while (rclcpp::ok() && switch_params_.do_switch)
1324+
std::unique_lock<std::mutex> switch_params_guard(switch_params_.mutex, std::defer_lock);
1325+
if (!switch_params_.cv.wait_for(
1326+
switch_params_guard, switch_params_.timeout, [this] { return !switch_params_.do_switch; }))
13171327
{
1318-
if (!rclcpp::ok())
1319-
{
1320-
return controller_interface::return_type::ERROR;
1321-
}
1322-
std::this_thread::sleep_for(std::chrono::microseconds(100));
1328+
RCLCPP_ERROR(
1329+
get_logger(), "Switch controller timed out after %f seconds!",
1330+
static_cast<double>(switch_params_.timeout.count()) / 1e9);
1331+
clear_requests();
1332+
return controller_interface::return_type::ERROR;
13231333
}
13241334

13251335
// copy the controllers spec from the used to the unused list
@@ -2155,6 +2165,12 @@ void ControllerManager::read(const rclcpp::Time & time, const rclcpp::Duration &
21552165

21562166
void ControllerManager::manage_switch()
21572167
{
2168+
std::unique_lock<std::mutex> guard(switch_params_.mutex, std::try_to_lock);
2169+
if (!guard.owns_lock())
2170+
{
2171+
RCLCPP_DEBUG(get_logger(), "Unable to lock switch mutex. Retrying in next cycle.");
2172+
return;
2173+
}
21582174
// Ask hardware interfaces to change mode
21592175
if (!resource_manager_->perform_command_mode_switch(
21602176
activate_command_interface_request_, deactivate_command_interface_request_))
@@ -2183,6 +2199,7 @@ void ControllerManager::manage_switch()
21832199

21842200
// All controllers switched --> switching done
21852201
switch_params_.do_switch = false;
2202+
switch_params_.cv.notify_all();
21862203
}
21872204

21882205
controller_interface::return_type ControllerManager::update(

controller_manager/test/test_controller_manager_srvs.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,38 @@ TEST_F(TestControllerManagerSrvs, list_controllers_srv)
169169
"joint3/acceleration", "joint3/position", "joint3/velocity", "sensor1/velocity",
170170
"joint1/effort"));
171171

172+
// Switch with a very low timeout 1 ns and it should fail as there is no enough time to switch
173+
ASSERT_EQ(
174+
controller_interface::return_type::ERROR,
175+
cm_->switch_controller(
176+
{}, {test_controller::TEST_CONTROLLER_NAME},
177+
controller_manager_msgs::srv::SwitchController::Request::STRICT, true,
178+
rclcpp::Duration(0, 1)));
179+
180+
result = call_service_and_wait(*client, request, srv_executor);
181+
ASSERT_EQ(1u, result->controller.size());
182+
ASSERT_EQ("active", result->controller[0].state);
183+
ASSERT_THAT(
184+
result->controller[0].claimed_interfaces,
185+
UnorderedElementsAre(
186+
"joint2/velocity", "joint3/velocity", "joint2/max_acceleration", "configuration/max_tcp_jerk",
187+
"joint1/position", "joint1/max_velocity"));
188+
ASSERT_THAT(
189+
result->controller[0].required_command_interfaces,
190+
UnorderedElementsAre(
191+
"configuration/max_tcp_jerk", "joint1/max_velocity", "joint1/position",
192+
"joint2/max_acceleration", "joint2/velocity", "joint3/velocity"));
193+
ASSERT_THAT(
194+
result->controller[0].required_state_interfaces,
195+
UnorderedElementsAre(
196+
"configuration/max_tcp_jerk", "joint1/position", "joint1/some_unlisted_interface",
197+
"joint1/velocity", "joint2/acceleration", "joint2/position", "joint2/velocity",
198+
"joint3/acceleration", "joint3/position", "joint3/velocity", "sensor1/velocity"));
199+
200+
// Try again with higher timeout
172201
cm_->switch_controller(
173202
{}, {test_controller::TEST_CONTROLLER_NAME},
174-
controller_manager_msgs::srv::SwitchController::Request::STRICT, true, rclcpp::Duration(0, 0));
203+
controller_manager_msgs::srv::SwitchController::Request::STRICT, true, rclcpp::Duration(3, 0));
175204

176205
result = call_service_and_wait(*client, request, srv_executor);
177206
ASSERT_EQ(1u, result->controller.size());

0 commit comments

Comments
 (0)