Skip to content

Commit e48546c

Browse files
committed
Issue-759: Adding cleanup service
1 parent 4794663 commit e48546c

File tree

9 files changed

+151
-0
lines changed

9 files changed

+151
-0
lines changed

Diff for: controller_manager/controller_manager/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
set_hardware_component_state,
2424
switch_controllers,
2525
unload_controller,
26+
cleanup_controller,
2627
)
2728

2829
__all__ = [
@@ -36,4 +37,5 @@
3637
"set_hardware_component_state",
3738
"switch_controllers",
3839
"unload_controller",
40+
"cleanup_controller",
3941
]

Diff for: controller_manager/controller_manager/controller_manager_services.py

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
SetHardwareComponentState,
2424
SwitchController,
2525
UnloadController,
26+
CleanupController,
2627
)
2728

2829
import rclpy
@@ -175,3 +176,11 @@ def unload_controller(node, controller_manager_name, controller_name, service_ti
175176
request,
176177
service_timeout,
177178
)
179+
180+
181+
def cleanup_controller(node, controller_manager_name, controller_name):
182+
request = CleanupController.Request()
183+
request.name = controller_name
184+
return service_caller(
185+
node, f"{controller_manager_name}/cleanup_controller", CleanupController, request
186+
)

Diff for: controller_manager/controller_manager/spawner.py

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
load_controller,
2929
switch_controllers,
3030
unload_controller,
31+
cleanup_controller,
3132
)
3233

3334
import rclpy
@@ -101,6 +102,7 @@ def wait_for_controller_manager(node, controller_manager, timeout_duration):
101102
f"{controller_manager}/reload_controller_libraries",
102103
f"{controller_manager}/switch_controller",
103104
f"{controller_manager}/unload_controller",
105+
f"{controller_manager}/cleanup_controller",
104106
)
105107

106108
# Wait for controller_manager

Diff for: controller_manager/include/controller_manager/controller_manager.hpp

+11
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "controller_manager_msgs/srv/set_hardware_component_state.hpp"
4040
#include "controller_manager_msgs/srv/switch_controller.hpp"
4141
#include "controller_manager_msgs/srv/unload_controller.hpp"
42+
#include "controller_manager_msgs/srv/cleanup_controller.hpp"
4243

4344
#include "diagnostic_updater/diagnostic_updater.hpp"
4445
#include "hardware_interface/handle.hpp"
@@ -107,6 +108,9 @@ class ControllerManager : public rclcpp::Node
107108
CONTROLLER_MANAGER_PUBLIC
108109
controller_interface::return_type unload_controller(const std::string & controller_name);
109110

111+
CONTROLLER_MANAGER_PUBLIC
112+
controller_interface::return_type cleanup_controller(const std::string & controller_name);
113+
110114
CONTROLLER_MANAGER_PUBLIC
111115
std::vector<ControllerSpec> get_loaded_controllers() const;
112116

@@ -296,6 +300,11 @@ class ControllerManager : public rclcpp::Node
296300
const std::shared_ptr<controller_manager_msgs::srv::UnloadController::Request> request,
297301
std::shared_ptr<controller_manager_msgs::srv::UnloadController::Response> response);
298302

