This repository contains the IMU firmware for Polaris.
This project's toolchain is based on PlatformIO, configured for the RP2040.
A dev shell is provided in flake.nix. If you use
direnv, it will load automatically when you enter the
directory. Otherwise:
nix developInstall Nix using the Determinate installer:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
mkdir -p ~/.config/nix/
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.confThen install direnv through Nix (the apt package is too old to support use flake):
nix profile add nixpkgs#direnv
echo '# Direnv shell hook'
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
exec bash
direnv allowInstall Nix using the Determinate installer:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
mkdir -p ~/.config/nix/
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.confThen install direnv through Nix:
nix profile add nixpkgs#direnv
echo '# Direnv shell hook'
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
exec zsh
direnv allowThe recommended path is WSL2 with Ubuntu 24.04. Install WSL2 from PowerShell:
wsl --install -d Ubuntu-24.04Once in WSL, follow the Linux instructions above.
For flashing, the RP2040 needs to be forwarded from Windows into WSL using usbipd-win:
usbipd list # find the RP2040 bus ID
usbipd bind --busid <id>
usbipd attach --wsl --busid <id>Skip this section if you've already configured git and your GitHub credentials.
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git config --global core.autocrlf false # Very important you don't miss this on WSL!Linux:
sudo apt update && sudo apt install ghmacOS:
brew install ghThen authenticate:
gh auth loginmake test # host Unity tests
make build # build firmware
make upload # flash the RP2040
make format # clang-format all sources in-placeRun make with no arguments to list all targets.
A Python harness at sim/ runs the C++ EKF offline for visualization and
tuning; the same filter that ships on the RP2040 runs in the sim, so tuning
values transfer faithfully.
make tui drops into an arrow-key picker; choose a view, then a scenario.
Timeseries: truth, measurements, EKF estimate, and open-loop gyro integration per channel, residuals with a +/-1 sigma band below:
Mounting: the calibration geometry from tuning.toml:
Simulate: animated 3D boat (truth, EKF estimate, raw IMU), rendered as a
GIF. A static pose filmstrip is available via --view pose:
make tui # interactive picker
make tui SCENARIO=wave_tack VIEW=timeseries # skip the picker
make sim-test # pytest suite
make sim-format # ruff format + checkNoise, EKF, and calibration flags are available on the direct CLI; see
cd sim && uv run python -m plrs_sim sim --help.
Pre-push hooks are tracked in hooks/ and mirror the CI checks (clang-format
- native tests). If you use direnv, they are installed automatically when you enter the directory. Without direnv, install them once manually:
ln -sf ../../hooks/pre-push .git/hooks/pre-pushSee CONTRIBUTING.md.
The goal is heading accuracy of ≤2° on Polaris by fusing IMU and GNSS measurements through a Kalman filter (likely an Extended Kalman Filter given time constraints).
TinyEKF: Lightweight C/C++ Extended Kalman Filter.
Filter tuning lives in tuning.toml, shared by the firmware and the sim. See docs/tuning.md for theory, datasheet-derived starting values, and the record-and-replay workflow.
MCU: Raspberry Pi RP2040
MEMS IMU (accelerometer, gyroscope, magnetometer): Xsens MTi-3-5A-T
GNSS kit (dual antenna): Septentrio mosaic-go H
| Milestone | Issues |
|---|---|
| Python Logger | Serial capture script, log format, replay utility |
| Python EKF Sim | pybind11 bindings, synthetic data generator, sim runner, plotter |
| HIL Testing | On-device test suite, PIO Remote agent, CI integration |


