Skip to content

Add a copper-rs human pose reference - #39

Open
nicksinas wants to merge 3 commits into
mainfrom
nsinas/copper-rs
Open

nicksinas wants to merge 3 commits into
mainfrom
nsinas/copper-rs

Conversation

@nicksinas

@nicksinas nicksinas commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The catalog has no reference for copper-rs, a Rust runtime for robots. The copper-rs maintainer suggested examples/cu_human_pose as the reference. That example runs only on a desktop. It starts a local Rerun viewer, downloads the model at startup and writes a 1 GB log to a relative path.

Solution

copper-rs-pose: a copy of cu_human_pose (copper-rs release/1.2) with the changes a device needs. A USB camera feeds the task graph through GStreamer. YOLOv8n-pose runs on the CPU with Candle. The device serves the results on port 9876, and the developer watches them with rerun --connect on a laptop.

Users run only avocado install and avocado build. Everything else happens in the compile and install scripts.

Key changes

  • New copper-rs-pose/ with avocado.yaml, README.md, getting_started.md, compile and install scripts, a systemd unit and a udev rule
  • Targets: every 2026/next board except QEMU and jetson-orin-nx (11 targets). The Deploy section gives the provisioning profile per board family (sd, tegraflash, ufs).
  • Pins 2026/next (see Reviewer notes)
  • Changes to the upstream example:
    • Rerun gRPC server on the device with a 256 MB history limit, in place of a local viewer
    • Model weights downloaded at build time (pinned Hugging Face commit and sha256) and installed in the extension, in place of hf-hub at startup
    • Log in /var/lib/copper-rs-pose (StateDirectory=) with 256 MB slabs, and no raw camera frames in the log
    • Exit with an error code when the run fails, so systemd restarts the service when the camera is missing
    • The consolemon TUI starts only in a terminal (ssh -t). Under systemd only logmon runs.
    • /dev/copper-camera udev link, because the SoC camera blocks on these boards also make /dev/video* nodes

Reviewer notes

It pins 2026/next. 2026/edge has only jetson-agx-thor and the qemu targets. All the boards here are on next.

It builds with --ignore-rust-version. copper-rs declares Rust 1.95, and the 2026 SDK has 1.94.1. All crates build on 1.94.1. The copper-rs crates are pinned to =1.2.1, and Cargo.lock is committed and built with --locked, so a new copper-rs release cannot break the build.

Cargo output goes in $AVOCADO_BUILD_DIR. The first build compiles about 550 crates. On the project file share in avocado-vm this ran at about 5 crates per minute, because cargo waited on file I/O. In the SDK volume the full first build takes about 7 minutes, and a build with no changes takes about 25 seconds.

Tested:

  • scripts/build-check-references.sh copper-rs-pose passes on raspberrypi5.
  • avocado install and avocado build pass on jetson-orin-nano.
  • The other 9 boards are not built locally yet. CI builds them.
  • The binary links only gstreamer, glib and libc. The extension has every gstreamer library and plugin it needs, and the rootfs has glib.
  • Not yet verified end to end on a device with a camera and the Rerun viewer.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Image-layout handling, stale overlays, and model pooling have unresolved correctness issues.

4 open findings
What changed in this PR

Adds a copper-rs reference for USB-camera human pose estimation on Avocado devices, with CPU inference and remote Rerun visualization.

Changes:

  • Adds the Rust task graph and YOLOv8 pose pipeline.
  • Automates cross-compilation, model installation, and device service setup.
  • Documents building, deploying, viewing, and customization.
