1313# limitations under the License.
1414
1515
16- from rcl_interfaces .srv import ListParameters
1716import rclpy
17+ from rclpy .parameter import parameter_value_to_python
18+ from rclpy .parameter_client import AsyncParameterClient
19+
1820from ros2cli .node .direct import DirectNode
1921from ros2cli .node .strategy import NodeStrategy
2022from ros2doctor .api import DoctorCheck
2426from ros2doctor .api .format import doctor_warn
2527
2628
27- def call_list_parameters (node , node_name , namespace = '/' ):
29+ def call_list_parameters (node , node_name ):
2830 """Call the list_parameters service for a specific node."""
2931 try :
30- # Create service name and client for the target node's list_parameters service
31- service_name = f"{ namespace .rstrip ('/' )} /{ node_name } /list_parameters"
32- if service_name .startswith ('//' ):
33- service_name = service_name [1 :]
34-
35- client = node .create_client (ListParameters , service_name )
36-
37- if not client .wait_for_service (timeout_sec = 1.0 ):
32+ client = AsyncParameterClient (node , node_name )
33+ ready = client .wait_for_services (timeout_sec = 2.0 )
34+ if not ready :
3835 return None
36+ future = client .list_parameters ()
37+ rclpy .spin_until_future_complete (node , future , timeout_sec = 2.0 )
38+ if future .done () and future .result () is not None :
39+ # Return the parameter names list
40+ return future .result ().result .names
41+ return None
42+ except Exception :
43+ return None
3944
40- request = ListParameters .Request ()
41- future = client .call_async (request )
4245
43- # Spin until the service call completes or times out
44- rclpy .spin_until_future_complete (node , future , timeout_sec = 2.0 )
46+ def call_get_parameters (node , node_name , parameter_names ):
47+ """
48+ Call the get_parameters service for a specific node.
4549
46- if future . done ():
47- response = future . result ()
48- node . destroy_client ( client )
49- return response
50- else :
51- node . destroy_client ( client )
50+ Return the parameter values.
51+ """
52+ try :
53+ client = AsyncParameterClient ( node , node_name )
54+ ready = client . wait_for_services ( timeout_sec = 2.0 )
55+ if not ready :
5256 return None
53-
57+ future = client .get_parameters (parameter_names )
58+ rclpy .spin_until_future_complete (node , future , timeout_sec = 2.0 )
59+ if future .done () and future .result () is not None :
60+ # Return the parameter values list
61+ return future .result ().values
62+ return None
5463 except Exception :
5564 return None
5665
@@ -65,15 +74,18 @@ def check(self):
6574 result = Result ()
6675 with NodeStrategy (None ) as node :
6776 try :
68- node_names_and_namespaces = node .get_node_names_and_namespaces ()
77+ node_names_and_namespaces = \
78+ node .get_node_names_and_namespaces ()
6979 except Exception :
7080 node_names_and_namespaces = []
7181 with DirectNode (None ) as param_node :
7282 for node_name , namespace in node_names_and_namespaces :
73- response = call_list_parameters (param_node .node , node_name , namespace )
74- if response is None :
75- full_name = f"{ namespace .rstrip ('/' )} /{ node_name } "
76- doctor_warn (f'Node { full_name } has no parameter services.' )
83+ full_name = f"{ namespace .rstrip ('/' )} /{ node_name } "
84+ param_names = call_list_parameters (
85+ param_node .node , full_name )
86+ if param_names is None :
87+ doctor_warn (
88+ f'Node { full_name } has no parameter services.' )
7789 result .add_warning ()
7890 return result
7991
@@ -88,7 +100,8 @@ def report(self):
88100 report = Report ('PARAMETER LIST' )
89101 with NodeStrategy (None ) as node :
90102 try :
91- node_names_and_namespaces = node .get_node_names_and_namespaces ()
103+ node_names_and_namespaces = \
104+ node .get_node_names_and_namespaces ()
92105 except Exception :
93106 node_names_and_namespaces = []
94107 if not node_names_and_namespaces :
@@ -103,15 +116,29 @@ def report(self):
103116 with DirectNode (None ) as param_node :
104117 for node_name , namespace in sorted (node_names_and_namespaces ):
105118 nodes_checked += 1
106- response = call_list_parameters (param_node .node , node_name , namespace )
107- if response and hasattr (response , 'result' ) and response .result :
108- result = response .result
109- param_names = result .names if hasattr (result , 'names' ) else []
110- if param_names :
111- total_param_count += len (param_names )
112- full_name = f"{ namespace .rstrip ('/' )} /{ node_name } "
113-
114- report .add_to_report ('node' , full_name )
119+ full_name = f"{ namespace .rstrip ('/' )} /{ node_name } "
120+ param_names = call_list_parameters (
121+ param_node .node , full_name )
122+
123+ if param_names :
124+ total_param_count += len (param_names )
125+ report .add_to_report ('node' , full_name )
126+ param_values = call_get_parameters (
127+ param_node .node , full_name , param_names
128+ )
129+ if (
130+ param_values and
131+ len (param_values ) == len (param_names )
132+ ):
133+ params_with_values = sorted (
134+ zip (param_names , param_values ),
135+ key = lambda x : x [0 ]
136+ )
137+ for name , value_msg in params_with_values :
138+ value = parameter_value_to_python (value_msg )
139+ report .add_to_report (
140+ 'parameter' , f'{ name } : { value } ' )
141+ else :
115142 for param_name in sorted (param_names ):
116143 report .add_to_report ('parameter' , param_name )
117144
0 commit comments