038d59f972
Centralize salmanoff snapcraft, dangerous-model image scripts, and QEMU workflow so UC26 can be reproduced from the SMO repo without ubuntu-core-practice. Co-authored-by: Cursor <cursoragent@cursor.com>
277 lines
12 KiB
Markdown
277 lines
12 KiB
Markdown
# Salmanoff on Ubuntu Core — Plan (derived from Yocto work)
|
||
|
||
## Purpose of this document
|
||
|
||
This plan is **not** a translation of an original Yocto design doc. It reflects **what we actually built and validated** in the Yocto path, reframed as goals for Ubuntu Core. Use it as primary context when scaffolding snaps, gadget/model, and dev VM workflow.
|
||
|
||
When done, snap definitions and support files land in the SMO repo under:
|
||
|
||
```
|
||
smo/distro/ubuntuCore/
|
||
```
|
||
|
||
(parallel to the existing `smo/distro/yocto/meta-salmanoff/`).
|
||
|
||
---
|
||
|
||
## What we proved in Yocto (facts, not aspirations)
|
||
|
||
We shipped a **minimal headless image** that runs the Salmanoff (SMO) cognitive robotics runtime on **QEMU x86-64**, bridged onto a lab LAN, talking to a **Livox LiDAR** on a fixed IP.
|
||
|
||
### Lab network (canonical — carry forward unchanged)
|
||
|
||
| Host | IP | Role |
|
||
|---|---|---|
|
||
| Laptop / gateway | `10.42.0.1` | Gateway + DNS |
|
||
| RPi5 (production target) | `10.42.0.2` | Future production node |
|
||
| **Dev guest (QEMU / UC VM)** | **`10.42.0.16`** | SMO dev runtime |
|
||
| Livox Avia | `10.42.0.139` | LiDAR sensor |
|
||
|
||
### Runtime configuration we validated
|
||
|
||
- **Body file**: `yocto-qemu-x86-headless.dapss` — Livox-only, headless (no win0/camera), `smo-ip=10.42.0.16`, includes `avia0.dapss`.
|
||
- **SMO build profile** (CMake):
|
||
- `RelWithDebInfo`
|
||
- `ENABLE_LIB_lcameraDev=ON`, `ENABLE_STIMBUFFAPI_lcameraBuff=ON` (libcamera + OpenCL YUV path compiled in; no camera passthrough needed in QEMU)
|
||
- `ENABLE_LIB_xcbXorg=OFF`, `COMPILE_PCL_TOOLS=OFF`, `ENABLE_TESTS=OFF`, `ENABLE_LCAMERADEV_TOOLS=OFF`
|
||
- Git submodules required (`libspinscale`, etc.)
|
||
- **Runtime command shape** (approximate):
|
||
```bash
|
||
salmanoff -d /usr/share/salmanoff/devices/bodies/body_yocto_qemu_x86_headless.daps -p /usr/lib -v
|
||
```
|
||
(exact installed `.daps` filename follows DAPSS build output naming)
|
||
|
||
### Platform services / packages we pulled into the image
|
||
|
||
| Need | What we used in Yocto |
|
||
|---|---|
|
||
| SMO runtime + libs | `salmanoff` recipe (`libspinscale`, `liblcameraDev`, `liblcameraBuff`, `liblivoxGen1`, …) |
|
||
| Boost | Pinned **1.86** (shared `boost-system`; must stay **< 1.89**) |
|
||
| liburing | Runtime dep |
|
||
| libcamera + v4l-utils | Present on image; camera optional at runtime |
|
||
| OpenCL | Mesa Rusticl via `opencl` distro feature; **needs `RUSTICL_ENABLE=llvmpipe`** or platform shows 0 devices |
|
||
| OpenCL verify | `clinfo` (also discovered **256M RAM OOMs** OpenCL probe — use **≥ 2G** for dev VM) |
|
||
| Network | Static `eth0`: `10.42.0.16/24`, gw `10.42.0.1` |
|
||
| Dev access | SSH (openssh on Yocto image) |
|
||
| Kernel probe | `rseqsliceprobe` + kernel config append for rseq slice extension |
|
||
| QEMU dev | Host bridge `br-smo`, `runqemu` with `bridge=br-smo`, `nographic`, `-m 2048` |
|
||
|
||
### Repo / packaging decisions already made in SMO
|
||
|
||
- Yocto layer vendored at `smo/distro/yocto/meta-salmanoff/` (committed on `clast`).
|
||
- SMO source changes on `clast`: headless body, flex/bison repo-relative `#line` paths, etc.
|
||
- Fetch uses private Gitea (`hayodea/salmanoff`, branch `clast`, submodules via `libspinscale` on separate SSH host alias).
|
||
|
||
---
|
||
|
||
## Conceptual goals (portable to Ubuntu Core)
|
||
|
||
These are the **intent** items — independent of BitBake:
|
||
|
||
1. **Repeatable dev environment** — headless guest on `10.42.0.16`, reachable from laptop, Livox at `10.42.0.139`.
|
||
2. **SMO as first-class payload** — not “install deps manually”; runtime + `.daps` bodies + plugin `.so`s packaged and startable.
|
||
3. **Same CMake feature profile** as Yocto (lcamera + OpenCL enabled; xcb/PCL tools off).
|
||
4. **OpenCL that actually works headless** — Rusticl/llvmpipe with env var set before SMO starts.
|
||
5. **libcamera stack present** — libraries available even when no camera device is passed through (QEMU/UC dev).
|
||
6. **Boost version constraint honored** — do not silently pick Boost ≥ 1.89.
|
||
7. **Production path to RPi5** — same snap(s), different body/IP (`10.42.0.2`), gadget/kernel for Pi hardware.
|
||
8. **Distro metadata lives in SMO** — `distro/ubuntuCore/` committed back into SMO when stable (mirrors Yocto layout).
|
||
|
||
---
|
||
|
||
## Yocto → Ubuntu Core mapping
|
||
|
||
| Yocto (what we did) | Ubuntu Core (target) |
|
||
|---|---|
|
||
| `meta-salmanoff/` layer | `distro/ubuntuCore/` — snaps, gadget, model, helper scripts |
|
||
| `salmanoff-image.bb` | **Model assertion** + `core` + gadget snap + app snaps on seeded image |
|
||
| `salmanoff.bb` recipe | **`salmanoff` snap** (`snapcraft.yaml`: cmake build, submodules, organize libs + daps) |
|
||
| `IMAGE_INSTALL` | Snap `stage-packages` / parts / content snaps (`mesa`, libcamera deps) |
|
||
| `salmanoff-rusticl-env` recipe | Snap `environment:` block or wrapper script: `RUSTICL_ENABLE=llvmpipe` |
|
||
| `init-ifupdown` static IP | **Netplan** via gadget default config, `network-setup` snap, or `system-connections` on UC |
|
||
| `runqemu-salmanoff-bridge` | **Dev VM script**: UC image in QEMU/LXD/multipass on `br-smo`, static `10.42.0.16`, 2G RAM |
|
||
| `DISTRO_FEATURES += opencl` | Ensure Mesa/OpenCL ICD available to snap (layout + plugs or bundled libs) |
|
||
| `DEPENDS` / `RDEPENDS` | Snapcraft `build-packages`, `stage-packages`, `slots`/`plugs`, `layout:` for `/usr/lib` ICD paths |
|
||
| `gitsm://` + `SRCREV` | Snapcraft `source` + `source-submodules` or `override-pull` git submodule update |
|
||
| `yocto-qemu-x86-headless.dapss` | Installed by salmanoff snap; UC-specific body can be `ubuntu-core-x86-headless.dapss` later |
|
||
| `rseqsliceprobe` | Validate UC kernel/base; custom kernel snap only if probe fails on stock UC kernel |
|
||
| SSH on image | UC: serial console, `ssh-keys` in model, or dedicated snap — **don’t assume openssh like Yocto** |
|
||
| Boost 1.86 pin | Pin in snapcraft (`stage-packages` version) or build Boost part from source |
|
||
| `RelWithDebInfo` + debug maps | Snapcraft `override-build` cmake flags; consider `debug` snap or stripped separate artifact |
|
||
|
||
---
|
||
|
||
## Proposed Ubuntu Core architecture
|
||
|
||
```
|
||
Host (10.42.0.1)
|
||
└── bridge br-smo (10.42.0.0/24)
|
||
└── UC dev VM / RPi5 (10.42.0.16 or .2)
|
||
├── snap: core (or core24)
|
||
├── snap: gadget-<platform> (boot, partitions, default netplan)
|
||
├── snap: salmanoff (daemon — main payload)
|
||
└── optional: mesa-support / libcamera-support content snaps if not bundled
|
||
```
|
||
|
||
### `salmanoff` snap (primary deliverable)
|
||
|
||
**Type**: likely `daemon` (simple) or `daemon` (notify) once startup semantics are known.
|
||
|
||
**Build** (mirror Yocto recipe intent):
|
||
|
||
- Source: SMO repo `clast` (submodules!)
|
||
- CMake options: same as Yocto `EXTRA_OECMAKE` block
|
||
- Install: `salmanoff` binary, `lib*.so*`, `/usr/share/salmanoff/devices/**`
|
||
- Apps: main daemon + optional `salmanoff.probe` for debugging
|
||
|
||
**Runtime environment**:
|
||
|
||
```yaml
|
||
environment:
|
||
RUSTICL_ENABLE: llvmpipe
|
||
```
|
||
|
||
**Interfaces to evaluate early** (exact set TBD by confinement testing):
|
||
|
||
- `network` / `network-bind` — Livox UDP/TCP to `10.42.0.139`
|
||
- `hardware-observe` — may be needed for camera discovery on Pi
|
||
- `camera` — for libcamera on production Pi
|
||
- `opengl` — if Mesa GL stack needed beyond OpenCL ICD
|
||
- `raw-usb` / `serial-port` — only if Livox path requires it on some platforms
|
||
- `home` — usually **avoid**; use `$SNAP_DATA` for state
|
||
|
||
**Layouts** (likely needed):
|
||
|
||
- OpenCL ICD loader expects `/etc/OpenCL/vendors` or known `LD_LIBRARY_PATH`
|
||
- May need `layout:` bind mounts for Mesa `libRusticlOpenCL.so` / gallium stack
|
||
|
||
### Platform snaps
|
||
|
||
| Platform | Gadget | Notes |
|
||
|---|---|---|
|
||
| **QEMU x86 dev** | `pc` or custom gadget | Static IP `10.42.0.16`, 2G RAM, bridged NIC |
|
||
| **RPi5 production** | `pi` gadget (22+ arm64) | Static IP `10.42.0.2`, libcamera, Livox |
|
||
|
||
### Bodies / config
|
||
|
||
- **Dev (UC VM)**: start from Yocto body or add `ubuntu-core-x86-headless.dapss` with same Livox-only intent and `smo-ip=10.42.0.16`.
|
||
- **Production (RPi5)**: reuse/adapt existing `rpi5-persys-headless.dapss` pattern with `smo-ip=10.42.0.2`.
|
||
|
||
Body files stay in SMO `devices/bodies/`; snap selects default via config or snap config hook.
|
||
|
||
---
|
||
|
||
## Phased plan (recommended order)
|
||
|
||
### Phase 0 — Repo scaffold
|
||
|
||
- [ ] New repo (or `distro/ubuntuCore/` in SMO) with `snapcraft.yaml` skeleton
|
||
- [ ] Document lab IP table and bridge prerequisites (port `runqemu-salmanoff-bridge` concepts)
|
||
- [ ] Link to SMO `clast` branch + submodule SSH host requirements
|
||
|
||
### Phase 1 — Build snap on host (no hardware)
|
||
|
||
- [ ] `snapcraft` / `craft` builds SMO with same CMake profile as Yocto
|
||
- [ ] Confirm submodule pull (`libspinscale`) in clean CI/local environment
|
||
- [ ] Resolve Boost < 1.89 (stage-package pin or source part)
|
||
- [ ] Package `.daps` + shared libs; verify `salmanoff -v` / dry-run in snap run environment
|
||
|
||
### Phase 2 — OpenCL + libcamera in confinement
|
||
|
||
- [ ] Replicate Yocto OpenCL stack inside snap (bundled vs system Mesa)
|
||
- [ ] Confirm `RUSTICL_ENABLE=llvmpipe` → `clinfo` shows ≥1 device **inside snap**
|
||
- [ ] Confirm `liblcameraDev` / `liblcameraBuff` load; no crash without camera device
|
||
- [ ] Document RAM requirement (≥ 2G for dev VM)
|
||
|
||
### Phase 3 — UC dev VM on lab LAN
|
||
|
||
- [ ] Boot Ubuntu Core x86 VM bridged to `br-smo`
|
||
- [ ] Static IP **10.42.0.16** (netplan/gadget)
|
||
- [ ] Install seeded `salmanoff` snap (devmode first, then strict)
|
||
- [ ] Ping gateway; reach Livox at `10.42.0.139`
|
||
- [ ] Run headless body; validate Livox traffic / SMO logs
|
||
|
||
### Phase 4 — Production path (RPi5)
|
||
|
||
- [ ] Model assertion for Pi5 + arm64 core
|
||
- [ ] Gadget with `10.42.0.2` netplan
|
||
- [ ] libcamera plug + Pi body file
|
||
- [ ] OTA refresh via snap channels
|
||
|
||
### Phase 5 — Commit back to SMO
|
||
|
||
- [ ] Move stable `distro/ubuntuCore/` into SMO repo
|
||
- [ ] Commit on `clast` (or dedicated branch); do **not** block on unfinished WIP snaps
|
||
|
||
---
|
||
|
||
## Known constraints & pitfalls (from Yocto — expect repeats)
|
||
|
||
1. **OpenCL**: platform visible but **0 devices** until `RUSTICL_ENABLE=llvmpipe`.
|
||
2. **Memory**: 256M insufficient for Rusticl/`clinfo`; use **2G** for dev VM.
|
||
3. **Boost**: must stay **< 1.89** (shared `boost-system` linkage).
|
||
4. **Submodules**: `libspinscale` is mandatory; fetch must be recursive; separate SSH host alias on Gitea.
|
||
5. **lcamera without hardware**: compile and ship libs; no QEMU camera passthrough required for basic bring-up.
|
||
6. **PCL / xcb**: keep off unless explicitly needed (MPI/cmake pain in Yocto).
|
||
7. **Private git**: snapcraft build needs SSH keys / credentials for Gitea fetch (or vendored source tarball part).
|
||
8. **Strict confinement**: biggest unknown vs Yocto — plan devmode → strict iteration; interfaces will take multiple passes.
|
||
9. **rseq kernel feature**: validate on UC base; custom kernel snap is expensive — only if probe fails.
|
||
|
||
---
|
||
|
||
## Success criteria (match Yocto milestone)
|
||
|
||
Minimum “we’re at parity” for UC dev:
|
||
|
||
- [ ] UC VM at `10.42.0.16` on `10.42.0.0/24` via host bridge
|
||
- [ ] `salmanoff` snap installed and daemon running (or manual `snap run` equivalent)
|
||
- [ ] Headless Livox body loaded; SMO stable with Livox on `10.42.0.139`
|
||
- [ ] OpenCL initialized (llvmpipe); lcamera libs present
|
||
- [ ] Snap definitions committed under `smo/distro/ubuntuCore/`
|
||
|
||
Stretch (production):
|
||
|
||
- [ ] Same snap on RPi5 at `10.42.0.2` with Pi-appropriate body
|
||
|
||
---
|
||
|
||
## Explicit non-goals (for now)
|
||
|
||
- Re-implement Yocto layer / BitBake in UC repo
|
||
- Camera passthrough in QEMU/UC x86 dev
|
||
- PCL tools / xcb window stack
|
||
- lcameraDev probe tools (need test support libs — off in Yocto too)
|
||
- Full OTA/signing production pipeline (Phase 4+)
|
||
|
||
---
|
||
|
||
## Reference: Yocto artifacts in SMO repo
|
||
|
||
When unsure, read the working Yocto implementation:
|
||
|
||
```
|
||
smo/distro/yocto/meta-salmanoff/
|
||
conf/layer.conf
|
||
conf/salmanoff-local.inc # opencl distro feature
|
||
recipes-salmanoff/salmanoff/salmanoff.bb
|
||
recipes-core/images/salmanoff-image.bb
|
||
recipes-core/init-ifupdown/... # 10.42.0.16 static IP
|
||
recipes-support/salmanoff-rusticl-env/
|
||
scripts/runqemu-salmanoff-bridge
|
||
|
||
smo/devices/bodies/yocto-qemu-x86-headless.dapss
|
||
```
|
||
|
||
SMO branch: **`clast`** on `hayodea/salmanoff` (Gitea).
|
||
|
||
---
|
||
|
||
## Instructions for the LLM in the Ubuntu Core repo
|
||
|
||
1. **Treat Yocto work as validated reference**, not something to re-derive from scratch.
|
||
2. **Preserve lab IP plan and CMake profile** unless user says otherwise.
|
||
3. **Start with snapcraft build on host**, then UC VM, then strict confinement — same order we used (build → package QA → runtime).
|
||
4. **Plan for `distro/ubuntuCore/` in SMO** as the final home of snaps/gadget/model/scripts.
|
||
5. **Ask before** committing snaps into SMO; user will commit when done.
|
||
6. **Do not** assume UC has openssh or classic Ubuntu package management — everything is snaps + interfaces.
|