File Description
copper-rs-pose/​README.md Catalog metadata and reference overview.
copper-rs-pose/​overlay/​usr/​lib/​udev/​rules.d/​70-copper-camera.rules Stable USB-camera device link.
copper-rs-pose/​overlay/​usr/​lib/​systemd/​system/​copper-rs-pose.service Service startup, storage, and restart settings.
copper-rs-pose/​getting_started.md Build, deployment, and usage guide.
copper-rs-pose/​copper-install.sh Installs the binary and model weights.
copper-rs-pose/​copper-compile.sh Cross-compiles and verifies downloaded weights.
copper-rs-pose/​avocado.yaml Targets, packages, and build integration.
copper-rs-pose/​app/​src/​yolo/​preprocess.rs Converts images into inference tensors.
copper-rs-pose/​app/​src/​yolo/​postprocess.rs Decodes and filters pose predictions.
copper-rs-pose/​app/​src/​yolo/​model.rs Implements YOLOv8 using Candle.
copper-rs-pose/​app/​src/​yolo/​mod.rs Exports inference modules.
copper-rs-pose/​app/​src/​tasks/​yolo_pose.rs Runs pose inference as a Copper task.
copper-rs-pose/​app/​src/​tasks/​rerun_viz.rs Serves images and pose overlays.
copper-rs-pose/​app/​src/​tasks/​mod.rs Exports task implementations.
copper-rs-pose/​app/​src/​tasks/​gst_to_image.rs Adapts GStreamer buffers to Copper images.
copper-rs-pose/​app/​src/​payloads.rs Defines pose and keypoint payloads.
copper-rs-pose/​app/​src/​main.rs Starts the runtime and persistent logging.
copper-rs-pose/​app/​src/​image.rs Shared pixel-format conversions.
copper-rs-pose/​app/​copperconfig.ron Configures the camera and task graph.
copper-rs-pose/​app/​Cargo.toml Declares dependencies and build features.
copper-rs-pose/​app/​build.rs Enables Copper build-time setup.
copper-rs-pose/​.gitignore Excludes generated build files.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread copper-rs-pose/app/src/tasks/gst_to_image.rs
Comment thread copper-rs-pose/app/src/tasks/rerun_viz.rs Outdated
Comment thread copper-rs-pose/app/src/yolo/model.rs Outdated
Comment thread copper-rs-pose/getting_started.md Outdated
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Avocado References — Build Check

Reference Target install build Result
copper-rs-pose raspberrypi5 ✅ ✅ PASS

Totals: 1 ✅ passed · 0 ❌ failed

Per-reference logs: workflow run

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Camera-to-viewer operation remains unverified on hardware, and CI covers only the default board rather than all advertised targets.

0 open findings

4 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity NV12 conversion ignores negotiated color range and matrix

copper-rs-pose/​app/​copperconfig.ron:26

When the camera supplies limited-range video, this NV12 path loses the negotiated color range and matrix: nv12_to_rgb assumes full-range BT.601, and both preprocessing and visualization use it. For example, neutral black (Y=16, U=V=128) becomes RGB (16,16,16) instead of (0,0,0), and white stops at 235. Negotiate RGB and configure the adapter as RGB3 so GStreamer's videoconvert handles the conversion before the image reaches the model and viewer.

🧠 Review effort: Balanced

@nicksinas
nicksinas requested a review from jetm October 16, 2026 19:06

@jetm jetm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicksinas, I read every file except Cargo.lock, which I only skimmed: it is consistent with Cargo.toml and I found no yanked crates by name. One inline blocker on the unbuilt boards. The code reads sound: postprocess.rs checks the prediction size before indexing and returns empty on no detections, nothing unwraps external input, the one unsafe has a SAFETY note, and the model download is pinned to a commit with a sha256 check. I did not build or run anything.

Non-blocking: preprocess.rs:53 says letterbox but the code stretches 640x360 to 640x352 (the rescale in postprocess.rs:45-46 matches the stretch, so only the comment is wrong). getting_started.md:180 advises multiples of 16 while the shipped default is 640x360, and getting_started.md:54 says about 700 crates while the PR body says about 550 and the lock has 718. rb3gen2 is not in spec_readme.md's valid-target table. The weights come from the third-party lmz/candle-yolo-v8 conversion and ship in the extension image, with the AGPL licence disclosed. NV12 to RGB runs twice per frame (rerun_viz.rs:87 and preprocess.rs:31), a NaN confidence passes the threshold check into NMS (postprocess.rs:60), and the Rerun server at rerun_viz.rs:45 is unauthenticated on 0.0.0.0:9876, which the Security section documents.


default_target: "raspberrypi5"

supported_targets:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 of 11 supported_targets are built nowhere

