v1.1.0
Browse files- CM5 variant (`Dockerfile.cm5`): build the image for a Compute Module 5 swapped into the Wireless carrier (uart2-pi5 motor bus, external antenna, CSI camera kept on libcamera, x264 software encoder for the WebRTC stream since the CM5 has no hardware encoder).
Source: 7020aa91cdfb58abd26aac56e2d0cf57055f7ee8
Auto-sync: ReachyPi
- CHANGELOG.md +14 -0
- Dockerfile.cm5 +38 -0
- README.md +15 -0
- VERSION +1 -0
- docker/stage-cm5-fixes.sh +63 -0
- image_2026-07-19-reachyminios-cm5.zip +3 -0
CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Changelog
|
| 2 |
+
|
| 3 |
+
Condensed, one entry per release. The top entry must match `VERSION`: `publish.sh`
|
| 4 |
+
refuses to publish otherwise, and ships these bullets as the commit message.
|
| 5 |
+
|
| 6 |
+
## v1.1.0 (2026-07-19)
|
| 7 |
+
|
| 8 |
+
- CM5 variant (`Dockerfile.cm5`): build the image for a Compute Module 5 swapped into the Wireless carrier (uart2-pi5 motor bus, external antenna, CSI camera kept on libcamera, x264 software encoder for the WebRTC stream since the CM5 has no hardware encoder).
|
| 9 |
+
|
| 10 |
+
## v1.0.0 (2026-06-27)
|
| 11 |
+
|
| 12 |
+
- Pi 5 SD-card image to run a Reachy Mini Lite USB wirelessly, over reachy-mini-os.
|
| 13 |
+
- Motors, camera, sound and the official app over Bluetooth all work (daemon v1.8.4).
|
| 14 |
+
- A prebuilt image to flash, plus a reproducible Docker build.
|
Dockerfile.cm5
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Build a CM5 image of reachy-mini-os, inside Docker: for a CM5 swapped into the
|
| 2 |
+
# Reachy Mini Wireless carrier (the stock robot ships a CM4). Usage: see README.md.
|
| 3 |
+
FROM debian:bookworm
|
| 4 |
+
|
| 5 |
+
# pi-gen build tools
|
| 6 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 7 |
+
ca-certificates git git-lfs curl \
|
| 8 |
+
quilt parted debootstrap zerofree zip dosfstools e2fsprogs fdisk \
|
| 9 |
+
libarchive-tools libcap2-bin rsync xz-utils file kmod bc gpg pigz xxd \
|
| 10 |
+
arch-test binfmt-support qemu-user-static \
|
| 11 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 12 |
+
|
| 13 |
+
# reachy-mini-os source (pi-gen fork) + its Git LFS files
|
| 14 |
+
RUN git lfs install \
|
| 15 |
+
&& git clone --depth 1 https://github.com/pollen-robotics/reachy-mini-os.git /pi-gen
|
| 16 |
+
WORKDIR /pi-gen
|
| 17 |
+
RUN git lfs pull
|
| 18 |
+
|
| 19 |
+
# CM5 boot tweaks + pinned daemon version. Unlike the Pi 5 build:
|
| 20 |
+
# - dtparam=ant2 stays (the CM5 has the U.FL connector, the Wireless uses the external antenna)
|
| 21 |
+
# - the imx708/i2c overlays stay (the Wireless camera is CSI)
|
| 22 |
+
# The motor bus keeps GPIO4/5, which on the CM5 is RP1 uart2 (ttyAMA2), not the CM4's uart3.
|
| 23 |
+
ARG DAEMON_VERSION=v1.8.4
|
| 24 |
+
RUN set -e; \
|
| 25 |
+
sed -i 's/^IMG_NAME="reachyminios"$/IMG_NAME="reachyminios-cm5"/' config; \
|
| 26 |
+
cfg=stage1/00-boot-files/files/config.txt; \
|
| 27 |
+
sed -i 's/^dtoverlay=uart3$/dtoverlay=uart2-pi5/' "$cfg"; \
|
| 28 |
+
sed -i -E "s/reachy-mini\[wireless-version\]==v[0-9.]+/reachy-mini[wireless-version]==${DAEMON_VERSION}/" \
|
| 29 |
+
stage2/05-reachy-mini/01-run-chroot.sh
|
| 30 |
+
|
| 31 |
+
# CM5 runtime fixes (motors, shutdown, software H264 encoder)
|
| 32 |
+
COPY docker/stage-cm5-fixes.sh stage2/05-reachy-mini/02-run-chroot.sh
|
| 33 |
+
RUN chmod +x stage2/05-reachy-mini/02-run-chroot.sh
|
| 34 |
+
|
| 35 |
+
# the build itself runs at `docker run` (needs --privileged: loop devices + ARM emulation)
|
| 36 |
+
COPY docker/entrypoint.sh /entrypoint.sh
|
| 37 |
+
RUN chmod +x /entrypoint.sh
|
| 38 |
+
ENTRYPOINT ["/entrypoint.sh"]
|
README.md
CHANGED
|
@@ -47,6 +47,17 @@ Image lands in `./deploy/*.zip`, then flash it (see [Getting started](#getting-s
|
|
| 47 |
|
| 48 |
> Override the daemon version with `docker build --build-arg DAEMON_VERSION=v1.8.4 -t reachy-pi5 .`
|
| 49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
## First boot & SSH if needed
|
| 51 |
|
| 52 |
The image ships the `pollen` user with SSH enabled — nothing to set up in Imager.
|
|
@@ -64,3 +75,7 @@ Everything (services, the venv, sudo) is built around `pollen` — that's why yo
|
|
| 64 |
## How it works
|
| 65 |
|
| 66 |
The [Dockerfile](Dockerfile) downloads `reachy-mini-os`, patches `config.txt` (Pi 5 motor UART, antenna), pins the daemon, and bakes the fixes from [docker/stage-pi5-fixes.sh](docker/stage-pi5-fixes.sh). Each fix lives in `/etc`, `/usr/local`, or `sitecustomize.py`, so it survives reboots and daemon self-updates.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
> Override the daemon version with `docker build --build-arg DAEMON_VERSION=v1.8.4 -t reachy-pi5 .`
|
| 49 |
|
| 50 |
+
### CM5 variant (Wireless carrier)
|
| 51 |
+
|
| 52 |
+
The **Reachy Mini Wireless** ships a CM4; a CM5 pops right into the carrier (see [the community swap thread](https://github.com/geerlingguy/raspberry-pi-pcie-devices/issues/800)). [Dockerfile.cm5](Dockerfile.cm5) builds the image for that swap: motor UART on `uart2-pi5` with the same udev alias, external antenna kept, the CSI camera keeps libcamera (do **not** use the Pi 5 image there, its camera fix targets the Lite's USB camera), and the WebRTC stream encodes with x264 in software since the CM5 has no hardware encoder ([docker/stage-cm5-fixes.sh](docker/stage-cm5-fixes.sh)).
|
| 53 |
+
|
| 54 |
+
```bash
|
| 55 |
+
docker build -f Dockerfile.cm5 -t reachy-cm5 .
|
| 56 |
+
docker run --rm --privileged -v "$PWD/deploy:/pi-gen/deploy" reachy-cm5
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
An eMMC CM5 flashes through `rpiboot`/usbboot rather than an SD card. ⚠️ Not yet tested on hardware: the [CM5 camera timeout](https://github.com/geerlingguy/raspberry-pi-pcie-devices/issues/800) reported by the community is an open question this image may still hit.
|
| 60 |
+
|
| 61 |
## First boot & SSH if needed
|
| 62 |
|
| 63 |
The image ships the `pollen` user with SSH enabled — nothing to set up in Imager.
|
|
|
|
| 75 |
## How it works
|
| 76 |
|
| 77 |
The [Dockerfile](Dockerfile) downloads `reachy-mini-os`, patches `config.txt` (Pi 5 motor UART, antenna), pins the daemon, and bakes the fixes from [docker/stage-pi5-fixes.sh](docker/stage-pi5-fixes.sh). Each fix lives in `/etc`, `/usr/local`, or `sitecustomize.py`, so it survives reboots and daemon self-updates.
|
| 78 |
+
|
| 79 |
+
## Changelog
|
| 80 |
+
|
| 81 |
+
Each release and what it brought is in [CHANGELOG.md](CHANGELOG.md).
|
VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
1.1.0
|
docker/stage-cm5-fixes.sh
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash -e
|
| 2 |
+
# CM5 fixes baked into the image, kept outside the Python package so daemon updates don't wipe them.
|
| 3 |
+
# Target: a CM5 swapped into the Reachy Mini Wireless carrier (issue geerlingguy/raspberry-pi-pcie-devices#800).
|
| 4 |
+
# Same BCM2712+RP1 silicon as the Pi 5; the camera path is where the two variants differ:
|
| 5 |
+
# the Wireless camera is CSI (imx708) and NEEDS libcamera, so unlike stage-pi5-fixes.sh
|
| 6 |
+
# nothing is disabled here, and the WebRTC encoder goes software (no HW encoder on BCM2712).
|
| 7 |
+
|
| 8 |
+
echo "Fix 1/3: motor port -> /dev/ttyAMA3 (udev)"
|
| 9 |
+
# the carrier's motor bus is on GPIO4/5: RP1 uart2 on the CM5 (ttyAMA2), not the CM4's uart3
|
| 10 |
+
install -d -m 0755 /etc/udev/rules.d
|
| 11 |
+
cat > /etc/udev/rules.d/99-reachy-cm5-motor.rules <<'RULE'
|
| 12 |
+
# /dev/ttyAMA3 = whichever motor bus exists (USB controller, or GPIO uart2)
|
| 13 |
+
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d3", SYMLINK+="ttyAMA3", GROUP="dialout", MODE="0660"
|
| 14 |
+
KERNEL=="ttyAMA2", SYMLINK+="ttyAMA3", GROUP="dialout", MODE="0660"
|
| 15 |
+
RULE
|
| 16 |
+
|
| 17 |
+
echo "Fix 2/3: shutdown button -> gpiozero lgpio backend"
|
| 18 |
+
install -d -m 0755 /etc/systemd/system/gpio-shutdown-daemon.service.d
|
| 19 |
+
cat > /etc/systemd/system/gpio-shutdown-daemon.service.d/10-cm5-lgpio.conf <<'DROP'
|
| 20 |
+
[Service]
|
| 21 |
+
Environment=GPIOZERO_PIN_FACTORY=lgpio
|
| 22 |
+
DROP
|
| 23 |
+
source /opt/uv/env 2>/dev/null || true
|
| 24 |
+
if [ -f /venvs/mini_daemon/bin/activate ]; then
|
| 25 |
+
source /venvs/mini_daemon/bin/activate
|
| 26 |
+
uv pip install lgpio || pip install lgpio || true
|
| 27 |
+
fi
|
| 28 |
+
|
| 29 |
+
echo "Fix 3/3: software H264 encoder for the WebRTC stream"
|
| 30 |
+
# the daemon's CSI path hardcodes v4l2h264enc, a hardware element the CM5 does not have:
|
| 31 |
+
# swap that one method for an x264enc version at import time
|
| 32 |
+
cat > /venvs/mini_daemon/lib/python3.12/site-packages/sitecustomize.py <<'PY'
|
| 33 |
+
# ReachyPi CM5: no hardware H264 encoder on BCM2712 -> encode the WebRTC branch in software
|
| 34 |
+
def _sw_encoder():
|
| 35 |
+
try:
|
| 36 |
+
from reachy_mini.media import media_server as ms
|
| 37 |
+
from gi.repository import Gst
|
| 38 |
+
except Exception:
|
| 39 |
+
return
|
| 40 |
+
def sw_branch(self, queue_webrtc, pipeline, webrtcsink):
|
| 41 |
+
convert = Gst.ElementFactory.make("videoconvert")
|
| 42 |
+
x264 = Gst.ElementFactory.make("x264enc")
|
| 43 |
+
caps_h264 = Gst.ElementFactory.make("capsfilter")
|
| 44 |
+
if not all([convert, x264, caps_h264]):
|
| 45 |
+
raise RuntimeError("Failed to create x264 encoder elements")
|
| 46 |
+
Gst.util_set_object_arg(x264, "tune", "zerolatency")
|
| 47 |
+
Gst.util_set_object_arg(x264, "speed-preset", "ultrafast")
|
| 48 |
+
x264.set_property("bitrate", 5000) # kbit/s, same 5 Mb/s as the hardware branch
|
| 49 |
+
x264.set_property("key-int-max", 60) # same keyframe period
|
| 50 |
+
caps_h264.set_property("caps", Gst.Caps.from_string(
|
| 51 |
+
"video/x-h264,stream-format=byte-stream,alignment=au,"
|
| 52 |
+
"level=(string)3.1,profile=(string)constrained-baseline"))
|
| 53 |
+
for elem in (convert, x264, caps_h264):
|
| 54 |
+
pipeline.add(elem)
|
| 55 |
+
queue_webrtc.link(convert)
|
| 56 |
+
convert.link(x264)
|
| 57 |
+
x264.link(caps_h264)
|
| 58 |
+
caps_h264.link(webrtcsink)
|
| 59 |
+
ms.GstMediaServer._build_rpi_encoder_branch = sw_branch
|
| 60 |
+
_sw_encoder()
|
| 61 |
+
PY
|
| 62 |
+
|
| 63 |
+
echo "CM5 fixes applied."
|
image_2026-07-19-reachyminios-cm5.zip
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8c8d55c80e034f9d497804934717d99acd739700dd6434ccea198d6a3e7a9d44
|
| 3 |
+
size 1719753241
|