On-robot reliability: systemd hardening, health monitoring, startup self-checks#51
Open
MJohnson459 wants to merge 1 commit into
Open
On-robot reliability: systemd hardening, health monitoring, startup self-checks#51MJohnson459 wants to merge 1 commit into
MJohnson459 wants to merge 1 commit into
Conversation
…-check Make the robot survive unattended operation: services recover when they die, subsystem health is continuously published, and a pre-flight self-check proves the hardware is ready before a mission is accepted. systemd hardening (mote-bringup/slam/nav/record): - Restart=always with backoff (RestartSec=2, RestartSteps=5, RestartMaxDelaySec=30) and StartLimitIntervalSec=0 so an unattended robot self-heals when reconnected hardware reappears without hammering the bus. - Device ordering: udev tags the servo/lidar devices TAG+="systemd" so bringup can order After=/Wants= dev-mote_*.device. - BindsTo/PartOf so slam/nav follow bringup; record/health are non-fatal. - journald-mote.conf bounds the persistent journal so restart loops can't fill the SD card. Installed by systemd/install.sh (still one `pixi run setup`). Health monitor (health_monitor.py -> mote-health.service, `pixi run health`): - Per-subsystem liveness/rate checks (scan, filtered scan, joint states, camera, odom TF, localisation TF) folding in system_monitor's host status and the last self-check verdict. - Publishes diagnostic_msgs/DiagnosticArray on /diagnostics_agg and a single OK/DEGRADED/FAULT summary on /health (std_msgs/String). - Type=notify + WatchdogSec watchdog fed by sd_notify.py (dependency-free, no-ops outside systemd), so a hung monitor is restarted. Startup self-check (self_check.py, `pixi run self-check`): - Runs as mote-bringup ExecStartPre; gates on servo ping (new servo_ping C++ tool), lidar/camera device presence, disk, clock sanity, config/site load. - Critical failure -> non-zero exit blocks the launch (safe idle, clear reason); systemd retries with backoff so replugging recovers on its own. - Writes $MOTE_HOME/self_check_status.yaml, surfaced by the health monitor. Per-node recovery: respawn=True on the drivers (mote_launch.py) and nav2 servers (nav2_launch.py) so a single crashed node is relaunched under the whole-service systemd restart. Chaos validation (test/chaos/): chaos_policy_demo.sh proves the systemd restart policy locally (committed chaos_log.txt: killed service back in ~2s); chaos_restart.sh kills ros2_control_node/sllidar_node/controller_server on the robot and verifies respawn — to be benched on auldbot. Battery voltage remains unmeasurable in software (the power bank exposes no telemetry); documented as a follow-up. Verified: `pixi run build` clean; 36 mote_bringup tests pass (18 new); systemd-analyze verify clean on all units; self-check correctly blocks on missing devices; health monitor publishes a rolled-up FAULT; lint/shellcheck pass. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01KLVgV7kwyBkroULWrq5hAv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On-robot reliability: systemd hardening, continuous health monitoring, and a pre-flight startup self-check so the robot survives unattended operation. Branch
reliability-hardening(1 commit,pixi run buildclean, 36 mote_bringup tests pass, lint/shellcheck green,systemd-analyze verifyclean on all units).What changed
systemd hardening (
mote-bringup/slam/nav/record+ newmote-health)Restart=alwayswith backoff (RestartSec=2,RestartSteps=5,RestartMaxDelaySec=30) andStartLimitIntervalSec=0— recovers from clean exits too and never latches into a permanent failed state, so the robot self-heals when reconnected hardware reappears, while backoff prevents bus hammering.TAG+="systemd", so bringup ordersAfter=/Wants=dev-mote_servos.device/dev-mote_lidar.device(waits for enumeration, no hard-bind on mid-run flaps).BindsTo/PartOfso slam→nav follow bringup; record/health are non-fatal to the drive stack.journald-mote.confbounds the persistent journal (500M/2wk) so restart loops can't fill the SD card. Installed bysystemd/install.sh— still onepixi run setup.Health monitor (
health_monitor.py→mote-health.service,pixi run health)system_monitor's host status and the last self-check verdict.diagnostic_msgs/DiagnosticArrayon/diagnostics_agg(fleet-consumable) and a singleOK/DEGRADED/FAULTline on/health(std_msgs/String, easyros2 topic echo). Criticality drives the roll-up: stale critical subsystem → FAULT, stale non-critical/slow → DEGRADED. Config inconfig/health.yaml(~/.moteoverride).Type=notify+WatchdogSec=15watchdog, fed bysd_notify.py(dependency-free$NOTIFY_SOCKETclient, no-ops outside systemd) — a hung monitor is restarted.Startup self-check (
self_check.py,pixi run self-check)mote-bringup'sExecStartPregate: servo bus ping (newservo_pingC++ tool, IDs fromrobot.yaml), lidar/camera device presence + openability, disk space, clock sanity (RTC-less Pi at epoch), config/site load.$MOTE_HOME/self_check_status.yaml, surfaced by the health monitor.Per-node recovery —
respawn=Trueon the drivers (mote_launch.py) and nav2 servers (nav2_launch.py; lifecycle managers getattempt_respawn_reconnection), so a single crashed node is relaunched inside the whole-service systemd restart.Chaos validation (
mote_bringup/test/chaos/)chaos_policy_demo.sh— hardware-free, proves the systemd restart policy locally via a transient--userunit. Committedchaos_log.txtshows a SIGKILLed service back with a new PID in ~2s.chaos_restart.sh(pixi run chaos) — killsros2_control_node/sllidar_node/controller_serveron the robot and verifies respawn within 30s. Safe by construction (matches executable names, excludes own PID).Acceptance criteria
chaos_log.txt./healthshows OK/DEGRADED/FAULT transitions (verified: monitor publishes a rolled-up FAULT with all critical subsystems stale).mote_bringup/README.md, CLAUDE.md, tools README).Needs bench with Michael (hardware-gated, not runnable from CI)
chaos_restart.shon auldbot (per-node respawn end-to-end) — capture itschaos_log.txt./healthOK↔DEGRADED↔FAULT transition by physically unplugging a sensor.servo_pingagainst the drive bus (validated as a clean build only; no hardware here).pixi run setupon the Pi to install the newmote-healthunit + journald drop-in.Note: not pushed (per the no-remote-writes rule);
voro prwill open the PR from this summary.