31
31
# of Clearpath Robotics.
32
32
import os
33
33
34
+ from apt import Cache
35
+
34
36
from clearpath_config .clearpath_config import ClearpathConfig
35
37
from clearpath_config .common .types .platform import Platform
36
38
from clearpath_config .common .utils .dictionary import merge_dict , replace_dict_items
39
+ from clearpath_config .sensors .types .cameras import BaseCamera , IntelRealsense
40
+ from clearpath_config .sensors .types .gps import BaseGPS
41
+ from clearpath_config .sensors .types .imu import BaseIMU , PhidgetsSpatial
42
+ from clearpath_config .sensors .types .lidars_2d import BaseLidar2D
43
+ from clearpath_config .sensors .types .lidars_3d import BaseLidar3D
44
+ from clearpath_config .sensors .types .sensor import BaseSensor
37
45
from clearpath_generator_common .common import Package , ParamFile
38
46
from clearpath_generator_common .param .writer import ParamWriter
47
+ from clearpath_generator_common .ros import ROS_DISTRO
39
48
40
49
41
50
class PlatformParam ():
42
51
CONTROL = 'control'
52
+ DIAGNOSTIC_AGGREGATOR = 'diagnostic_aggregator'
53
+ DIAGNOSTIC_UPDATER = 'diagnostic_updater'
43
54
IMU_FILTER = 'imu_filter'
44
55
LOCALIZATION = 'localization'
45
56
TELEOP_INTERACTIVE_MARKERS = 'teleop_interactive_markers'
46
57
TELEOP_JOY = 'teleop_joy'
47
58
TWIST_MUX = 'twist_mux'
48
59
60
+ NOT_APPLICABLE = 'not_applicable'
61
+
49
62
PARAMETERS = [
50
63
CONTROL ,
64
+ DIAGNOSTIC_AGGREGATOR ,
65
+ DIAGNOSTIC_UPDATER ,
51
66
IMU_FILTER ,
52
67
LOCALIZATION ,
53
68
TELEOP_INTERACTIVE_MARKERS ,
@@ -57,6 +72,7 @@ class PlatformParam():
57
72
58
73
class BaseParam ():
59
74
CLEARPATH_CONTROL = 'clearpath_control'
75
+ CLEARPATH_DIAGNOSTICS = 'clearpath_diagnostics'
60
76
61
77
def __init__ (self ,
62
78
parameter : str ,
@@ -169,6 +185,127 @@ def __init__(self,
169
185
self .default_parameter_file_package = self .clearpath_control_package
170
186
self .default_parameter_file_path = 'config'
171
187
188
+ class DiagnosticsAggregatorParam (BaseParam ):
189
+ """Parameter file that decides the aggregation of the diagnostics data for display."""
190
+
191
+ def __init__ (self ,
192
+ parameter : str ,
193
+ clearpath_config : ClearpathConfig ,
194
+ param_path : str ) -> None :
195
+ super ().__init__ (parameter , clearpath_config , param_path )
196
+ self .default_parameter_file_package = Package (self .CLEARPATH_DIAGNOSTICS )
197
+ self .default_parameter_file_path = 'config'
198
+
199
+ class DiagnosticsUpdaterParam (BaseParam ):
200
+ """Parameter file for Clearpath Diagnostics indicating which topics to monitor."""
201
+
202
+ DIAGNOSTIC_UPDATER_NODE = 'clearpath_diagnostic_updater'
203
+
204
+ def __init__ (self ,
205
+ parameter : str ,
206
+ clearpath_config : ClearpathConfig ,
207
+ param_path : str ) -> None :
208
+ super ().__init__ (parameter , clearpath_config , param_path )
209
+ self .default_parameter_file_package = Package (self .CLEARPATH_DIAGNOSTICS )
210
+ self .default_parameter_file_path = 'config'
211
+ self .diag_dict = {}
212
+
213
+ def generate_parameters (self , use_sim_time : bool = False ) -> None :
214
+ super ().generate_parameters (use_sim_time )
215
+
216
+ # Read the default parameter file
217
+ self .default_param_file = ParamFile (
218
+ name = self .default_parameter ,
219
+ package = self .default_parameter_file_package ,
220
+ path = self .default_parameter_file_path ,
221
+ parameters = {}
222
+ )
223
+ self .default_param_file .read ()
224
+
225
+ # Initialize parameters with the default parameters
226
+ self .param_file .parameters = self .default_param_file .parameters
227
+
228
+ # Update parameters based on the robot.yaml
229
+ platform_model = self .clearpath_config .get_platform_model ()
230
+ self .param_file .update ({self .DIAGNOSTIC_UPDATER_NODE : {
231
+ 'serial_number' : self .clearpath_config .get_serial_number (),
232
+ 'platform_model' : platform_model }})
233
+
234
+ if use_sim_time :
235
+ latest_apt_firmware_version = 'simulated'
236
+ installed_apt_firmware_version = 'simulated'
237
+ elif platform_model == Platform .A200 :
238
+ latest_apt_firmware_version = PlatformParam .NOT_APPLICABLE
239
+ installed_apt_firmware_version = PlatformParam .NOT_APPLICABLE
240
+ else :
241
+ # Check latest firmware version available and save it in the config
242
+ cache = Cache ()
243
+ latest_apt_firmware_version = 'not_found'
244
+ installed_apt_firmware_version = 'none'
245
+ try :
246
+ pkg = cache [f'ros-{ ROS_DISTRO } -clearpath-firmware' ]
247
+ latest_apt_firmware_version = pkg .versions [0 ].version .split ('-' )[0 ]
248
+ if (pkg .is_installed ):
249
+ installed_apt_firmware_version = pkg .installed .version .split ('-' )[0 ]
250
+ except KeyError :
251
+ print (f'\033 [93mWarning: ros-{ ROS_DISTRO } -clearpath-firmware'
252
+ ' package not found\033 [0m' )
253
+
254
+ self .param_file .update ({self .DIAGNOSTIC_UPDATER_NODE : {
255
+ 'ros_distro' : ROS_DISTRO ,
256
+ 'latest_apt_firmware_version' : latest_apt_firmware_version ,
257
+ 'installed_apt_firmware_version' : installed_apt_firmware_version }})
258
+
259
+ # List all topics to be monitored from each launched sensor
260
+ for sensor in self .clearpath_config .sensors .get_all_sensors ():
261
+
262
+ if not sensor .launch_enabled :
263
+ continue
264
+
265
+ match sensor :
266
+ case IntelRealsense ():
267
+ if sensor .color_enabled :
268
+ self .add_topic (sensor , sensor .TOPICS .COLOR_IMAGE )
269
+ if sensor .depth_enabled :
270
+ self .add_topic (sensor , sensor .TOPICS .DEPTH_IMAGE )
271
+ if sensor .pointcloud_enabled :
272
+ self .add_topic (sensor , sensor .TOPICS .POINTCLOUD )
273
+
274
+ case BaseCamera ():
275
+ self .add_topic (sensor , sensor .TOPICS .COLOR_IMAGE )
276
+
277
+ case BaseLidar2D ():
278
+ self .add_topic (sensor , sensor .TOPICS .SCAN )
279
+
280
+ case BaseLidar3D ():
281
+ self .add_topic (sensor , sensor .TOPICS .SCAN )
282
+ self .add_topic (sensor , sensor .TOPICS .POINTS )
283
+
284
+ case PhidgetsSpatial ():
285
+ self .add_topic (sensor , sensor .TOPICS .RAW_DATA ),
286
+ self .add_topic (sensor , sensor .TOPICS .MAG ),
287
+
288
+ case BaseIMU ():
289
+ self .add_topic (sensor , sensor .TOPICS .DATA )
290
+ self .add_topic (sensor , sensor .TOPICS .MAG )
291
+
292
+ case BaseGPS ():
293
+ self .add_topic (sensor , sensor .TOPICS .FIX )
294
+
295
+ # Output the list of topics into the parameter file
296
+ self .param_file .update ({self .DIAGNOSTIC_UPDATER_NODE : {'topics' : self .diag_dict }})
297
+
298
+ def add_topic (self , sensor : BaseSensor , topic_key : str ) -> None :
299
+ """
300
+ Add a sensor topic to the dictionary using the topic key string.
301
+
302
+ :param sensor: The sensor object from which the topic info will be gotten
303
+ :param topic_key: The key used to identify the topic to be monitored
304
+ """
305
+ self .diag_dict [sensor .get_topic_name (topic_key , local = True )] = {
306
+ 'type' : sensor .get_topic_type (topic_key ),
307
+ 'rate' : float (sensor .get_topic_rate (topic_key ))}
308
+
172
309
class LocalizationParam (BaseParam ):
173
310
EKF_NODE = 'ekf_node'
174
311
imu_config = [False , False , False ,
@@ -247,6 +384,8 @@ def __init__(self,
247
384
248
385
PARAMETER = {
249
386
IMU_FILTER : ImuFilterParam ,
387
+ DIAGNOSTIC_AGGREGATOR : DiagnosticsAggregatorParam ,
388
+ DIAGNOSTIC_UPDATER : DiagnosticsUpdaterParam ,
250
389
LOCALIZATION : LocalizationParam ,
251
390
TELEOP_JOY : TeleopJoyParam ,
252
391
TWIST_MUX : TwistMuxParam ,
0 commit comments