Domotick commited on
Commit
d177e5f
·
1 Parent(s): 69e3856

- 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 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