Skip to content

Commit 2f408e1

Browse files
committed
update readme + rename to .bash
1 parent 931a5b6 commit 2f408e1

16 files changed

Lines changed: 288 additions & 81 deletions

.github/workflows/main.yml

Lines changed: 0 additions & 41 deletions
This file was deleted.

README.md

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,30 +53,30 @@ sudo dd if=outputs/pi5_flash_image.img of=/dev/sdX bs=4M status=progress conv=fs
5353

5454
- Based on `ubuntu:24.04`, installs tooling (qemu-user-static, kpartx, parted, e2fsprogs, etc.)
5555
- Downloads `raspios-bookworm-arm64-lite` and expands the image by 4 GB
56-
- Entrypoint runs `setup_image.sh` then `export_image_and_compress.sh`
56+
- Entrypoint runs `setup_image.bash` then `export_image_and_compress.bash`
5757

58-
- `setup_image.sh`
58+
- `setup_image.bash`
5959

6060
- Attaches loop devices, fixes/extends partitions, runs `resize2fs`
6161
- Mounts the image (root and boot), binds `/dev`, `/proc`, `/sys`, `/workspace`
6262
- Copies `qemu-aarch64-static` into the chroot for ARM emulation
63-
- Chroots into the image and runs `main_startup.sh pi5.sh`
63+
- Chroots into the image and runs `main_startup.bash pi5.bash`
6464

65-
- Inside the chroot (`main_startup.sh`)
65+
- Inside the chroot (`main_startup.bash`)
6666

67-
- Runs hardware script `pi5.sh` (installs udev rule)
68-
- Runs `installation_common.sh` (packages, Rust, SSH/mDNS enable)
69-
- Runs `installation_blitz.sh` (clones B.L.I.T.Z, `scripts/install.sh` with default name)
70-
- Runs `installation_autobahn.sh` (clones Autobahn, installs)
71-
- Runs `post_install.sh` (installs and enables first-boot service)
67+
- Runs hardware script `pi5.bash` (installs udev rule)
68+
- Runs `installation_common.bash` (packages, Rust, SSH/mDNS enable)
69+
- Runs `installation_blitz.bash` (clones B.L.I.T.Z, `scripts/install.bash` with default name)
70+
- Runs `installation_autobahn.bash` (clones Autobahn, installs)
71+
- Runs `post_install.bash` (installs and enables first-boot service)
7272

73-
- `export_image_and_compress.sh`
73+
- `export_image_and_compress.bash`
7474
- Cleanly unmounts/breaks down loop/mapper devices
7575
- Renames the image, compresses to `.img.xz`, and copies into `./outputs/`
7676

7777
## First boot behavior
7878

79-
- A systemd service (`blitz_project.service`) runs `/usr/local/bin/blitzprojstartup.sh`.
79+
- A systemd service (`blitz_project.service`) runs `/usr/local/bin/blitzprojstartup.bash`.
8080
- On first boot, if the default name is still set, it will prompt on the console for a new device name and apply it (`hostnamectl`, `/etc/hosts`, restart Avahi/SSH), then reboot.
8181
- If you need a non-interactive first boot, pre-create `name.txt` inside the image at:
8282
- `/opt/blitz/B.L.I.T.Z/system_data/name.txt`
@@ -85,26 +85,26 @@ sudo dd if=outputs/pi5_flash_image.img of=/dev/sdX bs=4M status=progress conv=fs
8585

8686
- **Base image version**: in `Dockerfile` (`wget` URL). Update to a newer Raspberry Pi OS image if desired.
8787
- **Extra space**: in `Dockerfile` (`truncate -s +4G ...`). Increase if you need more room preinstalled.
88-
- **Hardware script**: currently `main_startup.sh` runs `pi5.sh`. Add your own script and change the argument in `setup_image.sh` (`main_startup.sh <your-script>.sh`).
89-
- **B.L.I.T.Z branch**: in `installation_blitz.sh` (`BRANCH_NAME="merge-backend"`). Change as needed.
90-
- **Default device name**: `installation_blitz.sh` (`DEFAULT_PI_NAME`). This is used on first boot before prompting.
91-
- **udev rules**: edit `installation/system-patch/90-usb-port-names.rules` or adapt `pi5.sh` to your hardware.
92-
- **Output filename**: `export_image_and_compress.sh` is invoked with `pi5_flash_image` by default (from `Dockerfile CMD`). Change it if you want a different name.
88+
- **Hardware script**: currently `main_startup.bash` runs `pi5.bash`. Add your own script and change the argument in `setup_image.bash` (`main_startup.bash <your-script>.bash`).
89+
- **B.L.I.T.Z branch**: in `installation_blitz.bash` (`BRANCH_NAME="merge-backend"`). Change as needed.
90+
- **Default device name**: `installation_blitz.bash` (`DEFAULT_PI_NAME`). This is used on first boot before prompting.
91+
- **udev rules**: edit `installation/system-patch/90-usb-port-names.rules` or adapt `pi5.bash` to your hardware.
92+
- **Output filename**: `export_image_and_compress.bash` is invoked with `pi5_flash_image` by default (from `Dockerfile CMD`). Change it if you want a different name.
9393

