The monitor¶
btview (or btview tui) opens a full-screen view built on
Textual. It runs in the alternate screen, so your
scrollback is intact when you quit.
┌ MainTree · 192.168.1.42:1667 · v4 ──────────────┬─ node ───────────────────┐
│ ▼ ▶ [!] NavigateRecovery [RecoveryNode] │ name FollowPath │
│ ├── ▼ ▶ [=] NavigateWithReplanning │ type FollowPath │
│ │ ├── ▼ ▶ -^- RateController │ uid 8 │
│ │ │ └── ▼ ✔ [!] ComputePathToPose │ status ▶ RUNNING │
│ │ │ ├── · --> ComputePathToPose │ in state 1.4s │
│ │ │ └── · --> ClearGlobalCostmap │ counters ran 3 ok 2 │
│ │ └── ▼ ▶ [!] FollowPath [RecoveryNode] │ ports path = {path} │
│ │ ├── ▶ --> FollowPath ├─ transitions ────────────┤
│ │ └── · --> ClearLocalCostmap │ 13:13:29.2 ·→▶ FollowPath│
│ └── ▼ · [o] RecoveryFallback │ 13:13:28.4 ✔→▶ RateCtrl │
│ ├── · (?) GoalUpdated │ 13:13:28.2 ▶→✔ ComputeP… │
│ └── ▼ · (o) RecoveryActions [RoundRobin] │ 13:13:27.6 ·→▶ ClearGlo… │
├─────────────────────────────────────────────────┴──────────────────────────┤
│ follow 16 nodes ▶5 ✔1 ·10 ● live │
│ q quit r refresh f follow a active only p pause / search ? help │
└────────────────────────────────────────────────────────────────────────────┘
Panels¶
Tree (left) — one row per node: status glyph, node-type glyph, then the name. The status leads so it is never the thing that gets truncated on a narrow terminal. The border title shows the tree name, the endpoint and the protocol.
Node (top right) — everything known about the row under the cursor: instance name, registration, uid, full path, live status, how long it has held that status, how many times it has run/succeeded/failed this session, its port remappings, and a sparkline of its recent statuses. The sparkline is the quickest way to catch a node that is flapping: a run of alternating green and red shows up there long before you spot it in the event log.
Transitions (bottom right) — every status change, newest first, with a timestamp to the millisecond. This is the panel that answers "what just happened?" after a tree flickers.
Summary bar — node counts by status, the active modes, a connection indicator that turns red with the error text when polling fails, and a sparkline of how many nodes were running over the last few dozen polls. A tree that is ticking normally has a lively strip; a flat line means the robot stopped doing anything.
Keys¶
| Key | Action |
|---|---|
| ↑ ↓ / k j | Move the cursor |
| ← → | Collapse / expand a branch |
| Space Enter | Toggle a branch |
| e / c | Expand all / collapse all |
| f | Follow — keep the cursor on the running leaf |
| a | Active only — hide branches that are neither running nor failing |
| g | Graph — swap the list for a drawn graph of the tree |
| / | Filter by name (Esc clears) |
| p | Pause / resume polling |
| r | Re-fetch the tree definition |
| s | Save a JSON snapshot to the working directory |
| b | Fetch the blackboard (v4 publishers) |
| ? | Help |
| q | Quit |
Follow is on by default: the cursor tracks the deepest running leaf, so the inspector always shows what the robot is actually doing. Moving the cursor yourself turns it off; f turns it back on.
Graph view¶
g swaps the indented list for the tree drawn as a graph, the way people sketch it on a whiteboard:
╭────────────────────╮
│ ▶ NavigateRecovery │
╰──────────┬─────────╯
╭─────────────────────┴─────────────────────╮
╭────────┴───────────╮ ╭──────────┴─────────╮
│ ▶ NavigateWithRepl…│ │ · RecoveryFallback │
╰──────────┬─────────╯ ╰──────────┬─────────╯
Boxes are coloured by status, and the node in focus gets a heavy border so you can keep track of it while the colours change around it. The pane scrolls (mouse drag or the scrollbars) and, while follow is on, it scrolls itself to keep the running node in view — which matters, because a real Nav2 tree is a few hundred columns wide.
Use the list for hunting a specific node; use the graph for seeing which branch the robot is down and how deep it is. The same drawing is available outside the TUI:
Status glyphs¶
| Glyph | Status | Colour |
|---|---|---|
▶ |
RUNNING | cyan |
✔ |
SUCCESS | green |
✖ |
FAILURE | red |
⊘ |
SKIPPED | magenta |
· |
IDLE | grey |
· was SUCCESS |
idle, but ran earlier this tick cycle | dim green |
That last one is worth knowing. BehaviorTree.CPP reports a node that has been halted but
already produced a result, and btview dims it rather than showing a bare IDLE — so you
can still see which branch succeeded before the tree moved on.
Node-type glyphs¶
| Glyph | Type | Glyph | Type | |
|---|---|---|---|---|
[-] |
sequence | [!] |
recovery | |
[o] |
fallback | (o) |
round robin | |
{-} {o} |
with memory | -^- |
decorator | |
[=] |
pipeline sequence | --> |
action | |
/_/ |
parallel | (?) |
condition | |
[+] |
subtree |
These follow py_trees' conventions. Types come from the publisher's own node model
(<TreeNodesModel> in v4, node_models in v3); when a tree does not advertise one,
btview falls back to BehaviorTree.CPP's built-in names and then to the shape of the tree.
Subtrees¶
SubTree nodes are expanded in place, showing the child tree's nodes inline the way Groot2
does. Repeated instantiations of the same subtree get their own copies with their own uids,
so two instances show their own statuses.
Terminals¶
The UI is built for a 100×30 terminal or larger, and degrades sensibly below that: the sidebar keeps a minimum width, long labels ellipsize, and the transition log truncates names rather than wrapping.
For terminals without unicode or colour:
btview --ascii # `+-` and `*` instead of `├─` and `▶`
NO_COLOR=1 btview
btview watch --ascii # no alternate screen at all
When the link drops¶
Polling happens on a worker thread, so a robot that stops answering never freezes the UI. The tree stays on screen with its last known statuses, the indicator turns red, and the error appears in the summary bar. When the robot comes back, polling resumes on its own — press r if the tree itself changed while you were disconnected.