Files
Jetson/README.md
T
AngePierreandClaude Opus 5 c167c836e6 Portable Ithaca capture node: one install for every Jetson
Extract the install that was applied by hand to the Jetson Nano into a single
checkout that builds itself for whatever Jetson it lands on.

The two nodes on the rig share no JetPack — tegra210 caps at 4, tegra234 needs
5+ — so nothing binary is portable between them. The source and the procedure
are: install.sh detects the platform (L4T / JetPack / SoC), installs deps,
builds the OrbbecSDK and the preview server from source locally, and generates
a per-user config and systemd unit. The tested bridge.py ships verbatim; all
machine-specific paths live in the generated config, so it stays unmodified —
its one hardcoded path is made home-relative.

The retired GStreamer/RTSP target is dropped: the direct route encodes no video.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 15:57:15 +02:00

4.2 KiB

Ithaca capture node

The software a Jetson runs to join an Ithaca RGBD capture rig: a Python bridge that puts the node on the WebSocket mesh and answers Preview / Record, and a C++ preview server that streams each camera's colour (the sensor's own JPEG) and depth (its own 16-bit millimetres, LZ4-compressed) straight to the Unity viewer.

One checkout, one command, on any Jetson:

git clone <this repo> ~/ithaca-node
cd ~/ithaca-node
./install.sh

Why an install script and not a disk image

The rig currently spans two Jetsons with no JetPack in common:

Node SoC JetPack Ubuntu / CUDA
Jetson Nano (2019) tegra210 4.x only (EOL) 18.04 / 10.2
Jetson Orin Nano tegra234 5 or 6 22.04 / 12.x

tegra210 never got a newer L4T and the Orin refuses the old one, so no single OS image covers both, and no compiled binary is portable between them — CUDA, glibc and the C++ ABI all differ by generation.

What is portable is the source and the procedure. install.sh detects the platform and builds the C++ locally against a locally-built OrbbecSDK, so the same command produces a correct binary on each machine. Adding a future Orin NX or a Thor needs nothing new here — the script compiles against whatever toolchain it finds.

The bridge is pure Python and already runs identically everywhere; keep it that way by never giving it a dependency that has to be compiled.

Layout

install.sh                     one entry point, idempotent
bridge/
  bridge.py                    the node client — shipped verbatim, tested in place
  config.template.json         @PLACEHOLDERS@ filled per user by install.sh
server/
  ithaca_rgbd_server.cpp       the preview server
  CMakeLists.txt               links a prebuilt libOrbbecSDK, no GStreamer
systemd/
  ithaca-bridge.service.in     templated with the user and repo path
  usbfs-memory.service         raises usbfs_memory_mb for the camera bandwidth
udev/
  99-obsensor-libusb.rules     reference copy (the SDK's own installer wins if present)
scripts/
  detect_platform.sh           L4T / JetPack / SoC, as KEY=value
  install_deps.sh              apt + websockets
  build_sdk.sh                 reuse or build OrbbecSDK v2 for this platform
  build_server.sh              cmake + make the preview server

What install.sh does

  1. Detects L4T / JetPack / SoC (scripts/detect_platform.sh).
  2. Installs build and run dependencies (no GStreamer — the direct route encodes no video).
  3. Locates a working OrbbecSDK build, or clones and builds one. A node that already has a good build (the Nano) is left untouched.
  4. Builds ithaca_rgbd_server against it.
  5. Generates bridge/config.json for the current user — this is where all the machine-specific paths live, so bridge.py itself stays unmodified.
  6. Installs the udev rules and the usbfs-memory service, and adds the user to the video group.
  7. Generates and starts the ithaca-bridge systemd service.

Re-run it after a git pull: it rebuilds, regenerates the unit and config, and restarts the service. It keeps an existing config.json (delete it to regenerate) and an existing SDK build.

The SDK is the one thing to watch on a new JetPack

build_sdk.sh reuses an existing build when it finds one. On a machine with none it clones the official OrbbecSDK v2 and builds it — this is the step most likely to need attention on a JetPack it has not been tried on. If it fails, build the SDK by hand once and re-run with its location:

OB_SDK_ROOT=/path/to/OrbbecSDK_v2 ./install.sh

Override the source with OB_SDK_REPO / OB_SDK_REF to pin a tag known to build on your JetPack.

Operating the node

systemctl status ithaca-bridge      # is it up
journalctl -u ithaca-bridge -f      # live log

Runtime state the bridge writes beside itself (git-ignored):

  • config.json — this machine's config (generated).
  • cam_settings.json — per-camera settings, kept across restarts.
  • stream_map.txt — the live composition: line 1 the cameras to stream, line 2 the alignment (raw or compare). The preview server re-reads it once a second, so a camera can be turned on or off, and Compare switched, without restarting.