The description says the other 9 boards "are not built locally yet. CI builds them." build-check.yml resolves one target per reference (default_target, else the first concrete supported_targets entry), so it builds raspberrypi5 here and nothing else, and compat-check.yml sweeps only the dev reference and does not run on PRs. By my read of the PR body, that leaves nine of the eleven listed boards unbuilt, and nothing has checked that kernel-module-uvcvideo, the GStreamer plugin packages or the Rust cross package exist in each board's 2026/next feed. Someone running avocado init --reference copper-rs-pose --target rb3gen2 could hit an install failure on a board the README lists.

Either build the remaining targets once (TARGET=<board> scripts/build-check-references.sh copper-rs-pose) and update the description, or trim supported_targets and the README to the boards that were built. I did not run the workflow or a build.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update on this after the targets: all build-check run on 9fb9741 (run 39053962445). Seven of the eleven boards build: jetson-orin-nano, jetson-agx-orin, jetson-agx-thor, raspberrypi4, raspberrypi5, rb3gen2 and rubikpi3.

The four NXP boards fail: imx8mp-evk, imx91-frdm, imx93-evk and imx93-frdm. In the imx8mp-evk job log the runtime build stops with Image file 'avocado-image-rootfs-imx8mp-evk.verity' for artifact 'rootfs_hash' not found in any input directory followed by Failed to build runtime 'dev'. I read that log for imx8mp-evk only. The other three jobs also fail, and I have not read their logs. The cause looks like the 2026/next NXP feeds, not this code.

That settles the nine-unbuilt question for seven boards, but supported_targets, the README front matter, the --target imx8mp-evk example in getting_started.md and the SD provisioning section still advertise all four failing boards. @nicksinas, I'd drop those four from the reference until their feeds build, and switch the example to a board that passes, such as jetson-orin-nano.

A Copper (copper-rs) task graph in Rust: USB camera through GStreamer,
YOLOv8n-pose on the CPU with Candle, results served to a Rerun viewer
on the laptop (rerun --connect, port 9876).

Based on copper-rs examples/cu_human_pose (release/1.2), with the
changes a device needs:
- Rerun gRPC server on the device (256 MB history) in place of a
  local viewer
- Model weights downloaded at build time (pinned commit + sha256)
  and installed in the extension, in place of hf-hub at runtime
- Copper log in /var/lib/copper-rs-pose (StateDirectory), 256 MB
  slabs, no raw frames in the log
- Exit non-zero on a run error so systemd restarts the service
- consolemon TUI over `ssh -t`; logmon only under systemd
- udev link /dev/copper-camera for the USB camera

Builds with only `avocado install` and `avocado build` on 2026/next.
Copper crates are pinned to =1.2.1 and built with
--ignore-rust-version (SDK rust 1.94.1, Copper declares 1.95). Cargo
output and cache go in $AVOCADO_BUILD_DIR, because the project file
share is too slow for this build.

Tested: build-check passes on raspberrypi5; jetson-orin-nano builds.
imx8mp-evk compiles, but the runtime image fails in stone validate
(feed bootfiles have no rootfs .verity placeholder, not this
reference). Not yet tested on hardware.

The YOLOv8 weights are AGPL-3.0 (Ultralytics). They are downloaded
by the build and are not in this repository.
Copper Robotics is the company and copper-rs is the product. Upstream
source text is not changed.
- supported_targets and README targets: every 2026/next board except
  QEMU and jetson-orin-nx (11 targets). The Deploy section gives the
  provisioning profile per board family (sd, tegraflash, ufs).
- rerun_viz: log keypoints, skeleton and boxes every frame. An empty
  set clears the overlay from the frame before, so stale overlays no
  longer stay when a person has no confident keypoints.
- yolo SPPF: pad the max-pool with -inf, as PyTorch MaxPool2d does.
  Zero padding changed border values, because SiLU can be negative.
- getting_started: use a width and height that are multiples of 16,
  because the app reads frames as rows with no padding.

@jetm jetm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on one point, which I've put on the existing thread at avocado.yaml:5 rather than opening a second one: the four NXP boards (imx8mp-evk, imx91-frdm, imx93-evk, imx93-frdm) fail to build on this head, and the reference still lists them in supported_targets, the README and the getting-started guide.

The branch is a rebase onto main with no change under copper-rs-pose/ since my last review, so the earlier thread is still open. The targets: all run on 9fb9741 now answers it for seven of the eleven boards. I found nothing else blocking in the rest of the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants