How to Run an Edge Impulse ML Model on Arduino UNO Q

Deploying an Edge Impulse machine learning model onto the Arduino UNO Q

TinyML used to mean fighting the linker to shave 12 KB off a model so it’d fit on a Cortex-M4 with 256 KB of RAM. You’d run the Edge Impulse CLI on your laptop, tether the board over USB, and pray your sample window matched your inference window. The Arduino UNO Q retires that dance. There’s a Linux SoC on the board itself, sitting next to the MCU, hosting the Edge Impulse daemon while the MCU handles deterministic inference.

In this tutorial you’ll train a 4-gesture classifier (idle, wave, punch, circle) using the onboard IMU and deploy it to the UNO Q’s MCU side. Working demo in about an hour. We’re targeting the edge impulse arduino uno q workflow specifically, which is different enough from the Nano 33 BLE Sense flow that copy-pasting old tutorials will just frustrate you.

Quick caveat: the UNO Q is new hardware as of late 2025. Command names, package versions, and deployment targets are moving. Where I give a specific command, double-check it against the current Edge Impulse and Arduino docs. I’ll flag the spots most likely to drift.

Why the UNO Q Changes the TinyML Workflow

The UNO Q has two brains. There’s a Qualcomm Dragonwing QRB2210 (quad-core Cortex-A53, runs Linux) and an STM32U585 (Cortex-M33, runs your firmware). They share the board and talk over an internal IPC channel.

┌─────────────────── Arduino UNO Q ───────────────────┐
│                                                      │
│   ┌──────────────────┐      ┌──────────────────┐    │
│   │ Qualcomm         │◄────►│ STM32U585        │    │
│   │ Dragonwing       │ IPC  │ Cortex-M33       │    │
│   │ (Linux)          │      │ (Real-time MCU)  │    │
│   │                  │      │                  │    │
│   │ • Edge Impulse   │      │ • IMU sampling   │    │
│   │   CLI / daemon   │      │ • run_classifier │    │
│   │ • Wi-Fi / BLE    │      │ • GPIO / Serial  │    │
│   └──────────────────┘      └──────────────────┘    │
└──────────────────────────────────────────────────────┘

The Linux side is your developer workstation, on the board. The MCU side is your product. For TinyML that split is unusually good news, because data collection and model deployment are exactly the workflow steps that used to require a tethered laptop.

Here’s how the new edge impulse qualcomm workflow compares to what you’re probably used to:

┌──────────────────┬─────────────────────┬──────────────────────┐
│ Feature          │ Nano 33 BLE Sense   │ Arduino UNO Q        │
├──────────────────┼─────────────────────┼──────────────────────┤
│ MCU              │ nRF52840 (M4)       │ STM32U585 (M33)      │
│ MCU RAM          │ 256 KB              │ ~786 KB              │
│ Linux SoC        │ —                   │ Qualcomm Dragonwing  │
│ On-device tools  │ No                  │ Yes (Linux side)     │
│ Wi-Fi / BT       │ BLE only            │ Wi-Fi + BLE          │
└──────────────────┴─────────────────────┴──────────────────────┘

About 3x the MCU RAM gets you bigger models, longer sample windows, and headroom for preprocessing. The real shift is the Linux side: SSH in, retrain, redeploy, and the board never leaves whatever it’s mounted to.

What You’ll Need

  • An Arduino UNO Q
  • USB-C cable
  • A free Edge Impulse account
  • Arduino IDE 2.x (or the Arduino CLI)
  • Roughly 30 minutes of data-collection patience

Step 1: Set Up the UNO Q and Edge Impulse CLI

Boot the board with its default Linux image. Either plug in a keyboard and monitor or grab the IP and SSH in. Once you have a shell on the Dragonwing side, install the Edge Impulse Linux CLI:

sudo apt update
sudo apt install -y nodejs npm
sudo npm install -g edge-impulse-linux

Then pair the board to your Edge Impulse project:

edge-impulse-daemon

It’ll prompt for your Edge Impulse credentials and ask which project to attach to. Pick “Create new project,” call it uno-q-gestures, and you’re done. The board will now show up in Edge Impulse Studio as a connected device, with the IMU listed as a sensor.

(Heads up: the exact package name for the Linux runner on the UNO Q’s Arduino OS may differ. If edge-impulse-linux doesn’t work out of the box, check Edge Impulse’s UNO Q-specific docs for the current install path.)

That’s the dual-core payoff. No separate gateway PC. The daemon runs on the same board the model will eventually run on.

Step 2: Collect IMU Gesture Data

In Edge Impulse Studio, head to Data acquisition. Set the sensor to “Inertial” and the sample length to 2000 ms. Frequency around 62.5 Hz works well for hand gestures.

Record about 3 minutes per gesture: idle, wave, punch, circle. That gives you roughly 90 samples per class, enough for clean separation on simple gestures.

Sample: wave_07.cbor    Duration: 2000ms    Frequency: 62.5Hz
┌────────────────────────────────────────────┐
│  accX  ╱╲    ╱╲    ╱╲                      │
│  accY ╱  ╲__╱  ╲__╱  ╲                     │
│  accZ ──────────────────                   │
└────────────────────────────────────────────┘

Three tips that matter more than people admit:

  1. Vary the speed and amplitude across samples. Robotically consistent data trains a brittle model.
  2. Hold the board in the same orientation you’ll use at inference time. The accelerometer doesn’t know “up” from “your wrist.”
  3. Collect idle while genuinely sitting still, walking, and gesturing-but-not-doing-a-gesture. The negative class is where most hobby models fail.

