Skip to content

Commit 369ba8a

Browse files
mergify[bot]saikishorchristophfroehlich
authored
Refactor spawner to be able to reuse code for ros2controlcli (backport #1661) (#1696)
* Refactor spawner to be able to reuse code for ros2controlcli (#1661) (cherry picked from commit 0631e3e) # Conflicts: # controller_manager/controller_manager/spawner.py # controller_manager/test/test_spawner_unspawner.cpp * [Iron] Fix conflicts of 1661 backport (#1736) * Fix conflicts * added controller_type parameter setting to the spawner --------- Co-authored-by: Sai Kishor Kothakota <[email protected]> Co-authored-by: Christoph Fröhlich <[email protected]>
1 parent 8534e6d commit 369ba8a

File tree

7 files changed

+134
-122
lines changed

7 files changed

+134
-122
lines changed

controller_manager/controller_manager/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
set_hardware_component_state,
2424
switch_controllers,
2525
unload_controller,
26+
get_parameter_from_param_file,
27+
set_controller_parameters,
28+
set_controller_parameters_from_param_file,
29+
bcolors,
2630
)
2731

2832
__all__ = [
@@ -36,4 +40,8 @@
3640
"set_hardware_component_state",
3741
"switch_controllers",
3842
"unload_controller",
43+
"get_parameter_from_param_file",
44+
"set_controller_parameters",
45+
"set_controller_parameters_from_param_file",
46+
"bcolors",
3947
]

controller_manager/controller_manager/controller_manager_services.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,29 @@
2626
)
2727

2828
import rclpy
29+
import yaml
30+
from rcl_interfaces.msg import Parameter
31+
32+
# @note: The versions conditioning is added here to support the source-compatibility with Humble
33+
# The `get_parameter_value` function is moved to `rclpy.parameter` module from `ros2param.api` module from version 3.6.0
34+
try:
35+
from rclpy.parameter import get_parameter_value
36+
except ImportError:
37+
from ros2param.api import get_parameter_value
38+
from ros2param.api import call_set_parameters
39+
40+
41+
# from https://stackoverflow.com/a/287944
42+
class bcolors:
43+
MAGENTA = "\033[95m"
44+
OKBLUE = "\033[94m"
45+
OKCYAN = "\033[96m"
46+
OKGREEN = "\033[92m"
47+
WARNING = "\033[93m"
48+
FAIL = "\033[91m"
49+
ENDC = "\033[0m"
50+
BOLD = "\033[1m"
51+
UNDERLINE = "\033[4m"
2952

3053

3154
class ServiceNotFoundError(Exception):
@@ -220,3 +243,84 @@ def unload_controller(node, controller_manager_name, controller_name, service_ti
220243
request,
221244
service_timeout,
222245
)
246+
247+
248+
def get_parameter_from_param_file(controller_name, namespace, parameter_file, parameter_name):
249+
with open(parameter_file) as f:
250+
namespaced_controller = (
251+
controller_name if namespace == "/" else f"{namespace}/{controller_name}"
252+
)
253+
parameters = yaml.safe_load(f)
254+
if namespaced_controller in parameters:
255+
value = parameters[namespaced_controller]
256+
if not isinstance(value, dict) or "ros__parameters" not in value:
257+
raise RuntimeError(
258+
f"YAML file : {parameter_file} is not a valid ROS parameter file for controller : {namespaced_controller}"
259+
)
260+
if parameter_name in parameters[namespaced_controller]["ros__parameters"]:
261+
return parameters[namespaced_controller]["ros__parameters"][parameter_name]
262+
else:
263+
return None
264+
else:
265+
return None
266+
267+
268+
def set_controller_parameters(
269+
node, controller_manager_name, controller_name, parameter_name, parameter_value
270+
):
271+
parameter = Parameter()
272+
parameter.name = controller_name + "." + parameter_name
273+
parameter_string = str(parameter_value)
274+
parameter.value = get_parameter_value(string_value=parameter_string)
275+
276+
response = call_set_parameters(
277+
node=node, node_name=controller_manager_name, parameters=[parameter]
278+
)
279+
assert len(response.results) == 1
280+
result = response.results[0]
281+
if result.successful:
282+
node.get_logger().info(
283+
bcolors.OKCYAN
284+
+ 'Setting controller param "'
285+
+ parameter_name
286+
+ '" to "'
287+
+ parameter_string
288+
+ '" for '
289+
+ bcolors.BOLD
290+
+ controller_name
291+
+ bcolors.ENDC
292+
)
293+
else:
294+
node.get_logger().fatal(
295+
bcolors.FAIL
296+
+ 'Could not set controller param "'
297+
+ parameter_name
298+
+ '" to "'
299+
+ parameter_string
300+
+ '" for '
301+
+ bcolors.BOLD
302+
+ controller_name
303+
+ bcolors.ENDC
304+
)
305+
return False
306+
return True
307+
308+
309+
def set_controller_parameters_from_param_file(
310+
node, controller_manager_name, controller_name, parameter_file, namespace=None
311+
):
312+
if parameter_file:
313+
spawner_namespace = namespace if namespace else node.get_namespace()
314+
set_controller_parameters(
315+
node, controller_manager_name, controller_name, "param_file", parameter_file
316+
)
317+
318+
controller_type = get_parameter_from_param_file(
319+
controller_name, spawner_namespace, parameter_file, "type"
320+
)
321+
if controller_type:
322+
if not set_controller_parameters(
323+
node, controller_manager_name, controller_name, "type", controller_type
324+
):
325+
return False
326+
return True

