Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
354ca90
Switch to pi-gen 2025-10-01-raspios-trixie-arm64
Apehaenger Oct 16, 2025
2dcb742
Actualized docs
Apehaenger Oct 16, 2025
b780330
Restrict dnsmasq to only listen on eth0
ClemensElflein Oct 16, 2025
e830703
ros configuration
Apehaenger Dec 16, 2025
041c157
Merge branch 'main' into feat/RC3-Prep
Apehaenger Dec 16, 2025
24d5415
Add CM5 tested features
Apehaenger Dec 16, 2025
5441fa0
Set mow_angle_increment to 0 in mower_params.yaml
ClemensElflein Dec 23, 2025
b32f2bc
Update new cases
Apehaenger Jan 3, 2026
d8bb3cc
Fix comitup no-IP issue
Apehaenger Jan 5, 2026
1df9ca8
🐛 fix(comitup): correct service configuration and script paths
Apehaenger Jan 6, 2026
ad096a7
Disable cloud-init and netplan installation
Apehaenger Jan 6, 2026
9e34b9f
📝 docs(tested_features): update test status and add CM5 specific foot…
Apehaenger Jan 6, 2026
a0aeb1b
📝 docs(TESTED_FEATURES): update comitup portal test status
Apehaenger Jan 6, 2026
85a7b6b
✨ feat(openocd): add openocd build and configuration stage
Apehaenger Jan 6, 2026
96fd9c0
✨ feat(openmower): add data directory and ros log symlink
Apehaenger Jan 6, 2026
268aeb5
Make coderrabbit happy
Apehaenger Jan 6, 2026
c25bae8
🐛 fix(openocd): correct file ownership and permissions in setup scripts
Apehaenger Jan 6, 2026
04e1066
🐛 fix(openocd): add null check for GPIO_CHIP variable
Apehaenger Jan 6, 2026
b3ace29
📝 docs(TESTED_FEATURES): update hardware test matrix and add note
Apehaenger Jan 7, 2026
d4f0e6d
Fix typo
Apehaenger Jan 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 6 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ Tip: Click a section title to expand/collapse.

3. After writing the image, eject the card, insert it into your mower’s Pi or xCore, and turn it on.

4. Your Pi will boot multiple times.<br>
***Sometimes, after the first boot, it may fail to reboot*** (the Pi/xCore’s green LED doesn’t flicker anymore and remains off for >10 seconds). If that happens, a power cycle will get it back on track.
4. Your Pi will boot multiple times. Be patient and wait till the green activity LED becomes silent for ≥ 10 seconds.<br>

5. ***Optional: Comitup hotspot (if you skipped step 2 "Raspberry Pi Imager configuration")***<br>
If you didn't enter your Wifi settings when asked for the custom settings during Pi Imager (see step 2), or if you accidentally entered the wrong Wifi settings:
Expand All @@ -61,7 +60,7 @@ If you didn't enter your Wifi settings when asked for the custom settings during

4. The hotspot will disappear and the mower should connect to your WiFi.

6. Two minutes after the second reboot, try pinging your mower via `ping openmower` (or the hostname you entered during Pi Imager). If the host can't be found, check your router for the mower's IP address.
6. Once the green activity LED becomes silent, try pinging your mower via `ping openmower` (or the hostname you entered during Pi Imager). If the host can't be found, check your router for the mower's IP address.

7. ***Optional:***<br>
1. If you didn't configure a custom password during step 2 (Raspberry Pi Imager configuration), login via SSH and change your password now via `passwd`.
Expand All @@ -75,10 +74,9 @@ If you didn't enter your Wifi settings when asked for the custom settings during
<summary><b>Manage OpenMower stack (GUI + CLI)</b></summary>