9494
## Directory overview
9595

9696
- `Dockerfile`: Builder and orchestrator for the image creation
9797
- `compose.yml`: Docker Compose service (privileged) that runs the pipeline
98-
- `setup_image.sh`: Mounts/extends the downloaded image and enters chroot
99-
- `main_startup.sh`: Orchestrates installs and setup inside the chroot
100-
- `pi5.sh`: Installs udev rule for USB port naming
101-
- `installation_common.sh`: Common packages, Rust toolchain, SSH/mDNS enable
102-
- `installation_blitz.sh`: Clones/installs B.L.I.T.Z
103-
- `installation_autobahn.sh`: Clones/installs Autobahn
104-
- `post_install.sh`: Installs and enables first-boot naming service
98+
- `setup_image.bash`: Mounts/extends the downloaded image and enters chroot
99+
- `main_startup.bash`: Orchestrates installs and setup inside the chroot
100+
- `pi5.bash`: Installs udev rule for USB port naming
101+
- `installation_common.bash`: Common packages, Rust toolchain, SSH/mDNS enable
102+
- `installation_blitz.bash`: Clones/installs B.L.I.T.Z
103+
- `installation_autobahn.bash`: Clones/installs Autobahn
104+
- `post_install.bash`: Installs and enables first-boot naming service
105105
- `blitz_project.service`: systemd unit for first-boot naming
106-
- `blitzprojstartup.sh`: prompts for device name on first boot
107-
- `export_image_and_compress.sh`: unmounts, compresses, and copies output
106+
- `blitzprojstartup.bash`: prompts for device name on first boot
107+
- `export_image_and_compress.bash`: unmounts, compresses, and copies output
108108
- `outputs/`: final `.img.xz` artifacts
109109

110110
## Troubleshooting

