Hex.pm Docs CI License

Terminal-based dashboard for Beam Bots robots. Built on ExRatatui.

BB.TUI Demo

Features

  • Safety controls — arm / disarm / force disarm with confirmation popup
  • Joint control panel — position table with type (revolute/prismatic/continuous), units (degrees/mm), visual range bars, target tracking, simulated joint markers, and direct position adjustment via keyboard (1% and 10% steps)
  • Event stream — scrollable, color-coded event list with formatted timestamps and message summaries; pause/resume, clear, and Enter to open a detail popup showing full payload
  • Commands panel — lists available robot commands with Ready/Blocked indicators based on runtime state. Argument-less commands execute on Enter; commands with declared arguments open an inline edit mode (Tab to cycle fields, type-to-edit, Enter to run, Esc to cancel). Argument types — boolean, integer, float, atom, enum ({:in, [...]}), string — are parsed before dispatch
  • Parameters panel — live parameter table grouped by path with real-time updates, plus bridge tabs for editing remote parameters
  • High-rate-safe — the event log debounces repeated sensor messages and renders coalesce to ~30fps, so fast telemetry never floods the log or stalls the UI
  • Status bar, help overlay, and theming — robot name / safety / runtime indicators, a scrollable keybinding reference, and a consistent semantic color palette
  • Keyboard-driven navigation — Tab to cycle panels, number keys to jump, vim-style j/k/h/l within panels
  • Three transports — local terminal, SSH (multiple isolated operator sessions), and Erlang distribution (attach a thin renderer to a TUI running on the robot node)
  • Runtime inspection — snapshot, trace, and inject events into a running TUI via ExRatatui.Runtime
  • Mix taskmix bb.tui --robot MyApp.Robot for standalone launch
  • Headless test suite — full coverage using Mimic and ExRatatui's test backend

Layout

 🤖 BB.TUI · MyApp.Robot                                                   title bar
 Safety  Joint Control 
  ARMED         Joint       Type  Position    Target              
 Runtime: Idle   elbow       rev   -63.8°      -90  90   60%
 a  arm          gripper SIM pri    30.6 mm      0  50   height
 d  disarm       wrist       rev    87.0° !    -90  90 
 Commands (2)  ...                                               
  home   Ready                                                   
   calibrate                                                       

 Events (47)  Parameters 
 18:23:12 sensor.sim       JointState 2 joint(s)                    
 18:23:11 state_machine    disarmed  armed                         

 MyApp.Robot   ARMED  idle   Tab panel  ? help  q quit  a arm  d disarm

Installation

Use Igniter to add bb_tui to a project. The installer imports formatter rules and prints a launch notice tailored to the chosen install shape. If the project already has a BB robot module (typically scaffolded by mix igniter.install bb):

mix igniter.install bb_tui
mix igniter.install bb_tui --robot MyApp.Arm

The install shape can be tuned with flags:

  • --auto-bb — scaffold a BB robot via bb.install when none is present (skips the interactive prompt).
  • --ssh — append a supervised {BB.TUI, …} child wired for an SSH daemon, so the dashboard is reachable as soon as the app boots. Accepts --port, --user, --password. Idempotent; change the generated credentials before deploying.
  • --nerves — register BB.TUI.subsystem(<Robot>) under config :nerves_ssh, :subsystems so the dashboard rides on an existing nerves_ssh daemon.

Local dashboards are not supervised — a child that claims the terminal on boot would fight an IEx session for stdin/stdout — so the local entry points are mix bb.tui and BB.TUI.run/1. See mix help bb_tui.install for the full option reference, and the Transports guide for SSH and distribution setups.

To skip Igniter, add the dep directly:

def deps do
  [
    {:bb_tui, "~> 0.1"}
  ]
end

Quick Start

Standalone, via the mix task:

mix bb.tui --robot MyApp.Robot

From IEx:

BB.TUI.start(MyApp.Robot)

Under a supervision tree:

children = [
  {BB.Supervisor, MyApp.Robot},
  {BB.TUI, robot: MyApp.Robot}
]

Serving the dashboard over SSH or attaching to a robot on another BEAM node is covered in the Transports guide. The full key reference lives in the Keybindings guide (and in the in-app ? overlay).

How It Works

BB stores state in ETS and publishes changes over PubSub. The TUI subscribes to the [:state_machine], [:sensor], and [:param] paths, takes a one-time ETS snapshot on mount, then keeps state fresh from PubSub messages. Keyboard events call BB APIs directly (safety, actuator, command execution) — there are no optimistic updates, so the dashboard is a faithful reflection of the robot's actual state.

All state transitions live in BB.TUI.State as pure functions — no side effects, no process communication — which makes the dashboard easy to test headlessly. BB.TUI.App wires input and async results to those transitions through ExRatatui's reducer runtime.

Robots can publish sensor data faster than a terminal can usefully redraw, so the event log debounces repeats of the same {path, payload-type} within a one-second window, and sensor-driven renders coalesce to at most one frame every ~33ms (~30fps). Key presses, command results, and safety/parameter/state changes still render immediately. Both windows are fields on BB.TUI.State.Throttle.

Configuration

KeyDefaultNotes
:bb_tui, :command_timeout30_000 msWait window for BB.Command.await/2 on commands dispatched from the UI. Compile-time only — downstream apps need mix deps.compile bb_tui --force after changing it.
# config/config.exs
config :bb_tui, command_timeout: 30_000

Development

The project ships a simulated WidowX-200 robot arm that starts automatically in dev:

mix deps.get
mix bb.tui --robot Dev.TestRobot

Dev.TestRobot exercises every panel feature end-to-end:

  • Commands with all argument shapes — home (no args), move (enum + float), log (string + integer), wobble (always returns {:error, :wobble_failed}), calibrate (sleeps ~2s so the throbber is visible), and stream (emits a high-rate JointState burst to show debounce + render coalescing).
  • Parameter groups covering every primitive type — float, integer, boolean, atom — most with :min / :max so 1%-of-range stepping applies.
  • A :mavlink bridge (Dev.MockBridge) with a fixed remote-parameter list and in-memory writes — press t in the Parameters panel to cycle to the Bridge tab.

Exercising the SSH and Erlang-distribution transports against the simulated robot is covered in the Transports guide.

Guides

GuideDescription
TransportsServe the dashboard over SSH or attach over Erlang distribution, inspect a running session, and test both locally
KeybindingsFull per-panel key reference, including command argument editing and parameter stepping
Telemetry:telemetry events for mount, input, dispatch, and frames — logging and Telemetry.Metrics

Contributing

See CONTRIBUTING.md for development setup and guidelines.

BB.TUI is built on ExRatatui - a general-purpose terminal UI library for Elixir, and Beam Bots - robotics framework. Contributions to underlying libraries are very welcome too.

License

Apache-2.0 — see LICENSE.