[Dockge](https://dockge.kuma.pet/) (a container manager GUI) and [ttyd](https://tsl0922.github.io/ttyd/) (a web terminal)
are bundled with the OpenMowerOS image and are unpacked and installed during the final second‑boot step.
This may take about 2 minutes.
are bundled together with the OpenMowerOS image, get unpacked and installed during the final boot step.

Please wait while the Pi/xCore’s green LED is flickering or steadily on.
Please wait till Pi/xCore’s green LED becomes silent for ≥ 10 seconds.

The WebTerminal is available as a lightweight alternative to SSH for running the same commands.
It can be reached via `http://openmower:7681` (adjust if you changed the hostname).
Expand All @@ -99,18 +97,12 @@ For each relevant GUI action, a CLI alternative is available via a powerful `ope
![Save .env](.github/img/dockge_04_save.jpg)

3. Start the stack (including the initial pull)
- CLI: If you configured your .env file via `openmower configure env` then the stack is pulled and started automatically.<br>
If not:

```bash
openmower pull
openmower start
```
- CLI: If you configured your .env file via `openmower configure env` then the stack is pulled and started automatically.
- GUI:
![Start Stack](.github/img/dockge_05_start.jpg)

4. Check status and open the OpenMower web app
- CLI: `openmower status` should list three service names (open_mower_ros, Mosquitto and OpenMowerApp), all with status 'up'. If so, open a browser and visit `http://openmower:8080` (or your configured hostname).
- CLI: `openmower status` should list three services (open_mower_ros, Mosquitto and OpenMowerApp), all with status 'up'. If so, open a browser and visit `http://openmower:8080` (or your configured hostname).
- GUI:
![Stack Active](.github/img/dockge_06_active.jpg)

Expand Down
47 changes: 25 additions & 22 deletions TESTED_FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,33 @@

Legend: ✅ Pass · ❌ Fail · 🟡 Todo · 🔁 Retry · 🧪 Manual-only

| Feature | Expected | HW‑V1<br>Pi4 | HW‑V2<br>CM4 | HW‑V2<br>CM5 |
| ---------------------------------------- | ----------------------------------------- | :----------: | :----------: | :----------: |
| Auto-reboot after initial boot | yes, but seem to be a bug | ✅ | ❌🧪 | 🟡 |
| Debian release `lsb_release -a` | Debian GNU/Linux 13 (trixie) | ✅ | ✅ | 🟡 |
| OpenMowerOS release `cat /etc/rpi-issue` | OpenMowerOS v2.x YYYY-MM-DD | ✅ | ✅ | 🟡 |
| Hostname (default) `hostname` | openmower | 🟡 | ✅ | 🟡 |
| Hostname (non- default) `hostname` | <as set by imager> | ✅ | ✅ | 🟡 |
| Default user/password | openmower/openmower | 🟡 | ✅ | 🟡 |
| SSH enabled | SSH active on first boot | ✅ | ✅ | 🟡 |
| SSH public key | Password less SSH login via SSH-key | 🟡 | ✅ | 🟡 |
| Imager Wi‑Fi | Preseeded Wi‑Fi connects on first boot | ✅ | ✅ | 🟡 |
| Imager openmower pass | Applied when configured | ✅ | ✅ | 🟡 |
| No known Wi‑Fi | Comitup AP appears (default SSID pattern) | 🟡 | ✅ | 🟡 |
| AP portal | Able to configure Wi‑Fi, then joins WLAN | 🟡 | ✅ | 🟡 |
| Internal LAN | xCore is getting an IPv4 | -- | ✅ | 🟡 |
| Home LAN | eth0 IPv4 by your networks DHCP | 🟡 | ✅ | 🟡 |
| SSH | Reachable after network is up | ✅ | ✅ | 🟡 |
| WebTerminal (ttyd) | Reachable at port 7681 | ✅ | ✅ | 🟡 |
| Dockge | Reachable at port 5001 | ✅ | ✅ | 🟡 |
| ESC access | Ports get exposed via `openmower ...` cmd | ✅ | 🟡 | 🟡 |
| GNSS access | Port get exposed via `openmower ...` cmd | ✅ | 🟡 | 🟡 |
| Container shell (prefix) | `openmower shell` has docker prefix | ✅ | ✅ | 🟡 |
| Feature | Expected | HW‑V1<br>Pi4 | HW‑V2<br>CM4 | HW‑V2<br>CM5 |
| ---------------------------------------- | --------------------------------------------- | :----------: | :----------: | :----------: |
| Auto-reboot after initial boot | yes | ✅ | ✅ | ✅ |
| Debian release `lsb_release -a` | Debian GNU/Linux 13 (trixie) | ✅ | ✅ | ✅ |
| OpenMowerOS release `cat /etc/rpi-issue` | OpenMowerOS v2.x YYYY-MM-DD | ✅ | ✅ | ✅ |
| Hostname (default) `hostname` | openmower | 🟡 | ✅ | ✅ |
| Hostname (non-default) `hostname` | <as set by Raspberry Pi Imager v1.9.x> | ✅ | ✅ | ✅ |
| Default user/password | openmower/openmower | 🟡 | ✅ | ✅ |
| SSH enabled | SSH active on first boot | ✅ | ✅ | ✅ |
| SSH public key | Password less SSH login via SSH-key | 🟡 | ✅ | ✅ |
| Imager Wi‑Fi | Preseeded Wi‑Fi connects on first boot | ✅ | ✅ | ✅ |
| Imager openmower pass | Applied when configured | ✅ | ✅ | ✅ |
| No known Wi‑Fi | Comitup AP appears (default SSID pattern) | 🟡 | ✅ | ✅ |
| Comitup captive portal | Able to configure Wi‑Fi, then joins WLAN [^1] | 🟡 | ✅ | ✅ |
| Internal LAN | xCore is getting an IPv4 | 🟡 | ✅ | ✅ |
| Home LAN | eth0 IPv4 by your networks DHCP | 🟡 | ✅ | ✅ |
| SSH | Reachable after network is up | ✅ | ✅ | ✅ |
| WebTerminal (ttyd) | Reachable at port 7681 | ✅ | ✅ | ✅ |
| Dockge | Reachable at port 5001 | ✅ | ✅ | ✅ |
| ESC access | Ports get exposed via `openmower ...` cmd | ✅ | ✅ | 🟡 |
| GNSS access | Port get exposed via `openmower ...` cmd | ✅ | 🟡 | 🟡 |
| OpenOCD remote debugging | Remote debugging via `openmower openocd` | 🟡 | ✅ | ✅ |
| Container shell (prefix) | `openmower shell` has docker prefix | ✅ | ✅ | ✅ |

## Notes

- Update cells as you validate on each hardware combo.
- If Imager Wi‑Fi is set, Comitup should not spawn AP; if not, AP should appear.

[^1]: You probably need to power-cycle your mower after entering your home WiFi credentials
2 changes: 2 additions & 0 deletions pi-gen.config
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ STAGE_LIST="/pi-gen/stage0 /pi-gen/stage1 /pi-gen/stage2 /stage-openmower"
# Compression of exported image
DEPLOY_COMPRESSION=zip
COMPRESSION_LEVEL=6

ENABLE_CLOUD_INIT=0
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ dtparam=ant1
# External- U.FL/IPEX antenna connector:
# dtparam=ant2

# Fan control (on CM4 it's GPIO18)
dtoverlay=pwm-gpio-fan,fan_gpio=18
# Fan control (GPIO fan) — enable and set start temperature (in millidegrees C)
dtoverlay=pwm-gpio-fan,fan_gpio=18,temp=70000

[cm5]
# CM5 antenna selection — choose Wi‑Fi antenna path
Expand All @@ -66,6 +66,5 @@ dtparam=ant1
# External- U.FL/IPEX antenna connector:
# dtparam=ant2

# Fan control (on CM5 it's GPIO18)
dtoverlay=pwm-gpio-fan,fan_gpio=18

# Fan control (GPIO fan) — enable and set start temperature (in millidegrees C)
dtoverlay=pwm-gpio-fan,fan_gpio=18,temp=70000
6 changes: 5 additions & 1 deletion stage-openmower/20-comitup/00-run-chroot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ apt-get update
apt-get install -y --no-install-recommends comitup network-manager wpasupplicant rfkill

systemctl enable comitup.service
systemctl enable comitup-web.service
systemctl enable comitup-nm-wifi-ensure.service

systemctl mask NetworkManager-wait-online.service
systemctl mask wpa-supplicant.service

if ! grep -q '^ap_name:' /etc/comitup.conf 2>/dev/null; then
printf '\n# Default OpenMower AP name for provisioning\nap_name: OpenMower-<nnn>\n' >> /etc/comitup.conf
fi

# Enable external_callback to manage dnsmasq
sed -i 's/^#\s*external_callback:.*/external_callback: \/usr\/local\/bin\/comitup-callback/' /etc/comitup.conf
chown -R root:root /usr/local/bin/comitup-callback
1 change: 1 addition & 0 deletions stage-openmower/20-comitup/00-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ STAGE_DIR="$(dirname "$0")"
# Install files
install -m 0644 -D "$STAGE_DIR/files/etc/NetworkManager/conf.d/10-comitup.conf" "$ROOTFS_DIR/etc/NetworkManager/conf.d/10-comitup.conf"
install -m 0644 -D "$STAGE_DIR/files/etc/systemd/system/comitup-nm-wifi-ensure.service" "$ROOTFS_DIR/etc/systemd/system/comitup-nm-wifi-ensure.service"
install -m 0755 -D "$STAGE_DIR/files/usr/local/bin/comitup-callback" "$ROOTFS_DIR/usr/local/bin/comitup-callback"
32 changes: 32 additions & 0 deletions stage-openmower/20-comitup/files/usr/local/bin/comitup-callback
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
# Callback script for comitup to manage dnsmasq
# Argument: $1 = state (HOTSPOT, CONNECTING, CONNECTED)

LOG="/var/log/comitup-callback.log"
DNSMASQ_SERVICE="dnsmasq.service"

log() {
echo "$(date): $*" >> "$LOG"
}

case "$1" in
HOTSPOT)
log "Entering HOTSPOT mode - stopping dnsmasq"
systemctl stop "$DNSMASQ_SERVICE" 2>/dev/null
pkill -9 dnsmasq 2>/dev/null
# Ensure no dnsmasq is listening on port 67
ss -ulpn | grep :67 && log "WARNING: Port 67 still occupied"
;;
CONNECTING)
log "Entering CONNECTING mode - dnsmasq remains stopped"
;;
CONNECTED)
log "Entering CONNECTED mode - restarting dnsmasq"
systemctl start "$DNSMASQ_SERVICE" 2>/dev/null
;;
*)
log "Unknown state: $1"
;;
esac

