DEV Community

Ertugrul
Ertugrul

Posted on

Part 3 — Real-Time Inference on Pico (Firmware Integration)

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)
Enter fullscreen mode Exit fullscreen mode

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 every printf 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);
}
Enter fullscreen mode Exit fullscreen mode

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
...
Enter fullscreen mode Exit fullscreen mode

Putty output:
putty


4) Visualizing Results

On your desktop, you can capture logs with:

screen /dev/ttyACM0 115200 > pico_run.csv
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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:

  1. Data Collection (Part 1) — Logging temperature and labeling load/idle.
  2. Training & Export (Part 2) — Computing slope features, fitting Logistic Regression, exporting parameters.
  3. 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

Top comments (0)