You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| Custom PCB |~95% | KiCad aligned with [docs/wiring.md](docs/wiring.md); **panelization** (fab-ready panel) is the remaining PCB task before ordering. |
| 3D enclosure | 0% | Not started. Plan: **battery-sized** shell first; optional slimmer **wired-only** enclosure if PH2 is omitted on those builds ([roadmap](docs/roadmap.md)). |
|**Firmware**| PlatformIO project for **Seeed XIAO ESP32-C3** + **BNO08x** over **SPI**: fused yaw / pitch / roll from the rotation-vector report. |
60
-
|**OpenTrack**|`xiao_esp32c3_hatire`: **Hatire Arduino** over USB (30-byte frames) **and** optional **WiFi → UDP**to the PC using OpenTrack’s**UDP over network** input (6× `double`, port 4242 by default). **HTTP settings** on port **8080** (`http://azimuth.local:8080`) for Wi‑Fi / UDP / reboot (NVS + `secrets.h` fallback). |
61
-
|**Debug**|Text telemetry over USB serial (`xiao_esp32c3` build). |
60
+
|**OpenTrack**|**`azimuth_main`**: **Hatire Arduino** over USB (30-byte frames) **and** optional **Wi‑Fi → UDP**(OpenTrack **UDP over network**, 6× `double`, port 4242 by default). **HTTP settings** on **8080** (`http://azimuth.local:8080`) — **NVS** (portal); optional compile‑time **`secrets.h`** when NVS is empty. |
61
+
|**Debug**|**`azimuth_debug`**: yaw / pitch / roll over USB serial only (no Wi‑Fi / portal). |
### CI (GitLab) and browser flasher (GitHub Pages)
90
+
91
+
| What | Where |
92
+
|------|--------|
93
+
|**GitLab pipeline**| Pushes to **`main`** run **`.gitlab-ci.yml`**: builds **`azimuth_main`** using **`include/secrets.h.example`** → **`include/secrets.h`** in CI. **Artifacts** → **`ci-artifacts/firmware/`** (`bootloader.bin`, `partitions.bin`, `boot_app0.bin`, `firmware.bin`). |
94
+
|**GitHub Pages USB flasher**| Workflow **`.github/workflows/github-pages-flasher.yml`** runs on **`main`**, builds the same env, runs **`scripts/prepare_web_flasher_firmware.sh`**, and deploys **`web-flasher/`** (portal-styled page using [esp-web-tools](https://github.com/esphome/esp-web-tools)). In the repo: **Settings → Pages → Build and deployment → Source: GitHub Actions**. Users need **Chrome** or **Edge** (Web Serial) and a **USB data** cable. When the installer offers **erase flash**, use it for a **factory-clean** device (clears NVS like on-device “Erase saved settings”). The page links to **`http://azimuth.local:8080/`** for the settings portal after install. |
95
+
96
+
Local check: `pio run -e azimuth_main` then `./scripts/prepare_web_flasher_firmware.sh` copies binaries into **`web-flasher/firmware/`** for testing.
97
+
98
+
Requires [PlatformIO](https://platformio.org/). **Default environment:****`azimuth_main`** (release). Use **`azimuth_debug`** for serial-only bring-up.
90
99
91
100
**Debug (serial monitor, yaw/pitch/roll):**
92
101
93
102
```bash
94
-
python3 -m platformio run -e xiao_esp32c3 -t upload
103
+
python3 -m platformio run -e azimuth_debug -t upload
python3 -m platformio run -e xiao_esp32c3_hatire -t upload
110
+
python3 -m platformio run -e azimuth_main -t upload
102
111
```
103
112
104
-
Copy **`include/secrets.h.example`**to **`include/secrets.h`**and set **`WIFI_SSID`**, **`WIFI_PASSWORD`**, and **`OPENTRACK_UDP_HOST`**(your PC’s LAN IP). `secrets.h` is **gitignored** so credentials are not committed. If there is **no SSID in NVS and `WIFI_SSID` is empty**, or if it **tries to join a saved network and fails** (wrong password, etc.), the board starts an open provisioning network **`Azimuth-Setup`**. It runs a small **captive portal**: DNS sends lookups to the board, HTTP on **port 80**answers OS “sign in to Wi‑Fi” checks with a redirect to **`http://192.168.4.1/`** (same settings UI as on the LAN). **`azimuth.local` does not apply on this network**—mDNS is only advertised after the board joins your home Wi‑Fi. After you save home Wi‑Fi and reboot, **`Azimuth-Setup` turns off** and normal mode uses **`http://azimuth.local:8080`**(or **`http://<LAN-IP>:8080`**). UDP port **`OPENTRACK_UDP_PORT`** is set in **`platformio.ini`** (default **4242**).
113
+
Most users configure Wi‑Fi and OpenTrack **only in the portal** (NVS) and leave **`include/secrets.h`**empty (copy from **`secrets.h.example`**for a valid build; file is **gitignored**). You *may*set **`WIFI_SSID`**, **`WIFI_PASSWORD`**, **`OPENTRACK_UDP_HOST`**there as compile‑time defaults when NVS has no SSID. If there is **no usable home SSID** (NVS + `secrets.h`), or **STA fails** (wrong password, AP missing), the board opens **`Azimuth-Setup`** and a **captive portal**: HTTP **port 80**redirects to **`http://192.168.4.1/`** (same UI as on the LAN). **`azimuth.local` does not apply** on that AP—mDNS starts after joining home Wi‑Fi. Normal use: **`http://azimuth.local:8080`** or **`http://<LAN-IP>:8080`**. UDP port **`OPENTRACK_UDP_PORT`** is in **`platformio.ini`** (default **4242**).
105
114
106
115
-**USB:** Input **Hatire Arduino**, **115200**, **DTR** on; start tracking and **recenter** after the filter settles. Do not leave a text serial monitor open on that port.
107
116
-**Hatire axis mapping (important):** In the Hatire tracker settings, set **Yaw axis = Rot 0**, **Pitch axis = Rot 1**, **Roll axis = Rot 2** (some UIs say “axis 0 / 1 / 2”). That lines up with how this firmware fills the packet and keeps USB and UDP identical. OpenTrack’s *old* Hatire defaults use **0 / 2 / 1**, which swaps pitch and roll—change to **0 / 1 / 2** for the simplest setup.
108
117
-**WiFi / UDP:** Input **UDP over network**, same port as in **`platformio.ini`** (`OPENTRACK_UDP_PORT`); allow the port through the PC firewall. Hatire and UDP both run from the same firmware.
109
118
110
119
### On-device settings (WiFi + OpenTrack)
111
120
112
-
With the **hatire** build:
121
+
With **`azimuth_main`**:
113
122
114
123
-**Already on your LAN:** open **`http://<hostname>.local:8080`** (default hostname **`azimuth`**) or **`http://<device-ip>:8080`**.
115
124
-**Provisioning (`Azimuth-Setup`):** join that network (no password). Many phones **open the settings page automatically**; if not, go to **`http://192.168.4.1/`** on **port 80**. After you save a real SSID (and password if needed), the device **reboots** into **station-only** mode—**`Azimuth-Setup` does not stay on**.
@@ -122,9 +131,9 @@ The portal is grouped into **Wi‑Fi**, **LAN & discovery**, **OpenTrack (PC)**,
122
131
|**LAN & discovery**|**mDNS** on/off, **device hostname** (letters, digits, hyphen; max 24). Changing these → **reboot** so DHCP/mDNS apply. |
123
132
|**OpenTrack (PC)**|**USB Hatire** on/off (Wi‑Fi‑only use), **UDP** on/off, **UDP address** / **port**, **axis mapping** (which fusion yaw/pitch/roll feeds Hatire/UDP **Rot 0–2**, each axis once, optional **invert** per slot). **`something.local` (mDNS)** often **does not** resolve from the ESP32; prefer numeric LAN IP or a DHCP hostname. **This browser’s IP** + **Fill address** when the portal is opened on the PC running OpenTrack. |
124
133
|**Tracking & radio**|**IMU report interval** (5 / 10 / 20 / 40 ms → 200 / 100 / 50 / 25 Hz). Change → **reboot** so the BNO08x report rate is reapplied. **Wi‑Fi TX power** (low / balanced / high) applies on save without reboot. |
125
-
|**Device**| Firmware version string, **Reboot**, **Erase saved settings** (clears NVS `azimuth`namespace and reboots into provisioning if no compile-time Wi‑Fi in `secrets.h`). |
134
+
|**Device**| Firmware version string, **Reboot**, **Erase saved settings** (clears NVS `azimuth` and reboots; provisioning AP if no home SSID in NVS /`secrets.h`). |
126
135
127
-
Values live in **NVS** (`Preferences`namespace **`azimuth`**); empty NVS keys still fall back to **`include/secrets.h`**. Firmware version is set at build time (`AZIMUTH_FW_VERSION` in **`platformio.ini`**for the hatire env).
136
+
**NVS** (`Preferences`**`azimuth`**) is the normal source of truth; unset fields fall back to **`include/secrets.h`** (often empty). **`AZIMUTH_FW_VERSION`** in **`platformio.ini`**applies to **`azimuth_main`** only.
128
137
129
138
The page is served by the stock Arduino **`WebServer`**: when no browser is connected, the firmware only calls **`handleClient()`** once per main loop (no background worker). **Wi‑Fi scan** runs only when you press **Scan networks** and can stall tracking briefly for a second or two.
130
139
@@ -144,7 +153,7 @@ Use **either** **Hatire Arduino** (USB) **or** **UDP over network** as the **Inp
144
153
145
154
| Step | What to do |
146
155
|------|------------|
147
-
|**Input**|**Hatire Arduino** (correct COM port, **115200**, **DTR** on) **or****UDP over network** (OpenTrack listens on **`OPENTRACK_UDP_PORT`** from **`platformio.ini`**, usually **4242**; set **`OPENTRACK_UDP_HOST`**in `secrets.h` to **this PC’s LAN IP**; allow UDP in the firewall). |
156
+
|**Input**|**Hatire Arduino** (COM port, **115200**, **DTR** on) **or****UDP over network** (OpenTrack listens on **`OPENTRACK_UDP_PORT`**, usually **4242**; set UDP target in the **portal**or **`secrets.h`**; allow UDP in the firewall). |
|**Filter**|**Natural motion** filter (name in the filter dropdown may vary slightly by OpenTrack version; pick the **Natural motion** / natural-style preset if available). |
150
159
|**Responsiveness**| Turn **responsiveness** up to **maximum** (slider all the way up) so head motion matches the tracker with minimal lag. |
@@ -180,9 +189,9 @@ So **~4–9 hours** on a **400 mAh** cell is a **reasonable band** until you b
180
189
181
190
-**`src/main.cpp`** — IMU bring-up, rotation vector, Hatire + optional OpenTrack UDP; `kPinCs` / `kPinInt` / `kPinRst` match the **ESP32_BNO086** PCB (see [docs/wiring.md](docs/wiring.md)).
182
191
-**`include/opentrack_pose.h`** — Fusion Euler (deg) → Hatire / OpenTrack UDP **Rot 0–2** with NVS‑configurable **per‑slot axis + invert** (defaults match README **Yaw→0, Roll→1, Pitch→2** with pitch negated).
If you move SPI off the default D8–D10 pins, call `SPI.begin(sck, miso, mosi, -1)`**before**`imu.beginSPI(...)` so the bus matches your board (the SparkFun driver initializes `SPI` internally; ESP32 keeps an already-started bus).
| Coexistence with USB (Hatire + UDP same build) | ✅ |
80
80
| Security baseline (WiFi credentials **not** in git) | 🟨 (`secrets.h` local; NVS on device; migration / hardening in Phase 3) |
81
81
@@ -100,7 +100,7 @@ Use this as a checklist; tighten or relax before tagging V1.
100
100
101
101
| Task | Status |
102
102
|------|--------|
103
-
| Captive portal or small HTTP server on ESP (when in AP or dual mode) | ✅ (provisioning + STA settings on :8080; portal HTML in `src/portal_html.cpp`) |
103
+
| Captive portal or small HTTP server on ESP (when in AP or dual mode) | ✅ (provisioning + STA settings on :8080; `src/portal_html.cpp` in **`azimuth_main`**) |
104
104
|**Or** BLE GATT for lightweight config (often nicer for phones; more firmware work) | ⬜ |
105
105
| Same settings backend as Phase 3 (one model, multiple UIs) | 🟨 (HTTP uses same NVS namespace; BLE not started) |
106
106
@@ -134,3 +134,4 @@ These are common for head trackers; pick what matches your audience.
Copy file name to clipboardExpand all lines: docs/wiring.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -95,7 +95,7 @@ GPIO21 is also **UART TX**; fine for the buzzer if you do not need that UART for
95
95
2.**Clock/checks:****CLKSEL0** pulled high (internal clock selection with `CLKSEL1` left unconnected), and **CAP** has dedicated **100 nF** to GND.
96
96
3.**ENV bus/checks:****ENV_SCL** / **ENV_SDA** have pull-ups (R7/R8) even if no external environmental sensor is populated.
97
97
4.**SCK**, **INT**, and **CS** traces short; solid **GND** return.
98
-
5. After assembly, run firmware **`xiao_esp32c3`** and confirm serial prints before Hatire mode.
98
+
5. After assembly, run **`azimuth_debug`**(`pio run -e azimuth_debug`) and confirm serial prints before switching to **`azimuth_main`** for OpenTrack / Wi‑Fi.
99
99
6. If init fails: check **3.3 V**, **NRST**, **H_INTN**, **SPI** order, then re-run DRC in KiCad.
0 commit comments