exit 0
6 changes: 6 additions & 0 deletions stage-openmower/25-lan/files/etc/dnsmasq.d/10-openmower.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
# specified interfaces (and the loopback) give the name of the
# interface (eg eth0) here.
# Repeat the line for more than one interface.
#
# AH20260105:
# bind-interfaces together with interface does not work as expected.
# dnsmasq always bind to 0.0.0.0:67. No 2nd dnsmasq on other interface bindable!
# See workaround in /usr/local/bin/comitup-callback
#bind-interfaces
#interface=eth0
# Or you can specify which interface _not_ to listen on
#except-interface=
Expand Down
6 changes: 6 additions & 0 deletions stage-openmower/40-openmower/00-run-chroot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ chown -R 1000:1000 /home/openmower/ros
mkdir -p /home/openmower/params
chown -R 1000:1000 /home/openmower/params

# Create dir and symlink for easy access to "latest" ros log
mkdir -p /data
chown -R 1000:1000 /data
ln -s /home/openmower/ros /data/ros


export DEBIAN_FRONTEND=noninteractive

# Minimal deps for fetching & unpacking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ mower_logic:
outline_overlap_count: 1
mow_angle_offset: 0
mow_angle_offset_is_absolute: false
mow_angle_increment: 110
mow_angle_increment: 0
gps_wait_time: 5.0
gps_timeout: 5.0
rain_mode: 0
rain_delay_minutes: 30
rain_check_seconds: 20
undock_distance: 1.0
undock_angled_distance: 2.0
undock_angle: 45.0
undock_angle: 0.0
undock_fixed_angle: false
undock_use_curve: true
# Once you validated the functionality of your emergency sensors,
Expand Down
23 changes: 23 additions & 0 deletions stage-openmower/45-openocd/00-run-chroot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash -e

