Skip to content

Commit 1427288

Browse files
committed
PoC YAML registry
1 parent bc84622 commit 1427288

File tree

5 files changed

+119
-60
lines changed

5 files changed

+119
-60
lines changed

greenwave_monitor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ ament_target_dependencies(greenwave_monitor
3535
std_msgs
3636
diagnostic_msgs
3737
greenwave_monitor_interfaces
38+
yaml_cpp_vendor
3839
)
3940
target_link_libraries(greenwave_monitor message_diagnostics)
4041

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
has_header:
2+
# sensor_msgs
3+
- sensor_msgs/msg/Image
4+
- sensor_msgs/msg/CompressedImage
5+
- sensor_msgs/msg/CameraInfo
6+
- sensor_msgs/msg/PointCloud2
7+
- sensor_msgs/msg/LaserScan
8+
- sensor_msgs/msg/Imu
9+
- sensor_msgs/msg/NavSatFix
10+
- sensor_msgs/msg/MagneticField
11+
- sensor_msgs/msg/FluidPressure
12+
- sensor_msgs/msg/Illuminance
13+
- sensor_msgs/msg/RelativeHumidity
14+
- sensor_msgs/msg/Temperature
15+
- sensor_msgs/msg/Range
16+
- sensor_msgs/msg/PointCloud
17+
18+
# geometry_msgs
19+
- geometry_msgs/msg/PoseStamped
20+
- geometry_msgs/msg/TwistStamped
21+
- geometry_msgs/msg/AccelStamped
22+
- geometry_msgs/msg/Vector3Stamped
23+
- geometry_msgs/msg/PointStamped
24+
- geometry_msgs/msg/QuaternionStamped
25+
- geometry_msgs/msg/TransformStamped
26+
- geometry_msgs/msg/WrenchStamped
27+
28+
# nav_msgs
29+
- nav_msgs/msg/OccupancyGrid
30+
- nav_msgs/msg/GridCells
31+
- nav_msgs/msg/Path
32+
- nav_msgs/msg/Odometry
33+
34+
# visualization_msgs
35+
- visualization_msgs/msg/Marker
36+
- visualization_msgs/msg/MarkerArray
37+
- visualization_msgs/msg/InteractiveMarker

greenwave_monitor/include/greenwave_monitor.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,15 @@ class GreenwaveMonitor : public rclcpp::Node
6363

6464
bool has_header_from_type(const std::string & type_name);
6565

66+
bool read_type_registry(const std::string path);
67+
6668
std::chrono::time_point<std::chrono::system_clock>
6769
GetTimestampFromSerializedMessage(
6870
std::shared_ptr<rclcpp::SerializedMessage> serialized_message_ptr,
6971
const std::string & type);
70-
72+
73+
std::string type_registry_path_;
74+
std::unordered_map<std::string, bool> known_header_types_;
7175
std::map<std::string,
7276
std::unique_ptr<message_diagnostics::MessageDiagnostics>> message_diagnostics_;
7377
std::vector<std::shared_ptr<rclcpp::GenericSubscription>> subscriptions_;

greenwave_monitor/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<depend>sensor_msgs</depend>
3737
<depend>greenwave_monitor_interfaces</depend>
3838
<depend>rclpy</depend>
39+
<depend>yaml_cpp_vendor</depend>
3940

4041
<exec_depend>launch</exec_depend>
4142
<exec_depend>launch_ros</exec_depend>

greenwave_monitor/src/greenwave_monitor.cpp

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,24 @@
2121
#include <cstring>
2222
#include <mutex>
2323
#include <unordered_map>
24+
#include <sys/stat.h>
25+
#include <yaml-cpp/yaml.h>
2426

2527
#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp"
2628

2729
using namespace std::chrono_literals;
2830

31+
namespace {
32+
33+
// Check if a file exists and is a regular file
34+
bool is_valid_file(const std::string& path) {
35+
struct stat st;
36+
if (stat(path.c_str(), &st) != 0) { return false; }
37+
return static_cast<bool>(st.st_mode & S_IFREG);
38+
}
39+
40+
} // anonymous namespace
41+
2942
GreenwaveMonitor::GreenwaveMonitor(const rclcpp::NodeOptions & options)
3043
: Node("greenwave_monitor", options)
3144
{
@@ -35,6 +48,26 @@ GreenwaveMonitor::GreenwaveMonitor(const rclcpp::NodeOptions & options)
3548
this->declare_parameter<std::vector<std::string>>("topics", {""});
3649
auto topics = this->get_parameter("topics").as_string_array();
3750

51+
// 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+
type_registry_path_ = this->get_parameter("type_registry_path").as_string();
54+
55+
// Check if the type registry path is valid
56+
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_)) {
65+
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.",
68+
type_registry_path_.c_str());
69+
}
70+
3871
message_diagnostics::MessageDiagnosticsConfig diagnostics_config;
3972
diagnostics_config.enable_all_topic_diagnostics = true;
4073

