Advanced Metal Research
GitHub Contact AMR

Build and install the pendant

On this page
  1. Before you start
  2. Qt5Qml without root
  3. Build
  4. Test
  5. Run it on the workstation
  6. Package
  7. Deploy
  8. Add it to Steam
  9. Site files
  10. planner.env
  11. Related pages

The v5 pendant ships as one directory, RosiePendantV5, that you build on a Linux workstation and copy to a Steam Deck. It holds the native app, OLP's program logic bundled for Qt's JavaScript engine, the OLP server it runs headless on the Deck, and the source trees that server reads. To use it once it is installed, see Program from the Steam Deck pendant.

Danger

Not qualified for real motion. The v5 pendant has not been qualified on physical stick, trigger and rear-button input, real robot motion, network faults, or a full plan, Load and Play on the Deck, and no CI workflow builds it. Its hold-to-enable trigger is a software deadman, not a safety-rated enabling device. Keep the cell's hardware E-stop within reach whenever the drives are powered, and use the pendant in simulation until the cell owner has qualified it. See the safety model.

Before you start#

On the build workstation, Ubuntu 22.04 or WSL2:

sudo apt install g++ make pkg-config qtbase5-dev libassimp-dev curl

You also need:

  • Qt5Qml. Install qtdeclarative5-dev, or, without root, extract it to a sysroot (below).
  • Node 22 and the OLP UI's packages, for esbuild and OLP's TypeScript sources.
  • Go 1.26.2, to build the OLP server for the Deck.
  • The C++17 toolchain for motion-server/v1, which the build uses for the pendant's Cartesian solver.
  • ssh access to the Deck, for deploying.

See Install the toolchain.

Qt5Qml without root#

The Makefile looks for a sysroot at ~/.rosie/qt5qml-sysroot, or wherever QML_SYSROOT points:

mkdir -p ~/.rosie/qt5qml-sysroot/debs && cd ~/.rosie/qt5qml-sysroot/debs
apt-get download qtdeclarative5-dev libqt5qml5 libqt5qmlmodels5 libqt5quick5
for d in *.deb; do dpkg-deb -x "$d" ..; done

Build#

From the repository root:

(cd offline-programming/v1/ui && npm ci)
make -C steamdeck/real/v5 -j4 all

This builds three things in steamdeck/real/v5/build/:

FileWhat it is
rosie-pendant-v5The native Qt 5.15 app
olp-core.jsOLP's program and machine logic, from offline-programming/v1/ui/src and steamdeck/real/v5/olp-core, bundled by esbuild as ES2016 for Qt's engine
robot-v4-cartesiandThe Cartesian solver the OLP server uses, built from motion-server/v1

The bundle depends on every non-test .ts file under OLP's ui/src, so a change to OLP rebuilds it. That is how the pendant and the desktop stay one implementation.

Test#

make -C steamdeck/real/v5 check
CheckWhat it covers
session.test.ts, machine.test.tsThe pendant's session and machine logic, under Node
core-checkThe built olp-core.js inside Qt's JavaScript engine, as the app runs it
capture-checkThe app's C++ capture TCP pose against OLP's own poses, for both robot descriptions
view-checkOffscreen: the input interlock, display kinematics, description identity and both robots' mesh sets

Run it on the workstation#

Start an OLP server on port 8794 (the quickstart does), then:

cd steamdeck/real/v5
LD_LIBRARY_PATH=~/.rosie/qt5qml-sysroot/usr/lib/x86_64-linux-gnu \
  build/rosie-pendant-v5 --windowed --robots ../../../robot_description/robots

Leave out LD_LIBRARY_PATH if Qt5Qml is installed system-wide.

OptionDefaultDescription
--olp <origin>http://127.0.0.1:8794The OLP server the pendant fronts
--bundle <path><app dir>/olp-core.jsThe OLP logic bundle
--robots <dir><app dir>/../olp/robot_description/robotsRobot descriptions, for the 3D view
--programs <dir>~/Rosie programsThe folder for OPEN and SAVE AS
--windowedfull screenRun in a desktop window
--snapshot <prefix>Render every page at 1280×800 to <prefix>-<n>.png after 3 s, then exit

Package#

steamdeck/real/v5/package.sh                       # the app and the OLP tree
steamdeck/real/v5/package.sh --with-tesseract-env  # also the Tesseract pixi environment (about 1 GB)

package.sh runs make all, builds the OLP server for Linux x86-64, and stages steamdeck/real/v5/build/package/RosiePendantV5:

