Sensor Bring-Up Guide¶
This guide walks through connecting and testing each sensor type incrementally, from one sensor to the full 12-sensor configuration.
Philosophy¶
Don't connect everything at once. Each sensor type has its own test class in
test_sensor_subsets.py. Validate each type in isolation before combining.
A failure in one sensor should not block testing another.
Phase 1: One IMU¶
1a. Software-only test (no hardware)¶
.venv/bin/python -m pytest tests/test_sensor_subsets.py::TestIMUOnly -v
This runs 4 tests with mocked IMU data and verifies the feature extractor produces valid features when only IMU data is present (EMG + FSR zeroed).
1b. Connect one BNO055¶
- Flash the KB2040 with only chest IMU enabled: edit
firmware/kb2040/src/main.cpp, comment outthigh_okand thigh reads. - Flash the STM32 with all IMUs disabled except #0 (L wrist): edit
firmware/stm32f405/src/imu_task.c, comment out IMUs #1–#3. - Both MCUs should show
LED_BUILTINon solid. - Connect the STM32 to PC, run serial monitor at 115200: one IMU should report
ok. - Run
.venv/bin/python -m host.serial_reader: frames with one non-zero IMU block.
1c. Verify feature extraction on live data¶
from host.serial_reader import SerialReader
from host.feature_extraction import FeatureExtractor
extractor = FeatureExtractor()
with SerialReader("/dev/ttyACM0") as reader:
for frame in reader:
feats = extractor.add_frame(frame)
if feats is not None:
# 1 IMU → 50 nonzero features, rest zero
nonzero = (feats != 0).sum()
print(f"nonzero features: {nonzero} (expected ~50 for 1 IMU)")
break
Phase 2: Multiple IMUs¶
- Re-enable the second IMU on each MCU (thigh on KB2040, R wrist on STM32).
- Re-flash both MCUs.
- Run
pytest tests/test_sensor_subsets.py -k IMUOnly— tests 2 IMUs. - Live test: nonzero features should be ~100.
- Enable remaining IMUs (#2 L arm, #3 R arm on STM32).
- Verify 6 IMUs → ~300 nonzero features.
Phase 3: EMG¶
- Connect the MyoWare forearm sensor to STM32 A0.
- Verify ADC reading: serial monitor should show non-zero EMG values when the muscle is flexed.
- Run
pytest tests/test_sensor_subsets.py -k EMGOnly— 3 tests pass. - Connect the back sensor to A1, verify both channels.
Phase 4: FSR¶
- Connect one FSR with 10 kΩ voltage divider to A2.
- Press the FSR — serial monitor shows increasing value.
- Run
pytest tests/test_sensor_subsets.py -k FSROnly— 3 tests pass. - Connect remaining 3 FSRs to A3–A5, verify all 4 channels.
Phase 5: Two sensor types¶
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k TwoTypes -v
Tests: IMU+EMG, IMU+FSR, EMG+FSR. Each verifies that the feature extractor correctly handles mixed sensor types where one type is zeroed.
Phase 6: All sensors¶
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k AllSensors
With all 12 sensors connected and streaming:
from host.serial_reader import SerialReader
from host.feature_extraction import FeatureExtractor
from host.live_inference import LiveClassifier
classifier = LiveClassifier("models/worker_har_best.pt")
extractor = FeatureExtractor()
with SerialReader("/dev/ttyACM0") as reader:
for frame in reader:
feats = extractor.add_frame(frame)
if feats is not None:
label, conf = classifier.predict(feats)
print(f"{label} ({conf:.2%})")
The classifier should produce non-trivial predictions. If all labels are
standing with low confidence, check that IMU quaternions are changing
(the BNO055 is in NDOF mode and has calibrated).
Phase 7: Full pipeline¶
- Flash both MCUs (reset to full firmware — all IMUs, EMG, FSR enabled)
- Run unit tests:
pytest tests/ -q→ 127 passed - Start dashboard:
streamlit run host/dashboard.py - Verify stick figure moves, EMG bars respond to muscle flex, FSR to foot pressure
- Dashboard activity gauge updates ~10× per second
Common bring-up issues¶
| Symptom | Phase | Fix |
|---|---|---|
IMU fail on serial log |
1b | Check I²C wiring, pull-ups, ADR pin |
| All features zero | 1c | BNO055 not in NDOF mode? Check fusion mode |
| EMG always 0 | 3 | MyoWare gain too low? Adjust onboard potentiometer |
| FSR saturation (always 1.0) | 4 | Voltage divider resistor too large; use 10 kΩ |
Classifier always standing |
6 | Model not trained on your data; train with your recordings |
| Dashboard FPS < 5 | 7 | Reduce stick-figure samples, close other tabs |