After collection, click Perform train/test split to get a clean 80/20 split.

Step 3: Design and Train the Impulse

Go to Impulse design. Set the window size to 2000 ms with a 200 ms increase. Add two blocks:

  • Processing: Spectral Analysis (well-suited to repetitive motion)
  • Learning: Classification (Keras)

Save the impulse, then click into Spectral features and hit Generate features. Look at the feature explorer. If the 4 gesture clusters are visually separable, your model will train fine. If they overlap into one blob, your data collection was inconsistent. Go back and recollect the messy class.

Then over to Classifier. Default settings are reasonable: 100 epochs, learning rate 0.0005, a small dense network. Hit Start training. You’re looking for >90% validation accuracy. Hand gestures with a clean dataset usually land at 95%+.

What the model is actually doing: the Spectral Analysis block converts each 2-second window of accelerometer data into a fixed set of frequency-domain features. The neural net then learns which combinations of frequencies map to which gesture. No raw time-series tricks, no LSTMs, no drama.

Step 4: Deploy to the MCU Side

You have two deployment paths, and they’re genuinely different products:

Path A (the hero): Arduino library on the MCU. Inference runs on the STM32U585. Sub-10ms latency, deterministic timing, works whether or not Linux is happy. This is what you ship.

Path B (the escape hatch): edge-impulse-linux-runner on the Dragonwing side. Slower, non-deterministic, but zero recompile. Useful for trying changes in 5 seconds instead of 5 minutes.

We’re going with Path A. In Edge Impulse Studio, open Deployment, pick Arduino library, and click Build. You’ll get a .zip file. In the Arduino IDE, choose Sketch → Include Library → Add .ZIP Library, and point it at the download.

Now a minimal sketch. This reads the IMU, fills a feature buffer, runs the classifier, and prints the result:

#include <uno-q-gestures_inferencing.h>
#include <Arduino_LSM6DSOX.h>  // verify the actual IMU library for UNO Q

#define FRAME_LEN  EI_CLASSIFIER_RAW_SAMPLE_COUNT
#define FRAME_INTERVAL_MS  (1000 / 62)

static float features[FRAME_LEN * 3];

int raw_feature_get_data(size_t offset, size_t length, float *out_ptr) {
    memcpy(out_ptr, features + offset, length * sizeof(float));
    return 0;
}

void setup() {
    Serial.begin(115200);
    IMU.begin();
}

void loop() {
    for (int i = 0; i < FRAME_LEN; i++) {
        float x, y, z;
        while (!IMU.accelerationAvailable());
        IMU.readAcceleration(x, y, z);
        features[i * 3 + 0] = x;
        features[i * 3 + 1] = y;
        features[i * 3 + 2] = z;
        delay(FRAME_INTERVAL_MS);
    }

    signal_t signal;
    signal.total_length = FRAME_LEN * 3;
    signal.get_data = &raw_feature_get_data;

    ei_impulse_result_t result = { 0 };
    run_classifier(&signal, &result, false);

    for (size_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {
        Serial.print(result.classification[i].label);
        Serial.print(": ");
        Serial.println(result.classification[i].value, 2);
    }
}

Flash it to the MCU side from the Arduino IDE. (The IMU driver name and accelerometer library for the UNO Q may differ from the LSM6DSOX I’ve shown here. Check the board’s reference before compiling.)

Step 5: Test and Iterate

Open the Serial Monitor at 115200 baud. Perform each gesture and watch:

idle:    0.02
wave:    0.94  ◄── predicted
punch:   0.03
circle:  0.01

If confidence is mushy (top class hovering around 0.5), three usual suspects:

  1. Orientation drift between collection and inference. Hold the board the same way.
  2. Not enough negative-class data. Add more idle recorded during real-world motion.
  3. Sample window mismatch. Your sketch’s frame length must match the model’s training window.

When you want to retrain, you don’t need to plug into a laptop. SSH back into the Dragonwing side, fire up edge-impulse-daemon again, collect new samples, retrain in Studio, rebuild the library, and reflash. The board never leaves the shelf.

Extending the Hybrid Pattern

The same workflow handles voice keyword spotting (add a mic), motor anomaly detection (sample current or vibration), and camera-based classification when you plug a USB webcam into the Linux side.

The hybrid pattern is the interesting one. Linux does the heavy preprocessing (image resize, or FFT on a big buffer). Then it ships a compact feature vector to the MCU for the actual classifier. You get desktop-class I/O on the front end and microcontroller-class determinism on the back end, on one board.

FAQ

Can the Arduino UNO Q run TensorFlow Lite directly? Yes. You can run TensorFlow Lite for Microcontrollers on the STM32U585 and full TensorFlow Lite (or LiteRT) on the Linux side. Edge Impulse generates TFLM-compatible code under the hood, so when you deploy via the Arduino library you’re already running TFLM.

How is the UNO Q different from the Nano 33 BLE Sense for ML? Three things: roughly 3x more MCU RAM (bigger models), an onboard Linux SoC (no tethered laptop for data collection or retraining), and Wi-Fi alongside BLE. The Nano 33 BLE Sense is still fine for ultra-low-power gesture work. The UNO Q is the better choice when you need on-device tooling, larger models, or richer connectivity.

Do I need to know Python to use Edge Impulse? No. The full data collection, training, and deployment flow runs through the Studio web UI and the CLI. The generated Arduino library is C++ you #include and call. Python only comes up if you want to write custom processing blocks.


Hubble Network enables wireless data ingestion from UNO Q deployments at scale, without provisioning gateways or managing cellular connectivity. See how it works →