Progress Log
Pi Software Bootstrap (Build Guide 2 Steps 1-3)
Pi Software Bootstrap (Build Guide 2 Steps 1-3)
Date: 2026-04-11 Type: Build Log
Context
Continuing the same evening that ended with 2026-04-11_2032--rpi-headless-first-boot.md. The Pi was headless, on WiFi, SSH-able, but the OS was bare. Todd wasn't in "wire stuff up" mode and didn't have all the hardware on hand yet, so we focused on the parts of Build Guide 2 that needed zero new hardware: the apt updates, the Python virtual environment, the hardware interfaces, and the project skeleton. Goal: leave the Pi in a "ready for components, just plug things in next session" state.
What Changed
The Pi (tickslayer) is fully software-provisioned per Build Guide 2 Steps 1, 2, 3, and 8. The build guide itself was rewritten to match reality, including several non-obvious gotchas that the original guide got wrong.
What we did, in order
sudo apt update && sudo apt upgrade -y— 92 packages upgraded. ~5 minutes. Notable: this is Debian 13 Trixie, not Bookworm (the Pi OS image ispi-genDec 4 2025 build, kernel6.12.47+rpt-rpi-v8). Initramfs was regenerated.- System packages installed:
python3-pip,python3-venv,i2c-tools,git,rpicam-apps(waslibcamera-apps— now a transitional package on Trixie),gpsd,gpsd-clients, pluspython3-picamera2andlibcap-dev(added after the next failure). - First pip install attempt failed.
pip install picamera2tried to buildpython-prctlfrom source, which requireslibcapdevelopment headers, which weren't installed. Even fixing that gives a worse install than the apt path. Pi OS-blessed approach: install picamera2 from apt, then use a venv with--system-site-packagesso the venv inherits it. - Recreated the venv with
--system-site-packages:
Verified picamera2 visible from inside:rm -rf ~/rover/venv python3 -m venv --system-site-packages ~/rover/venv/usr/lib/python3/dist-packages/picamera2/__init__.py✓ - Pip-installed the libraries that do belong in pip (everything except picamera2):
adafruit-circuitpython-pca9685,adafruit-circuitpython-ads1x15,adafruit-circuitpython-motor,pynmea2,pyserial,requests. Pulls in Adafruit-Blinka 9.0.4 plus a long tail of CircuitPython dependencies (Adafruit-PlatformDetect, Adafruit-PureIO, RPi.GPIO, rpi_ws281x, sysv_ipc, etc). - Verified imports from inside the venv:
All clean.import board, busio import adafruit_pca9685 import adafruit_ads1x15.ads1115 as ADS from adafruit_motor import servo import picamera2 import pynmea2 import serial import requests - Wired venv into
.bashrc:echo 'source ~/rover/venv/bin/activate' >> ~/.bashrc. This works for interactive SSH sessions only — non-interactivessh tickslayer 'cmd'doesn't source.bashrc, so my own scripts have to source the activate explicitly. - Enabled hardware interfaces via
raspi-config nonint:do_i2c 0— I2C ondo_serial_hw 0— UART hardware on (for GPS)do_serial_cons 1— login shell over serial off (so we don't fight with GPS over the wire)- No
do_camera: that function is gone in currentraspi-config. Camera is auto-detected via libcamera at boot, no explicit enable needed. - No
get_serial: also gone, only the setters exist.
- Created project structure:
~/rover/{config,logs,captures,routes}and staged~/rover/config/rover_config.pywith TODO-marked calibration values for steering, throttle, camera, GPS, and battery. - Rebooted the Pi to make the I2C kernel module load and the new initramfs from the apt upgrade take effect. Came back in ~50 sec, auto-rejoined WiFi via the NetworkManager profile from the previous session.
- Verified post-reboot state:
i2cdetect -y 1returns an empty 16x16 grid (all--). That's exactly what we want — bus is alive, no chips wired yet, but ready to talk to the ADS1115 and PCA9685 when they get wired up. Discoveredi2cdetectlives in/usr/sbin/, which is in PATH for interactive shells but not non-interactive.
Files Modified
-
On the Pi (
tickslayer):~/rover/venv/— Python virtualenv with--system-site-packages~/rover/config/rover_config.py— calibration constants, all marked TODO for later guides~/rover/{captures,logs,routes}/— empty data directories~/.bashrc— appendedsource ~/rover/venv/bin/activate/boot/firmware/config.txt—dtparam=i2c_arm=on, UART enabled (via raspi-config)/boot/cmdline.txt—console=serial0removed (viado_serial_cons 1)- All upgraded apt packages from
apt upgrade(initramfs regenerated)
-
In the repo:
docs/articles/build-02-pi-setup.md— Steps 1, 2, and 3 rewritten with reality (rpicam-apps name change, picamera2-via-apt,--system-site-packagesvenv requirement, raspi-config function changes, the non-interactive SSH.bashrcgotcha, thei2cdetectPATH gotcha, and an agent-tip callout for the bootstrap phase)
Key Takeaways
- Raspberry Pi OS Lite is now Debian 13 Trixie, not Bookworm. The guide language should reflect this.
libcamera-appsis a transitional package on Trixie. Real package isrpicam-apps. Use the new name in fresh installs.- NEVER
pip install picamera2. It fails onpython-prctl→libcapheaders, and even when patched gives a worse install. Alwaysapt install python3-picamera2and create the venv with--system-site-packagesso it inherits picamera2 from the system. raspi-configno longer hasdo_cameraorget_serialon current Pi OS. Camera is auto-detected via libcamera. Usedo_serial_hwanddo_serial_consinstead ofget_serial..bashrcvenv activation only works for interactive SSH sessions. Non-interactivessh tickslayer 'cmd'runs in a non-interactive shell that doesn't source.bashrc. For scripts: source the activate explicitly or use~/rover/venv/bin/pythondirectly.i2cdetectlives at/usr/sbin/i2cdetect. In PATH for interactive shells (via/etc/profile), not for non-interactive ones. Usesudo /usr/sbin/i2cdetect -y 1in scripts, or justi2cdetect -y 1interactively.- The user is right not to wire one chip in isolation. Setting up + tearing down a breadboard for a single i2cdetect test isn't worth it. Wait until enough parts are present to do all the I2C wiring at once (ADS1115 + PCA9685 + voltage divider into A0).
- Background tasks for slow apt/pip operations are great. Saved real time tonight by kicking off
apt upgradein the background and checking other state in the meantime. The harness's task notification system makes this clean.
What's still gated on parts
- Build Guide 1 Step 2 — Voltage divider passive test (need voltage sensor)
- Build Guide 1 Step 4 — Camera bench test (need camera + CSI cable)
- Build Guide 1 Step 5 — GPS NMEA test (need GPS module)
- Build Guide 1 Step 6 — PCA9685 I2C detect (need PWM driver)
- Build Guide 1 Step 7 — ADS1115 read through divider (have ADS1115 + multimeter, need voltage divider for the actual read; bare i2cdetect is doable now but low-value alone)
- Build Guide 1 Step 8 — USB battery pack power test (have everything; we deferred only because Todd was tired)
- Build Guide 2 Steps 4–7 — Camera deep test, GPS service setup, I2C verification with both chips, PWM servo sweep
- Build Guide 3+ — Vehicle prep and beyond
Next session
When more parts land, the Pi is ready. Just SSH in and start wiring. The first satisfying milestone will be i2cdetect -y 1 showing both 0x40 (PCA9685) and 0x48 (ADS1115) at the same time — that's Build Guide 2 Step 6 fully passing.
