In this part we take the exported parameters from Part 2 (model_params.hpp
) and wire them into the Raspberry Pi Pico firmware. The firmware continuously samples the onboard temperature sensor, computes the slope, applies the logistic regression, and maintains a hysteresis+hold FSM.
1) Firmware Components
-
model_params.hpp
— constants exported from Python training. -
slope_buf.hpp
— efficient rolling OLS slope buffer (keeps running sums). -
utils_rt.hpp
— fast runtime helpers (fast_sigmoid
, oversampling ADC read). -
main_infer.cpp
— main loop that ties it all together.
2) Firmware Initialization & Loop
Before running the real-time inference, the firmware must initialize both the serial interface and the onboard temperature sensor. This ensures that logs are reliably captured and sensor data is correctly read.
Initialization Phase
stdio_init_all(); // Initialize stdio (USB + UART)
while(!stdio_usb_connected()) { sleep_ms(100); } // Wait until USB serial is connected
setvbuf(stdout,nullptr,_IONBF,0); // Disable buffering for immediate printf output
printf("# BOOT OK (inference)\n");
printf("uptime_ms,temp_c,slope,prob,state\n"); // Print CSV header
adc_init(); // Initialize ADC subsystem
adc_set_temp_sensor_enabled(true); // Enable internal temperature sensor
adc_select_input(4); // Select ADC channel 4 (connected to sensor)
What’s happening here?
-
USB Setup:
stdio_init_all()
prepares the Pico for serial communication. The waiting loop ensures that the host PC is connected before data is sent, preventing lost logs. -
Unbuffered Output:
setvbuf(..., _IONBF, 0)
disables buffering so everyprintf
is pushed instantly to the serial console. -
Boot Message: The firmware prints a boot marker and a CSV header so that logs can be redirected directly into a
.csv
file. - ADC Setup: The onboard temperature sensor is internally wired to ADC channel 4. Initializing the ADC and selecting this channel prepares the Pico to measure raw temperature values.
Main Inference Loop
After initialization, the firmware enters the continuous loop where it samples temperature, computes the slope, applies the logistic regression model, and updates the hysteresis FSM.
SlopeBuf buf(WIN_S);
bool alarm=false; int hold=0;
while(true){
float T = read_temp_oversampled(128, 1500);
uint32_t ms = to_ms_since_boot(get_absolute_time());
float ts = ms * 1e-3f;
buf.push(ts, T);
float m = buf.slope();
float z = (m - MU) / (SIGMA > 1e-9f ? SIGMA : 1.f);
float prob = fast_sigmoid(A_COEF*z + B_INT);
if (!alarm && prob >= P_ON) {
if (++hold >= HOLD_S) { alarm = true; hold = 0; }
} else if (alarm && prob <= P_OFF) {
if (++hold >= HOLD_S) { alarm = false; hold = 0; }
} else {
hold = 0;
}
printf("%u,%.3f,%.5f,%.2f,%s\n", ms, T, m, prob, alarm?"ALARM":"OK");
sleep_ms(1000);
}
3) CSV Output for Debugging
The firmware prints a CSV stream via USB serial:
uptime_ms,temp_c,slope,prob,state
5702,24.330,0.00011,0.35,OK
6702,23.861,0.00042,0.78,ALARM
...
4) Visualizing Results
On your desktop, you can capture logs with:
screen /dev/ttyACM0 115200 > pico_run.csv
Then plot in Python:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("pico_run.csv")
plt.plot(df["uptime_ms"]*1e-3, df["prob"], label="prob")
plt.fill_between(df["uptime_ms"]*1e-3, 0, 1, where=df["state"]=="ALARM", alpha=0.2)
plt.show()
5) What to Tune Next
-
Window length (
WIN_S
): shorter = faster but noisier, longer = smoother but slower. -
Thresholds (
P_ON/P_OFF
): widen gap if oscillations occur. -
Hold counter (
HOLD_S
): require longer confirmation to reduce false toggles. - Sampling rate: 1 Hz is fine for thermal.
- Features: ratio of short vs long slope, or curvature, for earlier detection.
Conclusion
With this third and final part, the pipeline is complete:
- Data Collection (Part 1) — Logging temperature and labeling load/idle.
- Training & Export (Part 2) — Computing slope features, fitting Logistic Regression, exporting parameters.
- Firmware Integration (Part 3) — Real-time inference on the Pico with slope buffer, logistic regression, and hysteresis.
This demonstrates a full end-to-end edge AI workflow: from raw sensor data to a fully deployed lightweight model on embedded hardware.
🔗 Explore More
- 📂 Source code available on GitHub Repository
- 💼 Connect with me on LinkedIn
Top comments (0)