controller_manager/controller_manager/hardware_spawner.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from controller_manager import (
2020
list_hardware_components,
2121
set_hardware_component_state,
22+
bcolors,
2223
)
2324
from controller_manager.controller_manager_services import ServiceNotFoundError
2425

@@ -28,19 +29,6 @@
2829
from rclpy.signals import SignalHandlerOptions
2930

3031

31-
# from https://stackoverflow.com/a/287944
32-
class bcolors:
33-
HEADER = "\033[95m"
34-
OKBLUE = "\033[94m"
35-
OKCYAN = "\033[96m"
36-
OKGREEN = "\033[92m"
37-
WARNING = "\033[93m"
38-
FAIL = "\033[91m"
39-
ENDC = "\033[0m"
40-
BOLD = "\033[1m"
41-
UNDERLINE = "\033[4m"
42-
43-
4432
def first_match(iterable, predicate):
4533
return next((n for n in iterable if predicate(n)), None)
4634

controller_manager/controller_manager/spawner.py

Lines changed: 18 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,22 @@
1919
import sys
2020
import time
2121
import warnings
22-
import yaml
2322

2423
from controller_manager import (
2524
configure_controller,
2625
list_controllers,
2726
load_controller,
2827
switch_controllers,
2928
unload_controller,
29+
set_controller_parameters,
30+
set_controller_parameters_from_param_file,
31+
bcolors,
3032
)
3133
from controller_manager.controller_manager_services import ServiceNotFoundError
3234

3335
import rclpy
34-
from rcl_interfaces.msg import Parameter
3536
from rclpy.node import Node
36-
from rclpy.parameter import get_parameter_value
3737
from rclpy.signals import SignalHandlerOptions
38-
from ros2param.api import call_set_parameters
39-
40-
# from https://stackoverflow.com/a/287944
41-
42-
43-
class bcolors:
44-
MAGENTA = "\033[95m"
45-
OKBLUE = "\033[94m"
46-
OKCYAN = "\033[96m"
47-
OKGREEN = "\033[92m"
48-
WARNING = "\033[93m"
49-
FAIL = "\033[91m"
50-
ENDC = "\033[0m"
51-
BOLD = "\033[1m"
52-
UNDERLINE = "\033[4m"
5338

5439

