Diagnostics Messages (C++)

System health and safety types in horus::msg::. Include via <horus/msg/diagnostics.hpp>.

Quick Reference

TypeKey FieldsUse Case
Heartbeatnode_id[32], sequence, alive, cpu_usage, memory_usageNode liveness
EmergencyStopengaged (u8), reason[64], source[32], auto_resetSafety stop
DiagnosticStatuslevel (0-3), message[256]Component health
ResourceUsagecpu_percent, memory_mb, disk_percentSystem resources
NodeHeartbeatnode_name[32], tick_rate, cpu_usage, uptime_msPer-node metrics
SafetyStatussafe (bool), confidence, last_fault[128]Safety system state
DiagnosticValuekey[32], value[64], value_typeKey-value diagnostic
DiagnosticReportcomponent[32], values[16], levelMulti-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