PathContents
run.sh, start-olp.sh, controller.vdfThe launcher, the OLP server's start script, and the Steam Input layout
bin/rosie-pendant-v5, olp-core.js, robot-v4-cartesiand
lib/libassimp.so.5, libdraco.so.4 and libminizip.so.1 from the build host, with their Debian copyright files. SteamOS ships Qt 5.15 but not Assimp.
olp/The files of offline-programming/v1, motion-server/v1, robot_description, tesseract/v1, weld_planner/v1, cadquery/v1, and rt-core/config/{cells,machines,drives}, which the server needs to resolve remote cells. Also the server binary and a stub ui/dist/index.html, because serve refuses to start without one.
SHA256SUMSA hash of every file except the Tesseract environment

Pass --with-tesseract-env on the first deploy, and again whenever tesseract/v1/pixi.lock changes. The OLP server needs that environment.

package.sh adds the ~/.rosie toolchain directories to the front of PATH. If your Go and Node live elsewhere, have them on PATH already.

The package never contains site files: the cell catalogue, the rt-core binding, planner.env or credentials.

Deploy#

Exit the pendant on the Deck first. Then, with your Deck's address:

steamdeck/real/v5/deploy.sh deck@rosie-deck.local

The optional second argument is the directory on the Deck. It defaults to devkit-game/RosiePendantV5 in the deck user's home. deploy.sh:

  1. refuses while the pendant or its rosie-v5-olp unit is running, so nothing that holds a machine grant is replaced underneath it
  2. removes the files of the retired browser kiosk from the app directory
  3. copies the package over ssh
  4. checks every staged hash on the Deck with sha256sum -c SHA256SUMS, and prints deploy: all staged hashes match

Site files on the Deck are left alone.

Add it to Steam#

  1. Add run.sh as a non-Steam game (or devkit) shortcut.
  2. Set controller.vdf as that shortcut's Steam Input layout. It maps the rear buttons L4, L5, R4 and R5 to F1, F2, F3 and F4, makes the right trackpad an absolute mouse, and makes the left trackpad scroll. See Pendant controls.

run.sh:

  • starts start-olp.sh as the systemd user unit rosie-v5-olp, unless it is already running
  • waits up to 30 s for http://127.0.0.1:8794/api/offline-programming/v1/health
  • starts the app full screen, with Steam's LD_PRELOAD and LD_LIBRARY_PATH removed, LD_LIBRARY_PATH set to the package's lib/, QT_QPA_PLATFORM=xcb and a scale factor of 1
  • stops the unit when the app exits. The server's shutdown stops any machine it armed before it releases control.

Arguments to run.sh go to the app. The server's log is journalctl --user -u rosie-v5-olp.

Site files#

Put these beside run.sh on each Deck. They are never committed and never packaged:

FileRead byContents
olp-cells.jsonOLP server, as OFFLINE_PROGRAMMING_CELLSThe cell catalogue: which cells the CELL page lists. See Connect to a cell and run a program.
olp-rt-core.jsonOLP server, as OFFLINE_PROGRAMMING_RT_CORE_CONFIGThe server-only rt-core backend configuration, for a local simulation entry
planner.envstart-olp.sh, if presentWhere the weld planner is, and how to run the seam worker
client credentials (*.pem)OLP server, through the catalogueThe mutual-TLS credentials for remote cells, named by the catalogue. See Remote access (mTLS).

start-olp.sh also sets OFFLINE_PROGRAMMING_EXECUTION_BACKEND=rt_core, OFFLINE_PROGRAMMING_JOG_BACKEND=rt_core and the solver path, and starts offline-programming-linux serve --listen 127.0.0.1:8794 --enable-local-simulator. It leaves ROSIE_RT_* unset on purpose: OLP's disconnected local jog would otherwise take the simulation adapter's only controller slot and lock the pendant out.

planner.env#

Planning and Load both need a weld planner on a workstation the Deck can reach. Every plan also runs the seam worker once on the Deck, to pack the .weldplan. The package ships the seam worker's sources but no pixi environment. Packing uses only the Python standard library, so the Deck's system Python can run it:

planner.envBash
OFFLINE_PROGRAMMING_WELD_PLANNER_MOTION_ORIGIN=http://planner.local:8796
SEAM_WORKER_PYTHON=/usr/bin/python3
# Spare workers preload OpenCASCADE, which the system Python does not have.
SEAM_WORKER_SPARES=0

Without an origin, the RUN page shows the server's refusal and nothing is planned or loaded. Without SEAM_WORKER_PYTHON and without pixi on the Deck, planning fails because the seam worker cannot start. The alternative is pixi on the Deck and pixi install -e default in olp/weld_planner/v1.

Warning

The weld planner must listen on the network for the Deck to reach it, and it has no authentication. Firewall port 8796 so that only the Deck and your own machine can reach it. See Bind it safely.

A complete plan, Load and Play from the Deck against the weld planner has not been qualified.