2424#include < sys/stat.h>
2525#include < yaml-cpp/yaml.h>
2626
27+ #include " ament_index_cpp/get_package_share_directory.hpp"
2728#include " rosidl_typesupport_introspection_cpp/message_introspection.hpp"
2829
2930using namespace std ::chrono_literals;
@@ -49,23 +50,17 @@ GreenwaveMonitor::GreenwaveMonitor(const rclcpp::NodeOptions & options)
4950 auto topics = this ->get_parameter (" topics" ).as_string_array ();
5051
5152 // Declare and get the type registry path parameter
52- this ->declare_parameter <std::string>(" type_registry_path" , " /workspace/colcon_ws/src/greenwave_monitor/greenwave_monitor/config/type_registry.yml" );
53+ std::string default_type_registry_path = ament_index_cpp::get_package_share_directory (" greenwave_monitor" ) + " /config/type_registry.yml" ;
54+ this ->declare_parameter <std::string>(" type_registry_path" , default_type_registry_path);
5355 type_registry_path_ = this ->get_parameter (" type_registry_path" ).as_string ();
5456
5557 // Check if the type registry path is valid
5658 if (!type_registry_path_.empty () && !is_valid_file (type_registry_path_)) {
57- RCLCPP_ERROR (
58- this ->get_logger (), " Type registry path '%s' is not a valid file" ,
59- type_registry_path_.c_str ());
60- type_registry_path_.clear ();
61- return ;
62- }
63-
64- if (!read_type_registry (type_registry_path_)) {
6559 RCLCPP_WARN (
66- this ->get_logger (), " Failed to read type registry from path '%s'. "
67- " Assuming no message types have a header. Consider providing a valid type registry." ,
60+ this ->get_logger (), " Type registry path '%s' is not a valid file. "
61+ " Falling back to build-in type registry." ,
6862 type_registry_path_.c_str ());
63+ type_registry_path_.clear ();
6964 }
7065
7166 message_diagnostics::MessageDiagnosticsConfig diagnostics_config;
@@ -123,45 +118,6 @@ void GreenwaveMonitor::topic_callback(
123118 message_diagnostics_[topic]->updateDiagnostics (msg_timestamp.time_since_epoch ().count ());
124119}
125120
126- // Read YAML type registry
127- bool GreenwaveMonitor::read_type_registry (const std::string path) {
128- try {
129- YAML::Node config = YAML::LoadFile (path);
130- if (config[" has_header" ]) {
131- // Check if 'has_header' is a sequence (list)
132- if (config[" has_header" ].IsSequence ()) {
133- for (const auto & type_node : config[" has_header" ]) {
134- if (type_node.IsScalar ()) {
135- known_header_types_[type_node.as <std::string>()] = true ;
136- } else {
137- RCLCPP_WARN (
138- this ->get_logger (),
139- " Found a non-string value in the registry: %s. Skipping." ,
140- type_node.as <std::string>().c_str ());
141- }
142- }
143- } else {
144- RCLCPP_ERROR (
145- this ->get_logger (),
146- " 'has_header' key is not a sequence in the YAML file." );
147- return false ;
148- }
149- } else {
150- RCLCPP_ERROR (
151- this ->get_logger (),
152- " 'has_header' key is not found in the YAML file." );
153- return false ;
154- }
155- } catch (const YAML::BadFile& e) {
156- RCLCPP_ERROR (this ->get_logger (), " Error reading YAML file: %s" , e.what ());
157- } catch (const YAML::ParserException& e) {
158- RCLCPP_ERROR (this ->get_logger (), " Error parsing YAML string: %s" , e.what ());
159- } catch (const std::exception& e) {
160- RCLCPP_ERROR (this ->get_logger (), " An unexpected error occurred: %s" , e.what ());
161- }
162- return true ;
163- }
164-
165121void GreenwaveMonitor::timer_callback ()
166122{
167123 RCLCPP_INFO (this ->get_logger (), " ====================================================" );
@@ -254,22 +210,123 @@ bool GreenwaveMonitor::has_header_from_type(const std::string & type_name)
254210 return type_has_header_cache[type_name];
255211 }
256212
257- auto it = known_header_types_.find (type_name);
258- bool has_header = (it != known_header_types_.end ()) ? it->second : false ;
259-
260- type_has_header_cache[type_name] = has_header;
213+ // rosidl typesupport API is unstable across ROS distributions, so we use this
214+ // map as a more robust way to determine if a message type has a header
215+ static const std::unordered_map<std::string, bool > known_header_types = {
216+ // sensor_msgs
217+ {" sensor_msgs/msg/Image" , true },
218+ {" sensor_msgs/msg/CompressedImage" , true },
219+ {" sensor_msgs/msg/CameraInfo" , true },
220+ {" sensor_msgs/msg/PointCloud2" , true },
221+ {" sensor_msgs/msg/LaserScan" , true },
222+ {" sensor_msgs/msg/Imu" , true },
223+ {" sensor_msgs/msg/NavSatFix" , true },
224+ {" sensor_msgs/msg/MagneticField" , true },
225+ {" sensor_msgs/msg/FluidPressure" , true },
226+ {" sensor_msgs/msg/Illuminance" , true },
227+ {" sensor_msgs/msg/RelativeHumidity" , true },
228+ {" sensor_msgs/msg/Temperature" , true },
229+ {" sensor_msgs/msg/Range" , true },
230+ {" sensor_msgs/msg/PointCloud" , true },
231+
232+ // geometry_msgs
233+ {" geometry_msgs/msg/PoseStamped" , true },
234+ {" geometry_msgs/msg/TwistStamped" , true },
235+ {" geometry_msgs/msg/AccelStamped" , true },
236+ {" geometry_msgs/msg/Vector3Stamped" , true },
237+ {" geometry_msgs/msg/PointStamped" , true },
238+ {" geometry_msgs/msg/QuaternionStamped" , true },
239+ {" geometry_msgs/msg/TransformStamped" , true },
240+ {" geometry_msgs/msg/WrenchStamped" , true },
241+
242+ // nav_msgs
243+ {" nav_msgs/msg/OccupancyGrid" , true },
244+ {" nav_msgs/msg/GridCells" , true },
245+ {" nav_msgs/msg/Path" , true },
246+ {" nav_msgs/msg/Odometry" , true },
247+
248+ // visualization_msgs
249+ {" visualization_msgs/msg/Marker" , true },
250+ {" visualization_msgs/msg/MarkerArray" , true },
251+ {" visualization_msgs/msg/InteractiveMarker" , true },
252+
253+ // std_msgs (no headers)
254+ {" std_msgs/msg/String" , false },
255+ {" std_msgs/msg/Int32" , false },
256+ {" std_msgs/msg/Float64" , false },
257+ {" std_msgs/msg/Bool" , false },
258+ {" std_msgs/msg/Empty" , false },
259+ {" std_msgs/msg/Header" , false }, // Header itself doesn't have a header
260+
261+ // Common message types without headers
262+ {" geometry_msgs/msg/Twist" , false },
263+ {" geometry_msgs/msg/Pose" , false },
264+ {" geometry_msgs/msg/Point" , false },
265+ {" geometry_msgs/msg/Vector3" , false },
266+ {" geometry_msgs/msg/Quaternion" , false }
267+ };
268+
269+ auto it = known_header_types.find (type_name);
270+ bool has_header = (it != known_header_types.end ()) ? it->second : false ;
271+
272+ // In case the type is not in the known list, attempt to read from type registry
273+ if (it == known_header_types.end () && !type_registry_path_.empty ()) {
274+ has_header = has_header_from_type_registry (type_name);
275+ }
261276
262277 // Fallback of no header in case of unknown type, log for reference
263- if (it == known_header_types_ .end ()) {
278+ if (it == known_header_types .end () && !has_header ) {
264279 RCLCPP_WARN_ONCE (
265280 this ->get_logger (),
266281 " Unknown message type '%s' - assuming no header. Consider adding to registry." ,
267282 type_name.c_str ());
268283 }
269284
285+ // Cache the result for future lookups
286+ type_has_header_cache[type_name] = has_header;
287+
270288 return has_header;
271289}
272290
291+ bool GreenwaveMonitor::has_header_from_type_registry (const std::string & type_name) {
292+ try {
293+ YAML::Node config = YAML::LoadFile (type_registry_path_);
294+ if (config[" has_header" ]) {
295+ // Check if 'has_header' is a sequence (list)
296+ if (config[" has_header" ].IsSequence ()) {
297+ for (const auto & type_node : config[" has_header" ]) {
298+ if (type_node.IsScalar ()) {
299+ // Check if the type matches
300+ if (type_node.as <std::string>() == type_name) {
301+ return true ;
302+ }
303+ } else {
304+ RCLCPP_WARN (
305+ this ->get_logger (),
306+ " Found a non-string value in the registry: %s. Skipping." ,
307+ type_node.as <std::string>().c_str ());
308+ }
309+ }
310+ } else {
311+ RCLCPP_ERROR (
312+ this ->get_logger (),
313+ " 'has_header' key is not a sequence in the YAML file." );
314+ }
315+ } else {
316+ RCLCPP_ERROR (
317+ this ->get_logger (),
318+ " 'has_header' key is not found in the YAML file." );
319+ }
320+ } catch (const YAML::BadFile& e) {
321+ RCLCPP_ERROR (this ->get_logger (), " Error reading YAML file: %s" , e.what ());
322+ } catch (const YAML::ParserException& e) {
323+ RCLCPP_ERROR (this ->get_logger (), " Error parsing YAML string: %s" , e.what ());
324+ } catch (const std::exception& e) {
325+ RCLCPP_ERROR (this ->get_logger (), " An unexpected error occurred: %s" , e.what ());
326+ }
327+ return false ;
328+ }
329+
273330bool GreenwaveMonitor::add_topic (const std::string & topic, std::string & message)
274331{
275332 // Check if topic already exists
0 commit comments