chown -R 1000:1000 /home/openmower/.config

export DEBIAN_FRONTEND=noninteractive

# Install dependencies
apt-get update
apt-get install -y --no-install-recommends autoconf automake build-essential curl libftdi-dev libtool libusb-1.0-0-dev git pkg-config rpi.gpio-common texinfo libgpiod-dev libjim-dev

# Create directory for OpenOCD
mkdir -p /opt
cd /opt

# Clone OpenOCD repository
git clone https://github.com/raspberrypi/openocd.git --recursive

# Bootstrap, configure, compile, and install OpenOCD
cd openocd
./bootstrap
./configure --enable-ftdi --enable-sysfsgpio --enable-bcm2835gpio --enable-linuxgpiod
make -j$(nproc)
make install
10 changes: 10 additions & 0 deletions stage-openmower/45-openocd/00-run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash -e

STAGE_DIR="$(dirname "$0")"

# Install files
install -m 0755 -d "$ROOTFS_DIR/home/openmower/.config/openmower-cli"
install -m 0664 -D "$STAGE_DIR/files/xcore.cfg" "$ROOTFS_DIR/home/openmower/.config/openmower-cli/xcore.cfg"

install -o "root" -m 0755 -d "$ROOTFS_DIR/root/.config/openmower-cli"
install -o "root" -m 0664 -D "$STAGE_DIR/files/xcore.cfg" "$ROOTFS_DIR/root/.config/openmower-cli/xcore.cfg"
34 changes: 34 additions & 0 deletions stage-openmower/45-openocd/files/xcore.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-License-Identifier: GPL-2.0-or-later

