Skip to main content
Back to selected work
Operator UX · robotics telemetry

Robot telemetry fault harness

Learning project — a MuJoCo → Foxglove harness with an answer key on the wire, so operator panels and detection rules can be judged instead of eyeballed.

Foxglove panels during a stale /pose fault — speed continues while attitude flatlines
Outcome

I built a small fault-injection harness because recorded robot telemetry rarely ships with ground truth — and I care about operator interfaces: what a human sees, and whether plausible plots still lie.

I’m not a roboticist. I’m a product designer and design engineer — sixteen years in UI, design systems, and front-end, based in Northern Virginia. The thread I keep pulling is operator and debug interfaces: what a human sees, when they get interrupted, and whether the UI still tells the truth when a stream goes wrong.

Why this exists

Most recorded robot data arrives without an answer key. You stare at plots, guess whether a flat line means “holding steady” or “last good sample on repeat,” and never know if your detection idea is sound. I wanted a bench where faults are scheduled, ground truth is published beside telemetry, and a rule can be scored — not vibes.

What I built

MuJoCo → Foxglove over the SDK websocket. The harness commands base attitude from a known trajectory and publishes that command alongside the telemetry stream, so every sample has an authoritative record of what the robot was supposed to be doing.

Faults are scheduled in JSON — torque loss, frozen joints, sensor bias and noise, dropout, staleness — with fault windows on their own topic. Physical failures and display failures are separable on purpose. Runs on Apple Silicon, no GPU, no ROS. There is an optional Go1 gait under a Playground-trained policy if you want locomotion data instead of a scripted base.

The teaching moment

The GIF is the point. Left panel is speed, middle is roll/pitch, right is yaw. Partway through, /pose goes stale — the last message repeats. Attitude and heading flatline while speed keeps moving, because speed reads /odom.

Animated Foxglove view: speed panel still moves while roll, pitch, and yaw flatline after /pose goes stale

Neither failure mode looks like a failure. Stale reads as a calm attitude hold. Dropout interpolates a straight segment that reads as a smooth slow turn. Both are plausible for a quadruped, and they do not even look like each other — so there is no single “broken data” shape to pattern-match.

The contradiction sits one panel over: translating at about 1 m/s while attitude stays perfectly flat for six seconds. Nothing in the UI correlates those signals. That is the same class of problem I work on in ops dashboards and commerce tooling — a picture that hides failure because it still looks reasonable.

Judgment calls I made

I put ground truth on the wire next to sensed data. Without that, you cannot tell whether a detection rule is right — only whether it feels right on one clip.

I split machine faults from display faults in the schedule. A torque drop and a stale topic are different failure classes; scoring rules should know which world they are in.

I optimized for scoring rules, not demo polish. The harness is ugly on purpose: JSON schedules, explicit fault windows, topics you can assert against — closer to a test fixture than a product tour.

Honest limits

Simulation is cleaner than field data. A synthetic stale /pose is not a radio drop, and a scripted base is not a tired quadruped on wet stone. I am still learning MuJoCo and Foxglove by wiring them myself — open to being wrong about what matters most in the stack.

One UX question I have not solved yet: how staleness should read in a time-series plot. Holding the last value looks like physics; breaking the line helps but feels arbitrary without a convention. I am exploring max-age per series — not settled.

Want to build something like this?

Let's talk about your project.

Next case study

Shop Canvas