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>
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
- Detects L4T / JetPack / SoC (
scripts/detect_platform.sh). - Installs build and run dependencies (no GStreamer — the direct route encodes no video).
- Locates a working OrbbecSDK build, or clones and builds one. A node that already has a good build (the Nano) is left untouched.
- Builds
ithaca_rgbd_serveragainst it. - Generates
bridge/config.jsonfor the current user — this is where all the machine-specific paths live, sobridge.pyitself stays unmodified. - Installs the udev rules and the
usbfs-memoryservice, and adds the user to thevideogroup. - Generates and starts the
ithaca-bridgesystemd 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 (raworcompare). The preview server re-reads it once a second, so a camera can be turned on or off, and Compare switched, without restarting.