Tutorial 9: Record & Replay (C++)
Record all topic data while your robot runs, then replay it offline for debugging. This is the robotics equivalent of a flight recorder.
What You'll Learn
- Using
horus recordCLI to capture topic data - Using
horus replayto play back recorded data - Using BlackBox for crash analysis
- Designing nodes that work with both live and recorded data
Recording Live Data
While your robot is running:
# Record all topics to a file
horus record --output session_001.horus
# Record specific topics only
horus record --topics lidar.scan,cmd_vel,odom --output drive_test.horus
# Record for 60 seconds
horus record --duration 60 --output minute_log.horus
The recording captures every message on every topic with nanosecond timestamps.
Replaying Recorded Data
Play back recorded data — your subscriber nodes see the same messages as during recording:
# Replay at original speed
horus replay session_001.horus
# Replay at 2x speed (for faster analysis)
horus replay session_001.horus --rate 2.0
# Replay specific topics only
horus replay session_001.horus --topics lidar.scan,odom
Designing for Replay
The key pattern: separate your processing nodes from your hardware drivers. Processing nodes subscribe to topics — they don't care if data comes from live hardware or a recording.
// This controller works identically with live OR recorded data
class Controller : public horus::Node {
public:
Controller() : Node("controller") {
scan_sub_ = subscribe<horus::msg::LaserScan>("lidar.scan");
cmd_pub_ = advertise<horus::msg::CmdVel>("cmd_vel");
}
void tick() override {
auto scan = scan_sub_->recv();
if (!scan) return;
// This code runs the same whether lidar.scan comes from
// a real LiDAR or from horus replay
float min_range = 999.0f;
for (int i = 0; i < 360; i++) {
float r = scan->get()->ranges[i];
if (r > 0.01f && r < min_range) min_range = r;
}
horus::msg::CmdVel cmd{};
cmd.linear = min_range > 0.5f ? 0.3f : 0.0f;
cmd_pub_->send(cmd);
}
private:
horus::Subscriber<horus::msg::LaserScan>* scan_sub_;
horus::Publisher<horus::msg::CmdVel>* cmd_pub_;
};
BlackBox for Crash Analysis
The BlackBox records events even if the process crashes:
// Record important events during operation
horus::blackbox::record("controller", "Obstacle detected at 0.3m");
horus::blackbox::record("safety", "E-stop triggered");
horus::blackbox::record("motor", "Current spike: 15A");
// After a crash, inspect with CLI:
// horus blackbox --last 100
// horus log --since "5 minutes ago"
Workflow
1. Run robot → horus record --output test.horus
2. Bug happens → stop recording
3. Fix controller → edit code, recompile
4. Test with replay → horus replay test.horus
5. Verify fix → no bug? ship it
No need to set up hardware again. No need to reproduce the exact scenario. The recording has everything.
Key Takeaways
horus recordcaptures all SHM topic data with timestampshorus replayplays it back — subscribers see the same messages- Design nodes as pure topic processors — they work with live AND recorded data
- BlackBox events survive crashes — use for safety-critical logging
- Replay at different speeds for fast iteration