5540
def first_match(iterable, predicate):
@@ -81,24 +66,6 @@ def is_controller_loaded(node, controller_manager, controller_name, service_time
8166
return any(c.name == controller_name for c in controllers)
8267

8368

84-
def get_parameter_from_param_file(controller_name, namespace, parameter_file, parameter_name):
85-
with open(parameter_file) as f:
86-
namespaced_controller = (
87-
controller_name if namespace == "/" else f"{namespace}/{controller_name}"
88-
)
89-
parameters = yaml.safe_load(f)
90-
if namespaced_controller in parameters:
91-
value = parameters[namespaced_controller]
92-
if not isinstance(value, dict) or "ros__parameters" not in value:
93-
raise RuntimeError(
94-
f"YAML file : {parameter_file} is not a valid ROS parameter file for controller : {namespaced_controller}"
95-
)
96-
if parameter_name in parameters[namespaced_controller]["ros__parameters"]:
97-
return parameters[namespaced_controller]["ros__parameters"][parameter_name]
98-
else:
99-
return None
100-
101-
10269
def main(args=None):
10370
rclpy.init(args=args, signal_handler_options=SignalHandlerOptions.NO)
10471
parser = argparse.ArgumentParser()
@@ -199,75 +166,23 @@ def main(args=None):
199166
+ bcolors.ENDC
200167
)
201168
else:
202-
controller_type = (
203-
args.controller_type
204-
if param_file is None
205-
else get_parameter_from_param_file(
206-
controller_name, spawner_namespace, param_file, "type"
207-
)
208-
)
209-
if controller_type:
210-
parameter = Parameter()
211-
parameter.name = controller_name + ".type"
212-
parameter.value = get_parameter_value(string_value=controller_type)
213-
214-
response = call_set_parameters(
215-
node=node, node_name=controller_manager_name, parameters=[parameter]
216-
)
217-
assert len(response.results) == 1
218-
result = response.results[0]
219-
if result.successful:
220-
node.get_logger().info(
221-
bcolors.OKCYAN
222-
+ 'Set controller type to "'
223-
+ controller_type
224-
+ '" for '
225-
+ bcolors.BOLD
226-
+ controller_name
227-
+ bcolors.ENDC
228-
)
229-
else:
230-
node.get_logger().fatal(
231-
bcolors.FAIL
232-
+ 'Could not set controller type to "'
233-
+ controller_type
234-
+ '" for '
235-
+ bcolors.BOLD
236-
+ controller_name
237-
+ bcolors.ENDC
238-
)
169+
if args.controller_type:
170+
if not set_controller_parameters(
171+
node,
172+
controller_manager_name,
173+
controller_name,
174+
"type",
175+
args.controller_type,
176+
):
239177
return 1
240-
241178
if param_file:
242-
parameter = Parameter()
243-
parameter.name = controller_name + ".params_file"
244-
parameter.value = get_parameter_value(string_value=param_file)
245-
246-
response = call_set_parameters(
247-
node=node, node_name=controller_manager_name, parameters=[parameter]
248-
)
249-
assert len(response.results) == 1
250-
result = response.results[0]
251-
if result.successful:
252-
node.get_logger().info(
253-
bcolors.OKCYAN
254-
+ 'Set controller params file to "'
255-
+ param_file
256-
+ '" for '
257-
+ bcolors.BOLD
258-
+ controller_name
259-
+ bcolors.ENDC
260-
)
261-
else:
262-
node.get_logger().fatal(
263-
bcolors.FAIL
264-
+ 'Could not set controller params file to "'
265-
+ param_file
266-
+ '" for '
267-
+ bcolors.BOLD
268-
+ controller_name
269-
+ bcolors.ENDC
270-
)
179+
if not set_controller_parameters_from_param_file(
180+
node,
181+
controller_manager_name,
182+
controller_name,
183+
param_file,
184+
spawner_namespace,
185+
):
271186
return 1
272187

273188
ret = load_controller(node, controller_manager_name, controller_name)

ros2controlcli/ros2controlcli/verb/list_controllers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from controller_manager import list_controllers
16-
from controller_manager.spawner import bcolors
15+
from controller_manager import list_controllers, bcolors
1716

1817
from ros2cli.node.direct import add_arguments
1918
from ros2cli.node.strategy import NodeStrategy

ros2controlcli/ros2controlcli/verb/list_hardware_components.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from controller_manager import list_hardware_components
16-
from controller_manager.spawner import bcolors
15+
from controller_manager import list_hardware_components, bcolors
1716

1817
from lifecycle_msgs.msg import State
1918

ros2controlcli/ros2controlcli/verb/list_hardware_interfaces.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from controller_manager import list_hardware_interfaces
16-
from controller_manager.spawner import bcolors
15+
from controller_manager import list_hardware_interfaces, bcolors
1716

1817
from ros2cli.node.direct import add_arguments
1918
from ros2cli.node.strategy import NodeStrategy

0 commit comments

Comments
 (0)