44# you may not use this file except in compliance with the License.
55# You may obtain a copy of the License at
66#
7- # http://www.apache.org/licenses/LICENSE-2.0
7+ # http://www.apache.org/licenses/LICENSE-2.0
88#
99# Unless required by applicable law or agreed to in writing, software
1010# distributed under the License is distributed on an "AS IS" BASIS,
1111# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15-
16- from rcl_interfaces .srv import ListParameters
1715import rclpy
16+ from rclpy .parameter import parameter_value_to_python
17+ from ros2param .api import call_get_parameters
18+ from ros2param .api import call_list_parameters
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 = '/' ):
28- """Call the list_parameters service for a specific node."""
29- 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 ):
38- return None
39-
40- request = ListParameters .Request ()
41- future = client .call_async (request )
42-
43- # Spin until the service call completes or times out
44- rclpy .spin_until_future_complete (node , future , timeout_sec = 2.0 )
45-
46- if future .done ():
47- response = future .result ()
48- node .destroy_client (client )
49- return response
50- else :
51- node .destroy_client (client )
52- return None
53-
54- except Exception :
55- return None
56-
57-
58- class ParameterCheck (DoctorCheck ):
59- """Check for nodes without parameter services."""
60-
61- def category (self ):
62- return 'parameter'
63-
64- def check (self ):
65- result = Result ()
66- with NodeStrategy (None ) as node :
67- try :
68- node_names_and_namespaces = node .get_node_names_and_namespaces ()
69- except Exception :
70- node_names_and_namespaces = []
71- with DirectNode (None ) as param_node :
72- 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.' )
77- result .add_warning ()
78- return result
79-
80-
8129class ParameterReport (DoctorReport ):
8230 """Report parameter related information."""
8331
@@ -88,7 +36,8 @@ def report(self):
8836 report = Report ('PARAMETER LIST' )
8937 with NodeStrategy (None ) as node :
9038 try :
91- node_names_and_namespaces = node .get_node_names_and_namespaces ()
39+ node_names_and_namespaces = \
40+ node .get_node_names_and_namespaces ()
9241 except Exception :
9342 node_names_and_namespaces = []
9443 if not node_names_and_namespaces :
@@ -97,24 +46,59 @@ def report(self):
9746 report .add_to_report ('parameter' , 'none' )
9847 return report
9948
100- total_param_count = 0
49+ param_count = 0
10150 nodes_checked = 0
10251
10352 with DirectNode (None ) as param_node :
10453 for node_name , namespace in sorted (node_names_and_namespaces ):
10554 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 []
55+ full_name = f"{ namespace .rstrip ('/' )} /{ node_name } "
56+ try :
57+ response = call_list_parameters (
58+ node = param_node .node , node_name = full_name )
59+ if response is None :
60+ continue
61+ elif response .result () is None :
62+ continue
63+
64+ param_names = response .result ().result .names
11065 if param_names :
111- total_param_count += len (param_names )
112- full_name = f"{ namespace .rstrip ('/' )} /{ node_name } "
113-
66+ param_count += len (param_names )
11467 report .add_to_report ('node' , full_name )
115- for param_name in sorted (param_names ):
116- report .add_to_report ('parameter' , param_name )
68+ try :
69+ param_response = call_get_parameters (
70+ node = param_node .node ,
71+ node_name = full_name ,
72+ parameter_names = param_names
73+ )
74+ param_values = None
75+ if param_response :
76+ param_values = param_response .values
77+ if param_values and len (param_values ) == len (
78+ param_names
79+ ):
80+ params_with_values = sorted (
81+ zip (param_names , param_values )
82+ )
83+ for name , value_msg in params_with_values :
84+ value = parameter_value_to_python (
85+ value_msg
86+ )
87+ report .add_to_report (
88+ 'parameter' , f'{ name } : { value } ' )
89+ else :
90+ for param_name in sorted (param_names ):
91+ report .add_to_report (
92+ 'parameter' , param_name
93+ )
94+ except RuntimeError :
95+ for param_name in sorted (param_names ):
96+ report .add_to_report (
97+ 'parameter' , param_name
98+ )
99+ except RuntimeError :
100+ pass
117101
118102 report .add_to_report ('total nodes checked' , nodes_checked )
119- report .add_to_report ('total parameter count' , total_param_count )
103+ report .add_to_report ('total parameter count' , param_count )
120104 return report
0 commit comments