Hello — first, thank you for bdsim and the recent realtime work. I've been reading through feat/realtime, the design
docs (REALTIME_IO_DESIGN.md, TELEMETRY_CONTROL_DESIGN.md, docs/realtime-refactor-plan.md), and the CHANGELOG for
1.2.0 / 1.3.0, and I'd like to discuss adding a third runner that fits the "Option B (separate runners)" pattern
established in the realtime refactor plan.
Following CONTRIBUTING.md, I'm filing this for design discussion before any code. I'm not asking you to build anything —
I'd do the work and submit a PR if there's alignment. I just want to make sure it lands as something you'd welcome, in a
shape consistent with where you're already taking bdsim.
The use case
I'm working on a motor-driven hardware project that needs simulation during development for decision-making and
controller design. To support that, I'm building an interactive simulation app — a fixed-frame UI loop running at ~60
Hz, with the user driving the sim live:
- Sliders for tuning controller gains while the sim runs
- 2D pad widgets for vector inputs (force injection to perturb the system and observe response)
- Checkbox / dropdown for boolean / enum inputs
- Live plotting of selected signals over time for analysis
- Pause / playback-rate control (0.5×, 1×, 2×)
- Scrub-back through history via snapshot / restore
- All while the underlying physics + control graph evaluates
The idea is to use the bdsim graph as the design-and-validation environment for both control logic and hardware
choices before any firmware writing or procurement happens. Sliders to swap between candidate motors / drivers /
sensors and see how the closed loop behaves; tweaking geometry parameters (mounting offsets, arm lengths, CG locations)
interactively to find what's actually feasible; comparing alternatives side-by-side without rebuilding the world each
time. The control-logic-tuning use case is one slice of a broader hands-on design loop.
Why bdsim
I did a survey of Python node-graph / dataflow libraries (ryvencore, simupy, python-control, RxPy, streamz, OpenMDAO,
etc.). bdsim is the closest fit — the Block ABC, the Clock primitive, hybrid continuous + discrete scheduling, the
algebraic-loop check, and scipy.integrate.solve_ivp integration are all exactly what I want. The math layer is
excellent.
What's missing for the interactive-app use case is a runner that allows external pump (advance(dt) style), live
parameter mutation between advances, and snapshot / restore for scrub-back. BDSim.run() is batch (owns the time loop
end-to-end); BDRealTime.run() is hardware-realtime (blocks until tf at wall-clock rate). Neither directly supports a
UI driving the sim at 60 Hz with playback_rate control.
The proposal: BDLiveSim as a third runner
A separate runner alongside BDSim and BDRealTime, fitting the Option B pattern from
docs/realtime-refactor-plan.md:
| Runner |
Use case |
Time model |
BDSim.run(bd, T=10) |
Offline batch / validation |
As-fast-as-possible |
BDRealTime.run(bd, tf=20) |
Hardware control on RPi etc. |
Wall-clock realtime |
BDLiveSim |
UI-driven interactive sim |
Wall-locked × playback_rate |
Sketch of the API (just enough to ground discussion):
sim = BDLiveSim(bd)
sim.compile()
sim.start() # records t=0 snapshot
# in UI's 60 Hz frame loop:
def on_frame(wall_dt):
sim.advance(wall_dt * sim.playback_rate)
snap = sim.snapshot() # capture for plot / scrub buffer
render(snap)
# user dragging a slider:
def on_slider_change(block, param, value):
setattr(block, param, value) # takes effect next advance
# user scrubbing back:
def on_scrub_to(t):
sim.restore(snapshot_buffer[t])
Internally, advance(dt) would loop similarly to BDSim.run()'s while t0 < tf body — pulling the next event from the
eventq, running _interval_hybrid to that boundary, etc. — but exit when sim_t reaches the requested target rather
than running to a fixed tf. Reuses Clock, the algebraic-loop check, solve_ivp, the Block ABC — everything that lives
below the runner level.
BDLiveSim is the runner; UI is separate
To be explicit: this proposal is for the runtime layer only — BDLiveSim is UI-framework-agnostic and ships without
one, the same way BDSim ships without a GUI. The advance(dt) / snapshot() / setattr(block, param, value) surface
is a programmatic API any UI can drive.
Concrete UIs that could be built on top:
- bdedit-style desktop GUI (Qt) —
bdedit could grow a "live mode" that creates a BDLiveSim per loaded diagram,
drives it from a Qt timer, and routes property-panel edits through setattr.
- bdweb's web frontend — its FastAPI backend maps HTTP requests directly onto
BDLiveSim methods. Run button calls
sim.advance(dt); slider input calls setattr; scrub bar calls sim.restore(snap).
- Custom UIs in the host's own framework — I've currently built a first attempt at an interactive app in DearPyGui,
but the same backend would work behind any UI framework (PySide, web, Tkinter, terminal, headless test driver).
This mirrors the bdsim core / bdedit / bdweb separation that's already established — the runner doesn't depend on any
specific UI; specific UIs are built to use it.
Alignment with in-flight work
A few things you've recently built or planned that this proposal would benefit from / contribute to:
- 1.2.0's protected Block attributes ("This allows for discovery of parameters for possible run-time changing") —
this is the foundation for live parameter mutation in BDLiveSim.
TELEMETRY_CONTROL_DESIGN.md Phases C and D (parameter registry with type metadata, bounds, mutability flags,
"apply at next clock tick" semantics) — the same infrastructure that would power remote parameter control over network
would power local UI-driven mutation. Could be designed once, used by both.
- bdweb's runner gap — from the commit history (the Apr/May 2026 bdweb work on the cleanup branch), the frontend has
a Run button wired up but it isn't yet hooked to a working backend runner (per the commit message on 392ae7f).
BDLiveSim is exactly that backend runner: bdweb's FastAPI server would receive HTTP requests from the frontend and
translate them into sim.advance(dt) / sim.snapshot() / setattr(block, param, value) calls. If you'd been
intending to build that runner as part of bringing bdweb to life, this proposal could be it.
Questions for you
- Is this a direction you'd welcome? If not, no problem — I'll explore other approaches.
- If yes, is there a design constraint I should know about upfront — e.g., a different shape you'd prefer (single
runner with mode flags? subclass of BDRealTime? something else)?
- Is there alignment work I should do with the in-flight 1.3.0 changes before starting? I don't want to design against
an API surface that's actively shifting.
- Would you prefer I prototype small first and discuss the shape, or write up a more detailed design doc before any
code?
I'm in no rush — happy to wait for a thoughtful response and align with your direction. Thanks again for the work you've
put into bdsim.
Hello — first, thank you for bdsim and the recent realtime work. I've been reading through
feat/realtime, the designdocs (
REALTIME_IO_DESIGN.md,TELEMETRY_CONTROL_DESIGN.md,docs/realtime-refactor-plan.md), and the CHANGELOG for1.2.0 / 1.3.0, and I'd like to discuss adding a third runner that fits the "Option B (separate runners)" pattern
established in the realtime refactor plan.
Following CONTRIBUTING.md, I'm filing this for design discussion before any code. I'm not asking you to build anything —
I'd do the work and submit a PR if there's alignment. I just want to make sure it lands as something you'd welcome, in a
shape consistent with where you're already taking bdsim.
The use case
I'm working on a motor-driven hardware project that needs simulation during development for decision-making and
controller design. To support that, I'm building an interactive simulation app — a fixed-frame UI loop running at ~60
Hz, with the user driving the sim live:
The idea is to use the bdsim graph as the design-and-validation environment for both control logic and hardware
choices before any firmware writing or procurement happens. Sliders to swap between candidate motors / drivers /
sensors and see how the closed loop behaves; tweaking geometry parameters (mounting offsets, arm lengths, CG locations)
interactively to find what's actually feasible; comparing alternatives side-by-side without rebuilding the world each
time. The control-logic-tuning use case is one slice of a broader hands-on design loop.
Why bdsim
I did a survey of Python node-graph / dataflow libraries (ryvencore, simupy, python-control, RxPy, streamz, OpenMDAO,
etc.). bdsim is the closest fit — the Block ABC, the
Clockprimitive, hybrid continuous + discrete scheduling, thealgebraic-loop check, and scipy.integrate.solve_ivp integration are all exactly what I want. The math layer is
excellent.
What's missing for the interactive-app use case is a runner that allows external pump (
advance(dt)style), liveparameter mutation between advances, and snapshot / restore for scrub-back.
BDSim.run()is batch (owns the time loopend-to-end);
BDRealTime.run()is hardware-realtime (blocks untiltfat wall-clock rate). Neither directly supports aUI driving the sim at 60 Hz with
playback_ratecontrol.The proposal:
BDLiveSimas a third runnerA separate runner alongside
BDSimandBDRealTime, fitting the Option B pattern fromdocs/realtime-refactor-plan.md:BDSim.run(bd, T=10)BDRealTime.run(bd, tf=20)BDLiveSimSketch of the API (just enough to ground discussion):
Internally,
advance(dt)would loop similarly toBDSim.run()'swhile t0 < tfbody — pulling the next event from theeventq, running_interval_hybridto that boundary, etc. — but exit when sim_t reaches the requested target ratherthan running to a fixed
tf. ReusesClock, the algebraic-loop check, solve_ivp, the Block ABC — everything that livesbelow the runner level.
BDLiveSimis the runner; UI is separateTo be explicit: this proposal is for the runtime layer only —
BDLiveSimis UI-framework-agnostic and ships withoutone, the same way
BDSimships without a GUI. Theadvance(dt)/snapshot()/setattr(block, param, value)surfaceis a programmatic API any UI can drive.
Concrete UIs that could be built on top:
bdeditcould grow a "live mode" that creates aBDLiveSimper loaded diagram,drives it from a Qt timer, and routes property-panel edits through
setattr.BDLiveSimmethods. Run button callssim.advance(dt); slider input callssetattr; scrub bar callssim.restore(snap).but the same backend would work behind any UI framework (PySide, web, Tkinter, terminal, headless test driver).
This mirrors the bdsim core / bdedit / bdweb separation that's already established — the runner doesn't depend on any
specific UI; specific UIs are built to use it.
Alignment with in-flight work
A few things you've recently built or planned that this proposal would benefit from / contribute to:
this is the foundation for live parameter mutation in
BDLiveSim.TELEMETRY_CONTROL_DESIGN.mdPhases C and D (parameter registry with type metadata, bounds, mutability flags,"apply at next clock tick" semantics) — the same infrastructure that would power remote parameter control over network
would power local UI-driven mutation. Could be designed once, used by both.
a Run button wired up but it isn't yet hooked to a working backend runner (per the commit message on
392ae7f).BDLiveSimis exactly that backend runner: bdweb's FastAPI server would receive HTTP requests from the frontend andtranslate them into
sim.advance(dt)/sim.snapshot()/setattr(block, param, value)calls. If you'd beenintending to build that runner as part of bringing bdweb to life, this proposal could be it.
Questions for you
runner with mode flags? subclass of
BDRealTime? something else)?an API surface that's actively shifting.
code?
I'm in no rush — happy to wait for a thoughtful response and align with your direction. Thanks again for the work you've
put into bdsim.