Diagnostics Messages (C++)
System health and safety types in horus::msg::. Include via <horus/msg/diagnostics.hpp>.
Quick Reference
| Type | Key Fields | Use Case |
|---|---|---|
Heartbeat | node_id[32], sequence, alive, cpu_usage, memory_usage | Node liveness |
EmergencyStop | engaged (u8), reason[64], source[32], auto_reset | Safety stop |
DiagnosticStatus | level (0-3), message[256] | Component health |
ResourceUsage | cpu_percent, memory_mb, disk_percent | System resources |
NodeHeartbeat | node_name[32], tick_rate, cpu_usage, uptime_ms | Per-node metrics |
SafetyStatus | safe (bool), confidence, last_fault[128] | Safety system state |
DiagnosticValue | key[32], value[64], value_type | Key-value diagnostic |
DiagnosticReport | component[32], values[16], level | Multi-value report |
Heartbeat
Published periodically to prove a node is alive:
class HeartbeatPublisher : public horus::Node {
public:
HeartbeatPublisher() : Node("heartbeat_pub") {
hb_pub_ = advertise<horus::msg::Heartbeat>("heartbeat");
}
void tick() override {
if (++tick_ % 100 != 0) return; // 1 Hz at 100 Hz scheduler
horus::msg::Heartbeat hb{};
std::strncpy(reinterpret_cast<char*>(hb.node_id), "motor_ctrl", 31);
hb.sequence = seq_++;
hb.alive = true;
hb.cpu_usage = 12.5f; // percent
hb.memory_usage = 45.0f; // MB
hb_pub_->send(hb);
}
private:
horus::Publisher<horus::msg::Heartbeat>* hb_pub_;
uint64_t seq_ = 0;
int tick_ = 0;
};
EmergencyStop
The most safety-critical message. engaged=1 means all actuators must stop immediately:
// Trigger e-stop
horus::msg::EmergencyStop estop{};
estop.engaged = 1;
std::strncpy(reinterpret_cast<char*>(estop.reason), "Obstacle < 10cm", 63);
std::strncpy(reinterpret_cast<char*>(estop.source), "safety_monitor", 31);
estop.auto_reset = 0; // manual reset required
estop_pub_->send(estop);
// Clear e-stop
horus::msg::EmergencyStop clear{};
clear.engaged = 0;
estop_pub_->send(clear);
Convention: Every actuator node must subscribe to "emergency.stop" and zero outputs when engaged == 1.
DiagnosticReport — Multi-Value Health Check
horus::msg::DiagnosticReport report{};
std::strncpy(reinterpret_cast<char*>(report.component), "motor_driver", 31);
report.level = 1; // 0=OK, 1=WARN, 2=ERROR
report.value_count = 3;
// Value 0: temperature
std::strncpy(reinterpret_cast<char*>(report.values[0].key), "temperature", 31);
std::strncpy(reinterpret_cast<char*>(report.values[0].value), "72.5", 63);
report.values[0].value_type = 2; // float
// Value 1: current
std::strncpy(reinterpret_cast<char*>(report.values[1].key), "current_amps", 31);
std::strncpy(reinterpret_cast<char*>(report.values[1].value), "3.2", 63);
report.values[1].value_type = 2;
// Value 2: status
std::strncpy(reinterpret_cast<char*>(report.values[2].key), "status", 31);
std::strncpy(reinterpret_cast<char*>(report.values[2].value), "overheating", 63);
report.values[2].value_type = 0; // string
See Also
- Recipe: Emergency Stop — full safety monitor implementation
- Guide: Real-Time — watchdog and miss policies