mrs_lib
Various reusable classes, functions and utilities for use in MRS projects
Loading...
Searching...
No Matches
errorgraph.h
1#pragma once
2
3#include <string>
4#include <optional>
5#include <variant>
6#include <vector>
7#include <memory>
8#include <algorithm>
9
10#include <rclcpp/time.hpp>
11#include "rclcpp/clock.hpp"
12
13#include <mrs_lib/errorgraph/node_id.h>
14
15#include <mrs_msgs/msg/errorgraph_error.hpp>
16#include <mrs_msgs/msg/errorgraph_element.hpp>
17
18namespace mrs_lib
19{
20 namespace errorgraph
21 {
22 using errorgraph_error_msg_t = mrs_msgs::msg::ErrorgraphError;
23 using errorgraph_element_msg_t = mrs_msgs::msg::ErrorgraphElement;
24
48 {
49 public:
54 explicit Errorgraph(rclcpp::Clock::SharedPtr clock) : clock_(clock)
55 {
56 }
57
58 /* error_t //{ */
59
66 struct error_t
67 {
68 rclcpp::Time stamp;
69 std::string type;
70 std::optional<std::string> waited_for_topic;
71 std::optional<node_id_t> waited_for_node;
72
74 inline bool is_waiting_for() const
75 {
77 }
78
80 inline bool is_waiting_for_topic() const
81 {
82 return type == errorgraph_error_msg_t::TYPE_WAITING_FOR_TOPIC;
83 }
84
86 inline bool is_waiting_for_node() const
87 {
88 return type == errorgraph_error_msg_t::TYPE_WAITING_FOR_NODE;
89 }
90
92 inline bool is_waiting_for(const std::string& topic) const
93 {
94 return type == errorgraph_error_msg_t::TYPE_WAITING_FOR_TOPIC && waited_for_topic.has_value() && waited_for_topic.value() == topic;
95 }
96
98 inline bool is_waiting_for(const node_id_t& node_id) const
99 {
100 return type == errorgraph_error_msg_t::TYPE_WAITING_FOR_NODE && waited_for_node.has_value() && waited_for_node.value() == node_id;
101 }
102
104 inline bool is_no_error() const
105 {
106 return type == errorgraph_error_msg_t::TYPE_NO_ERROR;
107 }
108
110 error_t(const errorgraph_error_msg_t& msg) : type(msg.type)
111 {
112 if (msg.type == errorgraph_error_msg_t::TYPE_WAITING_FOR_NODE)
113 waited_for_node = node_id_t::from_msg(msg.waited_for_node);
114 else if (msg.type == errorgraph_error_msg_t::TYPE_WAITING_FOR_TOPIC)
115 waited_for_topic = msg.waited_for_topic;
116 stamp = msg.stamp;
117 }
118
120 errorgraph_error_msg_t to_msg() const
121 {
122 errorgraph_error_msg_t ret;
123 ret.stamp = stamp;
124 ret.type = type;
125 if (waited_for_topic.has_value())
126 ret.waited_for_topic = waited_for_topic.value();
127 if (waited_for_node.has_value())
128 ret.waited_for_node = waited_for_node.value().to_msg();
129 return ret;
130 }
131 };
132
133 //}
134
135 /* node_info_t //{ */
136
144 {
146 std::vector<error_t> errors;
147 rclcpp::Time stamp;
149
151 errorgraph_element_msg_t to_msg() const;
152 };
153
154 //}
155
156 /* topic_info_t //{ */
157
165 {
166 std::string topic_name;
168 rclcpp::Time stamp;
170
172 errorgraph_element_msg_t to_msg() const;
173 };
174
175 //}
176
178 using element_info_t = std::variant<node_info_t, topic_info_t>;
179
180 /* element_t //{ */
181
193 {
195 enum class type_t
196 {
197 node,
198 topic
199 };
200
201 size_t element_id;
203
204 std::string topic_name;
206
207 std::vector<error_t> errors;
208 rclcpp::Time stamp;
209 static constexpr double DEFAULT_NOT_REPORTING_DELAY_SECONDS = 3.0;
210 rclcpp::Duration not_reporting_delay = rclcpp::Duration::from_seconds(DEFAULT_NOT_REPORTING_DELAY_SECONDS);
211
212 std::vector<element_t*> parents;
213 std::vector<element_t*> children;
214 bool visited = false;
215
216 rclcpp::Clock::SharedPtr clock_;
217
219 element_t(size_t element_id, const node_id_t& source_node, rclcpp::Clock::SharedPtr clock)
220 : element_id(element_id), type(type_t::node), source_node(source_node), stamp(static_cast<int64_t>(0), clock->get_clock_type()), clock_(clock){};
221
223 element_t(size_t element_id, const std::string& topic_name, const node_id_t& source_node, rclcpp::Clock::SharedPtr clock)
225 stamp(static_cast<int64_t>(0), clock->get_clock_type()), clock_(clock){};
226
228 inline std::vector<const std::string*> waited_for_topics() const
229 {
230 std::vector<const std::string*> ret;
231 ret.reserve(errors.size());
232 for (const auto& el : errors)
233 {
234 if (el.waited_for_topic.has_value())
235 ret.push_back(&el.waited_for_topic.value());
236 }
237 return ret;
238 }
239
241 inline std::vector<const node_id_t*> waited_for_nodes() const
242 {
243 std::vector<const node_id_t*> ret;
244 ret.reserve(errors.size());
245 for (const auto& el : errors)
246 {
247 if (el.waited_for_node.has_value())
248 ret.push_back(&el.waited_for_node.value());
249 }
250 return ret;
251 }
252
254 inline bool is_waiting_for() const
255 {
256 return std::any_of(std::begin(errors), std::end(errors), [](const auto& error) { return error.is_waiting_for(); });
257 }
258
260 inline bool is_waiting_for(const node_id_t& node_id) const
261 {
262 return std::any_of(std::begin(errors), std::end(errors), [node_id](const auto& error) { return error.is_waiting_for(node_id); });
263 }
264
266 inline bool is_no_error() const
267 {
268 return !is_not_reporting() && std::all_of(std::begin(errors), std::end(errors), [](const auto& error) { return error.is_no_error(); });
269 }
270
272 inline bool is_not_reporting() const
273 {
274 return type != type_t::topic && clock_->now() - stamp > not_reporting_delay;
275 }
276
278 errorgraph_element_msg_t to_msg() const
279 {
280 errorgraph_element_msg_t ret;
281 ret.stamp = stamp;
282 ret.source_node = source_node.to_msg();
283 for (const auto& error : errors)
284 ret.errors.push_back(error.to_msg());
285 return ret;
286 }
287
289 element_info_t to_info() const;
290 };
291
292 //}
293
294 private:
295 std::vector<std::unique_ptr<element_t>> elements_;
296 bool graph_up_to_date_ = false;
297 rclcpp::Clock::SharedPtr clock_;
298
299 std::vector<element_t*> find_elements_waited_for(const element_t& by_element);
300
301 element_t* find_element_mutable(const std::string& topic_name);
302
303 element_t* find_element_mutable(const node_id_t& node_id);
304
305 void prepare_graph();
306
307 void build_graph();
308
309 std::vector<const element_t*> DFS(element_t* from, bool* loop_detected_out = nullptr);
310
311 element_t* add_new_element(const std::string& topic_name, const node_id_t& node_id = {});
312
313 element_t* add_new_element(const node_id_t& node_id);
314
315 size_t last_element_id = 0;
316
317 public:
322 void write_dot(std::ostream& os);
323
334 std::vector<element_info_t> find_dependency_roots(const node_id_t& node_id, bool* loop_detected_out = nullptr);
335
340 std::vector<element_info_t> find_error_roots();
341
346 std::vector<element_info_t> find_roots();
347
352 std::vector<element_info_t> find_leaves();
353
359 std::optional<element_info_t> find_element(const std::string& topic_name);
360
366 std::optional<element_info_t> find_element(const node_id_t& node_id);
367
378 element_info_t add_element_from_msg(const errorgraph_element_msg_t& msg);
379 };
380
381 } // namespace errorgraph
382} // namespace mrs_lib
A directed graph representing error dependencies between ROS nodes and topics.
Definition errorgraph.h:48
std::vector< element_info_t > find_roots()
Find all root elements (elements with no parents in the dependency graph).
Definition errorgraph.cpp:103
std::vector< element_info_t > find_leaves()
Find all leaf elements (elements with no children in the dependency graph).
Definition errorgraph.cpp:115
element_info_t add_element_from_msg(const errorgraph_element_msg_t &msg)
Add or update an element from a received ROS message.
Definition errorgraph.cpp:237
std::variant< node_info_t, topic_info_t > element_info_t
Type-safe variant representing either a node or topic element info.
Definition errorgraph.h:178
std::vector< element_info_t > find_error_roots()
Find all root-cause elements across the entire graph.
Definition errorgraph.cpp:91
std::vector< element_info_t > find_dependency_roots(const node_id_t &node_id, bool *loop_detected_out=nullptr)
Find the root-cause elements blocking the given node.
Definition errorgraph.cpp:10
std::optional< element_info_t > find_element(const std::string &topic_name)
Find an element by topic name.
Definition errorgraph.cpp:171
Errorgraph(rclcpp::Clock::SharedPtr clock)
Construct an empty Errorgraph.
Definition errorgraph.h:54
void write_dot(std::ostream &os)
Write the graph in Graphviz DOT format.
Definition errorgraph.cpp:280
All mrs_lib functions, classes, variables and definitions are contained in this namespace.
Definition attitude_converter.h:24
Internal representation of a node or topic in the error dependency graph.
Definition errorgraph.h:193
std::vector< error_t > errors
List of errors reported by this element (nodes only).
Definition errorgraph.h:207
std::string topic_name
Topic name (only meaningful if type == topic).
Definition errorgraph.h:204
element_t(size_t element_id, const node_id_t &source_node, rclcpp::Clock::SharedPtr clock)
Construct a node element.
Definition errorgraph.h:219
std::vector< const node_id_t * > waited_for_nodes() const
Returns pointers to node IDs this element is waiting for.
Definition errorgraph.h:241
errorgraph_element_msg_t to_msg() const
Convert to a ROS message.
Definition errorgraph.h:278
rclcpp::Time stamp
Last time this element was updated from a message.
Definition errorgraph.h:208
size_t element_id
Unique ID of this element within the graph.
Definition errorgraph.h:201
std::vector< element_t * > parents
Parent elements in the dependency graph.
Definition errorgraph.h:212
type_t type
Whether this is a node or topic element.
Definition errorgraph.h:202
element_t(size_t element_id, const std::string &topic_name, const node_id_t &source_node, rclcpp::Clock::SharedPtr clock)
Construct a topic element.
Definition errorgraph.h:223
bool is_waiting_for(const node_id_t &node_id) const
Returns true if this element is waiting for the given node.
Definition errorgraph.h:260
std::vector< element_t * > children
Child elements in the dependency graph.
Definition errorgraph.h:213
bool is_not_reporting() const
Returns true if this node element has stopped reporting (stale).
Definition errorgraph.h:272
std::vector< const std::string * > waited_for_topics() const
Returns pointers to topic names this element is waiting for.
Definition errorgraph.h:228
bool visited
Visited flag used during graph traversal.
Definition errorgraph.h:214
node_id_t source_node
Source node ID, or expected publisher for a topic.
Definition errorgraph.h:205
element_info_t to_info() const
Convert to a public element_info_t variant.
Definition errorgraph.cpp:254
bool is_waiting_for() const
Returns true if this element has any dependency errors.
Definition errorgraph.h:254
type_t
Whether this element represents a node or a topic.
Definition errorgraph.h:196
bool is_no_error() const
Returns true if this element has no errors and is actively reporting.
Definition errorgraph.h:266
Represents a single error reported by a node.
Definition errorgraph.h:67
bool is_waiting_for(const std::string &topic) const
Returns true if this error is waiting for the given topic.
Definition errorgraph.h:92
rclcpp::Time stamp
Timestamp when the error was reported.
Definition errorgraph.h:68
errorgraph_error_msg_t to_msg() const
Convert to a ROS message.
Definition errorgraph.h:120
error_t(const errorgraph_error_msg_t &msg)
Construct from a ROS message.
Definition errorgraph.h:110
bool is_no_error() const
Returns true if this represents a "no error" state.
Definition errorgraph.h:104
bool is_waiting_for(const node_id_t &node_id) const
Returns true if this error is waiting for the given node.
Definition errorgraph.h:98
bool is_waiting_for_node() const
Returns true if this error is waiting for a node.
Definition errorgraph.h:86
std::optional< node_id_t > waited_for_node
Node ID if this is a "waiting for node" error.
Definition errorgraph.h:71
bool is_waiting_for() const
Returns true if this error indicates a dependency (waiting for a topic or node).
Definition errorgraph.h:74
std::string type
Error type string (see ErrorgraphError message constants).
Definition errorgraph.h:69
std::optional< std::string > waited_for_topic
Topic name if this is a "waiting for topic" error.
Definition errorgraph.h:70
bool is_waiting_for_topic() const
Returns true if this error is waiting for a topic.
Definition errorgraph.h:80
Public view of a node element, returned by query methods.
Definition errorgraph.h:144
rclcpp::Time stamp
Last time this element was updated.
Definition errorgraph.h:147
std::vector< error_t > errors
List of errors reported by this node.
Definition errorgraph.h:146
bool not_reporting
Whether this node has stopped reporting (stale).
Definition errorgraph.h:148
errorgraph_element_msg_t to_msg() const
Convert to a ROS message.
Definition errorgraph.cpp:262
node_id_t source_node
Node ID of this element.
Definition errorgraph.h:145
Public view of a topic element, returned by query methods.
Definition errorgraph.h:165
errorgraph_element_msg_t to_msg() const
Convert to a ROS message.
Definition errorgraph.cpp:272
bool not_reporting
Whether this topic's publisher has stopped reporting.
Definition errorgraph.h:169
rclcpp::Time stamp
Last time this element was updated.
Definition errorgraph.h:168
std::string topic_name
Topic name.
Definition errorgraph.h:166
node_id_t source_node
Expected publisher node for this topic.
Definition errorgraph.h:167
Identifies a specific component within a ROS node for error reporting.
Definition node_id.h:21
errorgraph_node_id_msg_t to_msg() const
Convert to a ROS message.
Definition node_id.h:41
static node_id_t from_msg(const errorgraph_node_id_msg_t &msg)
Construct from a ROS message.
Definition node_id.h:32