303+
CONTROLLER_MANAGER_PUBLIC
304+
void cleanup_controller_service_cb(
305+
const std::shared_ptr<controller_manager_msgs::srv::CleanupController::Request> request,
306+
std::shared_ptr<controller_manager_msgs::srv::CleanupController::Response> response);
307+
299308
CONTROLLER_MANAGER_PUBLIC
300309
void list_controller_types_srv_cb(
301310
const std::shared_ptr<controller_manager_msgs::srv::ListControllerTypes::Request> request,
@@ -521,6 +530,8 @@ class ControllerManager : public rclcpp::Node
521530
switch_controller_service_;
522531
rclcpp::Service<controller_manager_msgs::srv::UnloadController>::SharedPtr
523532
unload_controller_service_;
533+
rclcpp::Service<controller_manager_msgs::srv::CleanupController>::SharedPtr
534+
cleanup_controller_service_;
524535

525536
rclcpp::Service<controller_manager_msgs::srv::ListHardwareComponents>::SharedPtr
526537
list_hardware_components_service_;

Diff for: controller_manager/src/controller_manager.cpp

+75
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,10 @@ void ControllerManager::init_services()
504504
"~/unload_controller",
505505
std::bind(&ControllerManager::unload_controller_service_cb, this, _1, _2), qos_services,
506506
best_effort_callback_group_);
507+
cleanup_controller_service_ = create_service<controller_manager_msgs::srv::CleanupController>(
508+
"~/cleanup_controller",
509+
std::bind(&ControllerManager::cleanup_controller_service_cb, this, _1, _2), qos_services,
510+
best_effort_callback_group_);
507511
list_hardware_components_service_ =
508512
create_service<controller_manager_msgs::srv::ListHardwareComponents>(
509513
"~/list_hardware_components",
@@ -664,6 +668,61 @@ controller_interface::return_type ControllerManager::unload_controller(
664668
return controller_interface::return_type::OK;
665669
}
666670

671+
controller_interface::return_type ControllerManager::cleanup_controller(
672+
const std::string & controller_name)
673+
{
674+
std::lock_guard<std::recursive_mutex> guard(rt_controllers_wrapper_.controllers_lock_);
675+
std::vector<ControllerSpec> & to = rt_controllers_wrapper_.get_unused_list(guard);
676+
const std::vector<ControllerSpec> & from = rt_controllers_wrapper_.get_updated_list(guard);
677+
678+
// Transfers the active controllers over, skipping the one to be removed and the active ones.
679+
to = from;
680+
681+
auto found_it = std::find_if(
682+
to.begin(), to.end(),
683+
std::bind(controller_name_compare, std::placeholders::_1, controller_name));
684+
if (found_it == to.end())
685+
{
686+
// Fails if we could not remove the controllers
687+
to.clear();
688+
RCLCPP_ERROR(
689+
get_logger(),
690+
"Could not clear controller with name '%s' because no controller with this name exists",
691+
controller_name.c_str());
692+
return controller_interface::return_type::ERROR;
693+
}
694+
695+
auto & controller = *found_it;
696+
697+
if (is_controller_active(*controller.c))
698+
{
699+
to.clear();
700+
RCLCPP_ERROR(
701+
get_logger(), "Could not clear controller with name '%s' because it is still active",
702+
controller_name.c_str());
703+
return controller_interface::return_type::ERROR;
704+
}
705+
706+
RCLCPP_DEBUG(get_logger(), "Cleanup controller");
707+
// TODO(destogl): remove reference interface if chainable; i.e., add a separate method for
708+
// cleaning-up controllers?
709+
controller.c->get_node()->cleanup();
710+
executor_->remove_node(controller.c->get_node()->get_node_base_interface());
711+
to.erase(found_it);
712+
713+
// Destroys the old controllers list when the realtime thread is finished with it.
714+
RCLCPP_DEBUG(get_logger(), "Realtime switches over to new controller list");
715+
rt_controllers_wrapper_.switch_updated_list(guard);
716+
std::vector<ControllerSpec> & new_unused_list = rt_controllers_wrapper_.get_unused_list(guard);
717+
RCLCPP_DEBUG(get_logger(), "Destruct controller");
718+
new_unused_list.clear();
719+
RCLCPP_DEBUG(get_logger(), "Destruct controller finished");
720+
721+
RCLCPP_DEBUG(get_logger(), "Successfully cleaned controller '%s'", controller_name.c_str());
722+
723+
return controller_interface::return_type::OK;
724+
}
725+
667726
std::vector<ControllerSpec> ControllerManager::get_loaded_controllers() const
668727
{
669728
std::lock_guard<std::recursive_mutex> guard(rt_controllers_wrapper_.controllers_lock_);
@@ -1878,6 +1937,22 @@ void ControllerManager::unload_controller_service_cb(
18781937
get_logger(), "unloading service finished for controller '%s' ", request->name.c_str());
18791938
}
18801939

1940+
void ControllerManager::cleanup_controller_service_cb(
1941+
const std::shared_ptr<controller_manager_msgs::srv::CleanupController::Request> request,
1942+
std::shared_ptr<controller_manager_msgs::srv::CleanupController::Response> response)
1943+
{
1944+
// lock services
1945+
RCLCPP_DEBUG(
1946+
get_logger(), "cleanup service called for controller '%s' ", request->name.c_str());
1947+
std::lock_guard<std::mutex> guard(services_lock_);
1948+
RCLCPP_DEBUG(get_logger(), "cleanup service locked");
1949+
1950+
response->ok = cleanup_controller(request->name) == controller_interface::return_type::OK;
1951+
1952+
RCLCPP_DEBUG(
1953+
get_logger(), "cleanup service finished for controller '%s' ", request->name.c_str());
1954+
}
1955+
18811956
void ControllerManager::list_hardware_components_srv_cb(
18821957
const std::shared_ptr<controller_manager_msgs::srv::ListHardwareComponents::Request>,
18831958
std::shared_ptr<controller_manager_msgs::srv::ListHardwareComponents::Response> response)

Diff for: controller_manager_msgs/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ set(srv_files
2323
srv/SetHardwareComponentState.srv
2424
srv/SwitchController.srv
2525
srv/UnloadController.srv
26+
srv/CleanupController.srv
2627
)
2728

2829
rosidl_generate_interfaces(${PROJECT_NAME}

Diff for: controller_manager_msgs/srv/CleanupController.srv

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# The CleanupController service allows you to cleanup a single controller
2+
# from controller_manager
3+
4+
# To cleanup a controller, specify the "name" of the controller.
5+
# The return value "ok" indicates if the controller was successfully
6+
# cleaned up or not
7+
8+
string name
9+
---
10+
bool ok
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2020 PAL Robotics S.L.
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+
from controller_manager import cleanup_controller
16+
17+
from ros2cli.node.direct import add_arguments
18+
from ros2cli.node.strategy import NodeStrategy
19+
from ros2cli.verb import VerbExtension
20+
21+
from ros2controlcli.api import add_controller_mgr_parsers, LoadedControllerNameCompleter
22+
23+
24+
class CleanupControllerVerb(VerbExtension):
25+
"""Cleanup a controller in a controller manager."""
26+
27+
def add_arguments(self, parser, cli_name):
28+
add_arguments(parser)
29+
arg = parser.add_argument("controller_name", help="Name of the controller")
30+
arg.completer = LoadedControllerNameCompleter()
31+
add_controller_mgr_parsers(parser)
32+
33+
def main(self, *, args):
34+
with NodeStrategy(args) as node:
35+
response = cleanup_controller(node, args.controller_manager, args.controller_name)
36+
if not response.ok:
37+
return "Error cleanup controllers, check controller_manager logs"
38+
39+
print(f"Successfully cleaned up controller {args.controller_name}")
40+
return 0

Diff for: ros2controlcli/setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
ros2controlcli.verb.set_controller_state:SetControllerStateVerb",
6565
"switch_controllers = ros2controlcli.verb.switch_controllers:SwitchControllersVerb",
6666
"unload_controller = ros2controlcli.verb.unload_controller:UnloadControllerVerb",
67+
"cleanup_controller = ros2controlcli.verb.cleanup_controller:CleanupControllerVerb",
6768
],
6869
},
6970
)

0 commit comments

Comments
 (0)