docs/HowWorks.md

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# How This Project Works and How to Customize It
2+
3+
This project builds a Raspberry Pi OS image that already has the Pinewood Robotics software stack installed (B.L.I.T.Z + Autobahn), plus some device-specific system setup.
4+
5+
The important idea is: **do all the image editing inside Docker**, using QEMU so we can chroot into an ARM64 Raspberry Pi OS image from an x86_64 machine.
6+
7+
## What this project produces
8+
9+
- A flashable Raspberry Pi OS `.img` file (optionally compressed to `.img.xz`)
10+
- The image is preconfigured so the device boots with:
11+
- system dependencies installed
12+
- SSH + mDNS enabled (so it is reachable on the network)
13+
- B.L.I.T.Z installed (from a chosen branch)
14+
- Autobahn installed
15+
- a USB udev naming rule applied (so ports map to stable names)
16+
- a first-boot flow that asks you to set the device name (hostname)
17+
18+
Outputs are written to `outputs/`.
19+
20+
## Big picture flow (methodology)
21+
22+
The pipeline is a sequence of small steps. Each step has one job and is easy to swap out.
23+
24+
### 1) Build container environment
25+
26+
- `Dockerfile` installs the tools needed to manipulate disk images:
27+
- loop devices, partition tools, filesystem tools
28+
- `qemu-user-static` so the host can execute ARM64 binaries via emulation
29+
- `compose.yml` runs the container in **privileged** mode so loop devices and `kpartx` work.
30+
31+
### 2) Pick a target device and base OS image
32+
33+
- Device definitions live in `installation/devices_and_distros/`.
34+
- `devices.conf` maps device keys to a Raspberry Pi OS download URL and filename.
35+
- The entrypoint (`installation/devices_and_distros/build.bash`) chooses:
36+
- build all device scripts, or
37+
- build one device script (example: `pi5`)
38+
39+
### 3) Download and unpack the base image (with caching)
40+
41+
- `installation/util/install_distro.bash` downloads the `.img.xz` into:
42+
- `installation/cached_images/` (on the host via the Docker volume)
43+
- It then decompresses into the container workspace so we can edit it.
44+
45+
Why this is structured this way:
46+
47+
- **Host cache** avoids re-downloading the large base image every run.
48+
- **Workspace copy** avoids mutating the cached file and keeps each run reproducible.
49+
50+
### 4) Expand partitions and mount the image
51+
52+
- `installation/devices_and_distros/build.bash` expands the image file size using `truncate`.
53+
- `setup_image.bash` does the low-level disk work:
54+
- attaches the image to a loop device
55+
- repairs/rescans the partition table (handles “expanded image” correctly)
56+
- resizes partition 2 to fill the available space
57+
- runs `e2fsck` and `resize2fs`
58+
- mounts root and boot partitions under `/mnt/raspios`
59+
- bind-mounts `/dev`, `/proc`, `/sys`, and the repo workspace into the chroot
60+
- copies `qemu-aarch64-static` into the image so `chroot` can run ARM64 binaries
61+
62+
This step is separated because it is “image plumbing” and is the same no matter which device or software stack you install.
63+
64+
### 5) Chroot into the image and install everything
65+
66+
Once mounted, `setup_image.bash` runs a device script inside the image:
67+
68+
- The device script (example: `installation/devices_and_distros/pi5.bash`) runs:
69+
- `installation/modules/main_startup.bash` to install the software stacks
70+
- device-specific patches (example: install a udev rules file)
71+
72+
Inside `installation/modules/main_startup.bash` the work is split into modules:
73+
74+
- `installation_common.bash`
75+
- installs OS packages and tools (git, python, build tools, OpenCV, etc.)
76+
- enables services like SSH and Avahi
77+
- installs Rust (via rustup) and ensures `python` points to `python3`
78+
- prepares `/opt/blitz`
79+
- `installation_blitz.bash`
80+
- clones `B.L.I.T.Z` into `/opt/blitz/B.L.I.T.Z`
81+
- checks out a specific branch (`merge-backend` in the current script)
82+
- runs the project installer with a default name
83+
- `installation_autobahn.bash`
84+
- clones Autobahn into `/opt/blitz/autobahn`
85+
- runs its installer script
86+
87+
Why the modules folder exists:
88+
89+
- **Common setup** is shared across devices.
90+
- **Per-project installs** are separate so you can add/remove components cleanly.
91+
- **Per-device scripts** stay small and focus on hardware/OS tweaks.
92+
93+
### 6) Apply device-specific system patches
94+
95+
For Pi 5, `installation/devices_and_distros/pi5.bash` installs:
96+
97+
- `installation/system-patch/90-usb-port-names.rules` into `/etc/udev/rules.d/`
98+
99+
This creates stable symlinks like `usb_cam1`, `usb_cam2`, etc., based on physical USB port topology.
100+
101+
Keeping this in `installation/system-patch/` makes it obvious that this is “OS configuration”, not “application code”.
102+
103+
### 7) Export (and optionally compress) the final image
104+
105+
- `export_image_and_compress.bash`:
106+
- unmounts everything mounted by `setup_image.bash`
107+
- detaches `kpartx` mappings and loop devices
108+
- copies the final `.img` into `/host/outputs/` (mapped to repo `outputs/`)
109+
- optionally compresses it using `xz`
110+
111+
This is separated so cleanup and export logic is consistent and easy to debug.
112+
113+
## First boot naming behavior (hostname)
114+
115+
The system is intended to ship with a placeholder name first, then ask for a real name on first boot.
116+
117+
- `installation/system-patch/blitzprojstartup.bash` checks this file:
118+
- `/opt/blitz/B.L.I.T.Z/system_data/name.txt`
119+
- If it is missing, it creates it with the default placeholder name.
120+
- If it still equals the placeholder, it prompts on the console for a new name and then:
121+
- writes it to `name.txt`
122+
- sets the system hostname (`hostnamectl`)
123+
- ensures `/etc/hosts` has `127.0.1.1 <name>`
124+
- restarts Avahi and SSH
125+
- reboots
126+
127+
`post_install.bash` is a helper script to place `installation/system-patch/blitzprojstartup.bash` into `/usr/local/bin/` and make it runnable.
128+
129+
## Why the file structure looks like this
130+
131+
This repo is split into a few “layers” on purpose:
132+
133+
- **Top-level Docker + entry scripts**
134+
- `Dockerfile`, `compose.yml`, `Makefile`
135+
- These define how to run the build in a controlled environment.
136+
- **Image plumbing**
137+
- `setup_image.bash`, `export_image_and_compress.bash`
138+
- These deal with loop devices, partitions, mounts, and cleanup.
139+
- **Installation logic inside the image**
140+
- `installation/modules/`
141+
- These are the steps that run _inside_ the chroot and install software.
142+
- **Per-device logic**
143+
- `installation/devices_and_distros/`
144+
- One small script per target device, plus a `devices.conf` that defines which OS image to use.
145+
- **System patches**
146+
- `installation/system-patch/`
147+
- Files that should be copied into the image as-is (udev rules, etc.).
148+
- **Docs**
149+
- `docs/` holds usage and “how it works” explanations.
150+
151+
This separation keeps changes safe:
152+
153+
- If you change device details, you usually only touch a device script or patch file.
154+
- If you change what software gets installed, you usually only touch `installation/modules/`.
155+
- If you change how images are mounted/exported, you usually only touch the image plumbing scripts.
156+
157+
## How to customize (common changes)
158+
159+
### Change the base OS image (or update versions)
160+
161+
Edit `installation/devices_and_distros/devices.conf`:
162+
163+
- Update `PI5_IMAGE_URL` to a newer Raspberry Pi OS image.
164+
- Update `PI5_IMAGE_FILE` to match the downloaded filename.
165+
166+
### Change how much extra space is added
167+
168+
Edit `installation/devices_and_distros/build.bash`:
169+
170+
- `EXPAND_IMAGE_SIZE` controls how much space is appended to the image file before resizing partitions.
171+
172+
### Add a new device target
173+
174+
1. Add a new `*.bash` script in `installation/devices_and_distros/` (copy `pi5.bash` as a starting point).
175+
2. Add `YOURDEVICE_IMAGE_FILE` and `YOURDEVICE_IMAGE_URL` to `devices.conf`.
176+
3. Build it with:
177+
- `make build-for ARGS=yourdevice`
178+
179+
### Change what gets installed inside the image
180+
181+
Edit modules in `installation/modules/`:
182+
183+
- Add packages in `installation_common.bash`
184+
- Change the B.L.I.T.Z branch or name defaults in `installation_blitz.bash`
185+
- Change Autobahn install behavior in `installation_autobahn.bash`
186+
187+
### Change USB port naming rules
188+
189+
Edit `installation/system-patch/90-usb-port-names.rules`.
190+
191+
If you are targeting different hardware, keep the patch file but adjust the `KERNELS==` matches and symlink names.
192+
193+
### Change first-boot name behavior
194+
195+
Edit `installation/system-patch/blitzprojstartup.bash`:
196+
197+
- Change the placeholder default name (currently `blitz-pi-random-name-1234`)
198+
- Change allowed characters (currently letters, numbers, `_`, `-`)
199+
- Change what services restart on rename
200+
201+
If you do not want an interactive prompt, you can pre-create:
202+
203+
- `/opt/blitz/B.L.I.T.Z/system_data/name.txt`
204+
with the final name inside the image during the build.
205+
206+
## Where to start reading code
207+
208+
If you want to understand the build end-to-end, read in this order:
209+
210+
1. `installation/devices_and_distros/build.bash`
211+
2. `installation/util/install_distro.bash`
212+
3. `setup_image.bash`
213+
4. `installation/devices_and_distros/pi5.bash`
214+
5. `installation/modules/main_startup.bash` and the module scripts it calls
215+
6. `export_image_and_compress.bash`
216+
7. `installation/system-patch/blitzprojstartup.bash`

