Trikke Motion Telemetry Logger

Prototype v0 firmware for a Seeed Studio XIAO ESP32-C3 with an ADXL345 accelerometer and L3G4200D gyroscope on a shared I2C bus.

This milestone does four things:

  1. Detects and verifies both sensors by their identification registers.
  2. Configures each sensor for a nominal 100 Hz raw output rate.
  3. Emits timestamped, sensor-native raw readings over the XIAO USB connection.
  4. Maps both sensors into a shared enclosure coordinate frame for validation.

BLE transport and phone-side storage come after the wired sensor path is proven.

Wiring

Signal XIAO pin ESP32-C3 GPIO
SDA D4 GPIO6
SCL D5 GPIO7
Sensor power 3V3
Sensor ground GND

Both breakouts share SDA, SCL, 3V3, and GND. The firmware checks both possible 7-bit I2C addresses for each device:

  • ADXL345: 0x53 or 0x1D; expected DEVID is 0xE5.
  • L3G4200D: 0x69 or 0x68; expected WHO_AM_I is 0xD3.

Sensor configuration

  • ADXL345: nominal 100 Hz output rate, full-resolution mode, +/-8 g. Nominal scale is 3.9 mg/LSB.
  • L3G4200D: nominal 100 Hz output rate, LPF2 selected with a 25 Hz cutoff, +/-500 dps. Nominal scale is 17.5 mdps/LSB.

The enclosure coordinate frame is:

  • +X points right in the reference photograph.
  • +Y points toward the top of the enclosure.
  • +Z points out of the board toward the enclosure cover.

The L3G4200D already matches that frame. The ADXL345 mapping is:

enclosure X =  native Y
enclosure Y = -native X
enclosure Z =  native Z

No software calibration, software filtering, or sensor fusion is performed yet.

The ESP32-C3 polls at exactly 100 Hz, but each sensor has an independent internal sample clock. The status registers are read immediately before each XYZ read so a consumer can distinguish a fresh sample from a repeated poll and identify gyro overruns. Hardware data-ready interrupts and FIFO acquisition are deferred to the buffering milestone.

Build and flash

ESP-IDF 6.0.2 is installed at:

/Users/jay/.espressif/v6.0.2/esp-idf

For each new terminal:

source /Users/jay/.espressif/v6.0.2/esp-idf/export.sh
idf.py build
idf.py -p /dev/cu.usbmodem1134101 flash monitor

Exit the serial monitor with Ctrl-].

USB output

After startup metadata, records use CSV:

sequence,poll_timestamp_us,accel_x_raw,accel_y_raw,accel_z_raw,gyro_x_raw,gyro_y_raw,gyro_z_raw,accel_native_x_raw,accel_native_y_raw,accel_native_z_raw,gyro_native_x_raw,gyro_native_y_raw,gyro_native_z_raw,accel_int_source,gyro_status,loop_overrun_count

poll_timestamp_us is the ESP32-C3 monotonic time immediately before the status and data reads. It is not the sensors' physical sample time. The axes in the first six sample columns use the enclosure frame above. Native columns remain available for diagnostics.

Status bits:

  • accel_int_source & 0x80: an unread ADXL345 sample existed when status was checked. If clear, treat the following sample as stale/untrusted; a sample can arrive in the short interval between the status and data transactions.
  • accel_int_source & 0x01: ADXL345 unread data was overwritten.
  • gyro_status & 0x08: L3G4200D sample is fresh.
  • gyro_status & 0x80: L3G4200D data overran before it was read.
  • loop_overrun_count: cumulative acquisition deadlines missed; the loop resynchronizes after a miss instead of issuing catch-up bursts.

The capture tool auto-detects a single /dev/cu.usbmodem* device, writes only validated numeric records to a real CSV, and reports sequence or timing problems:

python tools/capture_serial.py
S
Description
No description provided
Readme 496 KiB
Languages
C 42.2%
Python 29.5%
Kotlin 27.9%
CMake 0.4%