`esw.visualization`
Live plotting for bench testing, so you can watch a target and an actual value converge while a control loop runs.
AsyncPlotter
Section titled “AsyncPlotter”A context manager that runs matplotlib in a separate process, so plotting cannot stall the loop feeding it data.
AsyncPlotter( labels: tuple[str, ...] = ("Target", "Actual"), max_size: int = 200, loop_delay: float = 0.05, x_label: str = "", y_label: str = "",)| Argument | Meaning |
|---|---|
labels | one line per label, and the arity send_data expects |
max_size | samples retained; older ones scroll off |
loop_delay | redraw interval in seconds |
x_label, y_label | axis labels |
| Method | Signature |
|---|---|
send_data | send_data(*values: float) |
send_data timestamps each sample relative to when the plotter started. Passing the wrong number
of values logs a warning rather than raising.
from esw.can.canbus import CANBusfrom esw.can.dbc import get_dbcfrom esw.visualization.async_plotter import AsyncPlotter
TARGET = 1.0
with AsyncPlotter(labels=("Target", "Actual"), y_label="position (rad)") as plot: with CANBus(get_dbc(dbc_name="MRoverCAN"), "can0") as bus: while True: bus.send("BMCTargetCmd", {"target": TARGET, "target_valid": 1}, dest_id=0x67) msg = bus.recv(timeout=0.1) if msg and msg[0] == "BMCMotorState": plot.send_data(TARGET, msg[1]["position"])The child process ignores SIGINT, so Ctrl+C is handled by the parent and the plot window shuts
down with it.