@@ -90,6 +123,45 @@ void GreenwaveMonitor::topic_callback(
90123
message_diagnostics_[topic]->updateDiagnostics(msg_timestamp.time_since_epoch().count());
91124
}
92125

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+
93165
void GreenwaveMonitor::timer_callback()
94166
{
95167
RCLCPP_INFO(this->get_logger(), "====================================================");
@@ -182,69 +254,13 @@ bool GreenwaveMonitor::has_header_from_type(const std::string & type_name)
182254
return type_has_header_cache[type_name];
183255
}
184256

185-
// rosidl typesupport API is unstable across ROS distributions, so we use this
186-
// map as a more robust way to determine if a message type has a header
187-
static const std::unordered_map<std::string, bool> known_header_types = {
188-
// sensor_msgs
189-
{"sensor_msgs/msg/Image", true},
190-
{"sensor_msgs/msg/CompressedImage", true},
191-
{"sensor_msgs/msg/CameraInfo", true},
192-
{"sensor_msgs/msg/PointCloud2", true},
193-
{"sensor_msgs/msg/LaserScan", true},
194-
{"sensor_msgs/msg/Imu", true},
195-
{"sensor_msgs/msg/NavSatFix", true},
196-
{"sensor_msgs/msg/MagneticField", true},
197-
{"sensor_msgs/msg/FluidPressure", true},
198-
{"sensor_msgs/msg/Illuminance", true},
199-
{"sensor_msgs/msg/RelativeHumidity", true},
200-
{"sensor_msgs/msg/Temperature", true},
201-
{"sensor_msgs/msg/Range", true},
202-
{"sensor_msgs/msg/PointCloud", true},
203-
204-
// geometry_msgs
205-
{"geometry_msgs/msg/PoseStamped", true},
206-
{"geometry_msgs/msg/TwistStamped", true},
207-
{"geometry_msgs/msg/AccelStamped", true},
208-
{"geometry_msgs/msg/Vector3Stamped", true},
209-
{"geometry_msgs/msg/PointStamped", true},
210-
{"geometry_msgs/msg/QuaternionStamped", true},
211-
{"geometry_msgs/msg/TransformStamped", true},
212-
{"geometry_msgs/msg/WrenchStamped", true},
213-
214-
// nav_msgs
215-
{"nav_msgs/msg/OccupancyGrid", true},
216-
{"nav_msgs/msg/GridCells", true},
217-
{"nav_msgs/msg/Path", true},
218-
{"nav_msgs/msg/Odometry", true},
219-
220-
// visualization_msgs
221-
{"visualization_msgs/msg/Marker", true},
222-
{"visualization_msgs/msg/MarkerArray", true},
223-
{"visualization_msgs/msg/InteractiveMarker", true},
224-
225-
// std_msgs (no headers)
226-
{"std_msgs/msg/String", false},
227-
{"std_msgs/msg/Int32", false},
228-
{"std_msgs/msg/Float64", false},
229-
{"std_msgs/msg/Bool", false},
230-
{"std_msgs/msg/Empty", false},
231-
{"std_msgs/msg/Header", false}, // Header itself doesn't have a header
232-
233-
// Common message types without headers
234-
{"geometry_msgs/msg/Twist", false},
235-
{"geometry_msgs/msg/Pose", false},
236-
{"geometry_msgs/msg/Point", false},
237-
{"geometry_msgs/msg/Vector3", false},
238-
{"geometry_msgs/msg/Quaternion", false}
239-
};
240-
241-
auto it = known_header_types.find(type_name);
242-
bool has_header = (it != known_header_types.end()) ? it->second : false;
257+
auto it = known_header_types_.find(type_name);
258+
bool has_header = (it != known_header_types_.end()) ? it->second : false;
243259

244260
type_has_header_cache[type_name] = has_header;
245261

246262
// Fallback of no header in case of unknown type, log for reference
247-
if (it == known_header_types.end()) {
263+
if (it == known_header_types_.end()) {
248264
RCLCPP_WARN_ONCE(
249265
this->get_logger(),
250266
"Unknown message type '%s' - assuming no header. Consider adding to registry.",

0 commit comments

Comments
 (0)