# Config for Raspberry Pi 5 used as a bitbang adapter.
# https://www.raspberrypi.com/documentation/computers/raspberry-pi.html

# Raspberry Pi 5 is not compatible with bcm2835gpio native GPIO driver.
# The linuxgpiod driver without configurable adapter speed runs at approximately
# 800 kHz (SWD writes) and 360 kHz (SWD reads)

adapter driver linuxgpiod

proc read_file { name } {
if {[catch {open $name r} fd]} {
return ""
}
set result [read $fd]
close $fd
return $result
}

set pcie_aspm [read_file /sys/module/pcie_aspm/parameters/policy]
if {![string match {*\[performance\]*} $pcie_aspm]} {
echo "Warn : Switch PCIe power saving off or the first couple of pulses gets clocked as fast as 20 MHz"
echo "Warn : Issue 'echo performance | sudo tee /sys/module/pcie_aspm/parameters/policy'"
}

set _GPIO_CHIP 0

# Each of the SWD lines need a gpio number set: swclk swdio
# OpenMower pins
adapter gpio swclk -chip $_GPIO_CHIP 27
adapter gpio swdio -chip $_GPIO_CHIP 22

transport select swd
1 change: 0 additions & 1 deletion stage-openmower/50-extras/00-packages-nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Install a few helpful packages
mc
openocd
wavemon
aptitude
socat
Expand Down