docs/Usage.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Basic Usage of This Project
2+
3+
## Dependencies
4+
5+
- Docker Engine (https://www.docker.com/get-started/)
6+
- Make (`brew install make` on macOS)
7+
8+
## Quick Start
9+
10+
```bash
11+
make build-all
12+
# Builds for all devices defined (right now only pi5)
13+
```
14+
15+
## Build for a specific device
16+
17+
```bash
18+
make build-for ARGS=pi5
19+
# Builds for the specific device defined (right now only pi5)
20+
```
21+
22+
## Outputs
23+
24+
The outputs are located in the `outputs/` directory. Usually, the output is a .img file for faster copying.
25+
26+
In order to compress the output, you can use the following command:
27+
28+
```bash
29+
xz -T 0 -v outputs/image_name.img
30+
```
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ DO_COMPRESSION=${3:-true}
77

88
MOUNT_POINT="/mnt/raspios"
99

10-
echo "Unmounting everything that setup_image.sh mounted..."
10+
echo "Unmounting everything that setup_image.bash mounted..."
1111

1212
LOOP_DEV=$(losetup -j "$INPUT_IMAGE" | cut -d: -f1)
1313
if [ -z "$LOOP_DEV" ]; then

installation/devices_and_distros/build.bash

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ function build() {
3939

4040
# Run the per-device script inside the chroot. Path must be valid inside the container/chroot.
4141
local SCRIPT_IN_CHROOT="./installation/devices_and_distros/$SCRIPT_NAME"
42-
bash ./setup_image.sh "$UNZIPPED_IMAGE_PATH" "$SCRIPT_IN_CHROOT"
42+
bash ./setup_image.bash "$UNZIPPED_IMAGE_PATH" "$SCRIPT_IN_CHROOT"
4343

44-
bash ./export_image_and_compress.sh "$UNZIPPED_IMAGE_PATH" "${SCRIPT_NAME%.*}_flash_image" "$COMPRESS_OUTPUT"
44+
bash ./export_image_and_compress.bash "$UNZIPPED_IMAGE_PATH" "${SCRIPT_NAME%.*}_flash_image" "$COMPRESS_OUTPUT"
4545
}
4646

4747
if [ "$BUILD_ALL" = true ]; then

0 commit comments

Comments
 (0)