Most robot bugs are not found by staring at code. They are found by watching what the robot actually did — which means a recording, a timeline, and a disciplined way of moving from “it behaved strangely” to the minute, then the second, then the signal where behaviour diverged. This workflow uses PlotJuggler as the investigation desk: record the run, load the recording, align the signals in time, derive the quantities that are not logged directly, and save the whole view as a layout you can reuse on the next run and hand to a colleague.
Step 1: Record with debugging in mind
A debugging session starts before PlotJuggler opens. Record the run in the format your stack already produces — a ROS bag or an MCAP recording are the common cases — and record the topics you would want if something went wrong, not only the topics for the feature you are testing. Note the wall-clock time of anything you observe in the room: a bump, a pause, a missed grasp. That single note is often the difference between a ten-minute investigation and an afternoon of scrubbing. Our guide to reading rosbag and MCAP files in PlotJuggler covers loading both formats, including what to check when a recording does not open as expected.
Step 2: Load, orient, and narrow the window
Load the recording and first read it at the widest level: when did the robot start moving, when did the task end, and where does the observed problem sit? Plot a small set of high-level signals — commanded versus actual motion is the classic pair — and zoom into the window around your noted timestamp. Resist adding more series until the window is right. Debugging fails by drowning: fifty plotted topics will always contain something that looks odd, somewhere.
Step 3: Align signals with time offset
Signals recorded by different parts of a system rarely share a perfect clock, and a cause can appear to follow its effect if two series are offset. PlotJuggler’s per-curve time offset exists for exactly this: shift one series until events that happened together line up together, then judge the relationship. The dedicated walkthrough is PlotJuggler time offset: aligning signals that do not line up. Alignment is also the step that makes sensor-versus-command comparisons honest — a “lag” that disappears after a small offset was never a control problem; it was a timestamp problem, which is a different bug and a different fix.
Step 4: Derive what was not logged
The signal that proves a root cause is often not in the recording at all — it is a combination of signals that are. PlotJuggler’s transform tools cover the common cases two ways. Built-in transforms give you derivatives, integrals, moving averages and scaling without code. For anything bespoke, custom functions do the job: Lua has been the scripting route on the established line, and PlotJuggler 4 adds Python alongside it, as our PlotJuggler 4 Python scripting guide explains. Typical derived series in a debugging session include an error signal (command minus actual), a rate (the derivative of a position), and a combined condition that only matters when two states coincide. Build the derived series, plot it in the narrowed window, and the question usually answers itself.
Step 5: Save the investigation as a layout
When the view finally shows the problem clearly, save it as a layout before you touch anything else. A saved layout preserves which series are plotted, where, and — on PlotJuggler 4’s layout format — the viewport and offsets as well, so the same investigation can be reopened on tomorrow’s recording in one step. The how-to is saving and sharing PlotJuggler layouts. Treat good layouts like good tests: one per recurring question (“why did navigation pause?”, “why did the arm overshoot?”), named for the question, and shared with the team so root-cause analysis stops depending on who holds the mouse.
The workflow in one pass
- Record generously, and note the wall-clock time of anything you see go wrong.
- Load the bag or MCAP file and narrow to the window around that note.
- Align series with time offset before judging cause and effect.
- Derive the missing quantity with a built-in transform or a Lua/Python custom function.
- Confirm the pattern in the window, then check whether it appears elsewhere in the run.
- Save the layout, named for the question it answers, and reuse it on the next recording.
Followed in order, that sequence turns debugging from folklore into a repeatable method — and each step leaves an artefact (the recording, the offsets, the derived series, the layout) that someone else can check.
