# Program from the Steam Deck pendant

> Use the native v5 teach pendant on a Steam Deck to connect a cell, arm, jog with the hold-to-enable trigger, record waypoints, edit the program, plan it with the weld planner, preview it and run it.

URL: https://advancedmetalresearch.com/docs/guides/program-from-the-pendant
Section: RosieOS docs / Guides
Last updated: 2026-10-10

The v5 teach pendant is a native Qt app for the Steam Deck's 1280×800 screen. It edits the same programs as the offline programming (OLP) desktop app, because it runs OLP's own program and machine logic inside the app. It talks to a headless OLP server on the Deck, and that server holds the machine session through rt-control.

> [!WARNING] **Energised motion.** This moves the robot. RosieOS has no software E-stop: keep the hardware E-stop within reach and clear the cell before you arm. Jog, moves and Home are checked against joint limits only, not against collisions. See the [safety model](https://advancedmetalresearch.com/docs/get-started/safety-model).

> [!CAUTION] **The v5 pendant is not qualified for real motion.** Physical stick, trigger and rear-button handling, real robot motion, network fault handling and a full plan, Load and Play on the Deck have not been qualified, and no CI builds it. The hold-to-enable trigger is a software deadman, not a safety-rated enabling device. Use it in [simulation](https://advancedmetalresearch.com/docs/guides/run-in-simulation) until the cell owner has qualified it.

To install it on a Deck, see [Build and install the pendant](https://advancedmetalresearch.com/docs/guides/install-the-pendant). Every control is listed in [Pendant controls](https://advancedmetalresearch.com/docs/reference/pendant-controls).

## How it fits together

- **The app** (`rosie-pendant-v5`) is the only user interface. It reads the gamepad from `/dev/input/js0` to `js3`.
- **The OLP server** runs headless on `127.0.0.1:8794` as a systemd user unit, `rosie-v5-olp`. It owns the machine session and serves connect, arm, stop, heartbeat, jog, move, Load and Play, the robot catalogue and planning. The app never talks to rt-control directly.
- **Planning** goes from the Deck's OLP server to a weld planner on a workstation the Deck can reach.

Because rt-control admits one controller at a time, a desktop OLP or another client holding the same cell locks the pendant out, and the other way round. See [One controller at a time](https://advancedmetalresearch.com/docs/get-started/safety-model#one-controller).

Closing the app stops the OLP server. Its shutdown stops any machine it armed before it releases control. Starting the app never arms, homes or moves anything.

## The screen

The header shows the program name, its save state (**LOCAL**, **SAVED** or **UNSAVED**), the connected cell and its posture, the **Arm** pill and **■ STOP**. Below it are five pages, which you cycle with **L1** and **R1**:

| Page | Use it to |
|---|---|
| **JOG** | Jog joints or the tool, and record waypoints, beside the 3D view |
| **PROGRAM** | Edit the program's node spreadsheet |
| **RUN** | Plan, preview, load, play and stop |
| **TELEMETRY** | Watch the drives' plots |
| **CELL** | Connect a cell, home it, and match the program's robot settings to it |

**■ STOP** (B, R5, Esc) works on every page and in every dialog. It stops the robot and also disarms. It is a software stop: it is not the hardware E-stop, and a stop receipt does not prove the robot has stopped moving.

**Menu** opens the controls guide. **View** jumps to the CELL page.

## 1. Connect a cell

On **CELL**, the list shows the cells in the Deck's cell catalogue (`olp-cells.json`). Tap one to connect. Connecting checks the cell's identity; it never arms.

- **HOME AXES** asks the cell to run Home. It appears when the cell supports native Home. Home is not verified against collisions.
- **PULL CELL SETTINGS** copies the cell's robot settings and calibration into the program.
- **ACCEPT CURRENT SETTINGS** adopts the current robot description when the program was written against an older one. Plan again and verify before you run.
- **DISCONNECT** and **REFRESH** do what they say.

The steps below the list follow OLP's machine steps, so you can see what is still missing before you can arm or load.

## 2. Arm

Hold **R2** and press **A**, or tap the **Arm** pill. On a real machine the pill changes to **CONFIRM ARM · A**: press **A** again to confirm, or **CANCEL**. Arming acquires control and energises the drives.

## 3. Jog

On **JOG**, nothing moves unless you hold **R2**, the hold-to-enable trigger. Release it and the jog stops.

- **Joints**: press **D-pad ▲▼** to pick a joint, then hold **R2** and push the **left stick** up or down.
- **Cartesian**: press **L3** to switch. Hold **R2** and use the left stick for X and Y, the right stick up and down for Z and left and right for RZ. Add **L2** to turn the left stick into RX and RY.
- **Speed**: **D-pad ◀▶** steps the jog speed through 5, 10, 25, 50, 75 and 100 %.

Cartesian jog moves one axis at a time: whichever stick direction is largest. A direction counts once the stick is past 0.35 of its travel. Choose **BASE** or **TOOL** as the frame, and **HOLD** or **STEP** as the mode. In **STEP** mode each push makes one bounded move of the linear step (100 mm by default) or angular step (15° by default); centre the stick before the next.

After a page change, a mode or axis change, a new direction, the Steam overlay taking focus, or a lost controller, the hold ends. You must bring the controls back to neutral before the next jog starts.

The touch controls do the same without the pad: **−** and **+** for each joint, an angle move per joint (**± 10°** and **GO**), **HOME JOINTS** and **ALL JOINTS TO 0°**. These are joint moves, checked against joint limits only.

Without **R2**, the right stick orbits the 3D view and **L2** with it zooms. **R3** resets the view.

## 4. Record waypoints

With the robot still:

| Press | To |
|---|---|
| **A** or **L4** | Record a waypoint at the measured pose |
| **X** or **L5** | Reteach the selected waypoint |
| **Y** or **R4** | Record a via pose for the selected waypoint, making it a circular move |

The pendant records under exactly the same rules as the desktop app: every axis homed and trusted, the robot still, fresh status, and the program's robot description matching the machine's. A refusal appears in the status line as `Record blocked: …`. See [Teach waypoints and moves](https://advancedmetalresearch.com/docs/guides/teach-waypoints#record-a-waypoint) for each refusal.

## 5. Edit the program

**PROGRAM** shows the node spreadsheet, a page at a time. **D-pad ▲▼** moves the selected row; **◀ PAGE** and **PAGE ▶** page.

| Button | Does |
|---|---|
| **● RECORD**, **RETEACH**, **VIA** | Record, as on the JOG page |
| **+ DWELL**, **+ IO**, **+ HOME** | Add an event or a Home |
| **EDIT** | Open the selected node's fields (also a double tap) |
| **ON / OFF** | Enable or disable the node |
| **▲ UP**, **▼ DOWN**, **DELETE** | Reorder or remove |
| **UNDO**, **REDO** | History |
| **PLAN SPEED** | The whole-plan speed, 1–100 % |
| **NEW**, **OPEN**, **SAVE AS** | Program files |

Editing is locked while the program runs. The node fields are the same as the desktop's; see [Edit a move](https://advancedmetalresearch.com/docs/guides/teach-waypoints#edit-a-move).

**OPEN** and **SAVE AS** read and write OLP project files (`offline-programming.project-export.v1` JSON) in `~/Rosie programs`. The current program also saves itself to `~/.local/share/Rosie/Rosie Pendant v5/current.olp.json` after every change. Press **Steam** + **X** for the on-screen keyboard when a dialog asks for a name.

## 6. Plan, preview and run

On **RUN**:

1. **PLAN PROGRAM** sends the program to the weld planner through the Deck's OLP server. The planner plans and verifies every move, as on the desktop. When it passes, the status says `Planned · <samples> samples, <seconds> s · Preview, or Load to robot`, and the pendant keeps the trajectory bytes in its own data directory.
2. **▶ PREVIEW PLAN** replays the kept trajectory in the 3D view, with a scrubber. **■ END PREVIEW** stops it.
3. Choose **DRY RUN** (process outputs off). Torch outputs are refused in this release, and there is no seam tracking.
4. **GO TO PLAN START** moves the robot to the plan's first pose with a joint move, then says `Move completed. Load to robot, then Play.` This move is not verified against collisions.
5. **LOAD TO ROBOT** loads the trajectory. Load fetches it by digest from the planner's store and checks its identity, the robot description and calibration, and Home.
6. **▶ PLAY** starts it. The executing node is highlighted in the program list. **■ STOP** ends it.

The pendant plans with the shipped fitted torch and the B-spline free-space solver. It holds no STEP file and has no seam search, so it can plan programs without a CAD part, such as taught moves. A program whose welds come from a part answers `This program's part (STEP) is not on the pendant; plan it in offline programming, then open it here`.

Only planned programs pass the verifier. Jog, the joint moves, Home and Go to plan start do not. See [What is verified before motion](https://advancedmetalresearch.com/docs/get-started/safety-model#what-is-verified).

## Telemetry

**TELEMETRY** plots the drives' data. Choose the quantity and the time **WINDOW**. **LIVE** follows the stream and **HOLD** freezes it. **CAPTURE 1 kHz** reads the last few seconds at the full 1 kHz rate.

## Related pages

- [Pendant controls](https://advancedmetalresearch.com/docs/reference/pendant-controls)
- [Build and install the pendant](https://advancedmetalresearch.com/docs/guides/install-the-pendant)
- [Teach waypoints and moves](https://advancedmetalresearch.com/docs/guides/teach-waypoints)
- [Use the virtual pendant](https://advancedmetalresearch.com/docs/guides/virtual-pendant)
- [Offline programming HTTP API](https://advancedmetalresearch.com/docs/apis/olp-http)

## Sources

Written from these files in the RosieOS repository (https://github.com/advanced-metal-research/RosieOS):

- `steamdeck/real/v5/src/main.cpp:11-24`
- `steamdeck/real/v5/src/window.cpp:55-59,61-207,215-281,378-523,525-593,661-677,694-792,794-873`
- `steamdeck/real/v5/src/input.hpp:1-50`
- `steamdeck/real/v5/src/controller.cpp:14-57`
- `steamdeck/real/v5/src/pages.hpp:26-150`
- `steamdeck/real/v5/src/jog_page.cpp:18-22,67-85,192-233,245-300`
- `steamdeck/real/v5/src/program_page.cpp:170-263`
- `steamdeck/real/v5/src/run_page.cpp:33-124,170-300`
- `steamdeck/real/v5/src/cell_page.cpp:63-126`
- `steamdeck/real/v5/src/telemetry_page.cpp:209-252`
- `steamdeck/real/v5/olp-core/run.ts:102-113`
- `steamdeck/real/v5/run.sh`
- `steamdeck/real/v5/start-olp.sh`
- `steamdeck/real/v5/controller.vdf`
