In my previous video, I introduced the Arduino Uno Q and tested its pre-loaded AI models. Now it’s time to build something practical. In this tutorial, I’ll walk you through creating a working AI-powered person detector that uses a USB webcam to detect people in real-time and displays the results on the Uno Q’s built-in LED matrix.
This project demonstrates what makes the Uno Q genuinely unique: its ability to run actual AI models on a board that fits in the palm of your hand, while seamlessly communicating between the Linux processor and the traditional Arduino microcontroller.
What we’re building
By the end of this tutorial, you’ll have an application that:
- Captures video from a USB webcam connected to the Uno Q
- Runs AI inference to detect whether a person is present
- Displays a “P” on the LED matrix when a person is detected
- Shows a dash pattern when something else is detected
- Provides a web interface to view the live camera feed
The real value here isn’t just the end result—it’s understanding how the Uno Q’s dual-processor architecture works and how Python AI code communicates with Arduino C++ code through the bridge system.
Hardware setup
My setup for this project is straightforward:
- Arduino Uno Q (2GB RAM version)
- Powered USB hub with USB-C power delivery
- USB webcam connected through the hub
- USB power supply (even a basic 5V supply works)
Power flows into the USB hub through its USB-C connector, then the hub delivers power to the Arduino Uno Q. The webcam connects to another port on the same hub. This setup allows the Uno Q to run independently—once powered, it operates on its own with its built-in web server, regardless of whether you’re connected to App Lab.
A quick tour of the Arduino Uno Q hardware
Before diving into the code, let’s identify the key components on the board:
Top Side:
- Qualcomm Dragonwing QRB2210 – The main CPU running Debian Linux
- DRAM chip – 2GB on my board (4GB version available)
- Wi-Fi/Bluetooth module – Provides wireless connectivity
- USB-C controller – Manages the single USB-C port
- 8×13 LED matrix – Each LED has multiple intensity levels for fading effects
- Standard Arduino headers – Compatible with UNO shields, controlled by the MCU
Bottom Side:
- eMMC flash storage – 16GB on the standard model
- STM32U585 microcontroller – The Arduino-style MCU for real-time control
- Additional headers – Provide access to CPU-level pins (MIPI camera, display, audio)
Understanding the dual-brain architecture
The Arduino Uno Q has two processors that need to work together, and understanding this architecture is essential for building applications:
The Linux Side (Qualcomm Dragonwing):
- Runs full Debian Linux
- Handles AI inference through Docker containers
- Executes Python code
- Manages networking and web servers
The MCU Side (STM32U585):
- Traditional Arduino-style chip
- Handles real-time control
- Controls GPIO pins
- Drives the LED matrix
The Bridge: This is Arduino’s communication layer between the two sides. Think of it as a messenger service. On the Arduino side, you register functions that can be called from Python. On the Python side, you use bridge.call() to trigger those functions. This is what makes the Uno Q different from other computer/microcontroller hybrids.
Project structure in Arduino App Lab
One thing I genuinely appreciate about App Lab is that everything lives in one place. A typical project contains:
- Python/main.py – The Python script running AI detection on Linux
- Sketch/sketch.ino – The Arduino C++ code for the MCU
- Assets/ – HTML, JavaScript, and other web interface files
- app.yaml – Configuration file listing bricks and settings
- README.md – Project documentation
When you deploy, everything goes together as a single application.
Understanding bricks
Bricks are a key concept in App Lab that makes AI development remarkably quick—perfect for prototyping. A brick is essentially a pre-packaged module providing specific functionality.
For my person detector, I used two bricks:
1. WebUI HTML Brick – Provides a web browser interface with Socket.IO for real-time communication. This creates the live video feed display.
2. Video Image Classification Brick – Runs a MobileNet model and returns detection results. I selected the “person classification” model from this brick.
When you add a brick to your application, it appears in the app.yaml configuration file automatically. Behind the scenes, most bricks run as Docker containers on the Linux side. When you start an application, App Lab pulls the necessary container images from the internet, starts them up, and then launches your application.
Each brick comes with documentation, usage examples, and API references accessible directly in App Lab. You can click on any brick to see which of your applications use it.
The Python code: where the AI magic happens
Let’s walk through the Python code that handles AI detection. Here’s the structure:
# Import Arduino utilities
from arduino import app, bridge
# Import bricks
from webui_html import WebUI
from video_image_classification import VideoImageClassification
# Standard Python libraries
import datetime
import json
# Initialize bricks
web_ui = WebUI()
detection_stream = VideoImageClassification(
confidence=0.5, # Only report detections with 50%+ confidence
debounce=0.5 # Wait 0.5 seconds between inferences
)
The confidence parameter controls how certain the model must be before reporting a detection. Since this is a pre-trained model, adjusting confidence is your main way to tune accuracy. The debounce parameter prevents flooding—half a second between inferences works well for real-time display.
Next, we handle detection events:
# When a person is detected
def person_detected(result):
bridge.call("show_person")
print(f"Person detected with confidence: {result['confidence']}")
# Register the callback
detection_stream.on_detect("person", person_detected)
# Handle all other detections
def handle_all_detections(results):
bridge.call("clear_display")
for result in results:
if result['label'] != 'person':
bridge.call("show_x") # Show dash pattern
detection_stream.on_detect_all(handle_all_detections)
# Start the application
app.run()
The key insight here is how simple the bridge communication is. When Python detects a person, it calls bridge.call("show_person"), which triggers the corresponding function on the Arduino side. That’s the entire integration—no complex serial protocols or message parsing.
The Arduino code: receiving commands and updating the display
The Arduino side is deliberately simple. Its job is to receive commands and update the LED matrix:
#include "Arduino_LED_Matrix.h"
#include "ArduinoRouterBridge.h"
ArduinoLEDMatrix matrix;
// Bitmap patterns (104 elements = 8x13 matrix)
const uint8_t pattern_P[] = {
// Pattern data for letter "P"
};
const uint8_t pattern_dash[] = {
// Pattern data for dash
};
void setup() {
matrix.begin();
matrix.clear();
// Register functions that Python can call
Bridge.provide("show_person", showPerson);
Bridge.provide("show_x", showX);
Bridge.provide("clear_display", clearDisplay);
}
void loop() {
// Nothing here - we respond to Python callbacks
}
void showPerson() {
matrix.loadFrame(pattern_P);
Serial.println("Showing person pattern");
}
void showX() {
matrix.loadFrame(pattern_dash);
Serial.println("Showing dash pattern");
}
void clearDisplay() {
matrix.clear();
}
Notice that the loop() function is empty. The program doesn’t actively do anything until Python calls one of the registered functions. This event-driven approach is clean and efficient.
One quirk I discovered: Serial output from the Arduino side doesn’t appear in App Lab’s serial monitor when connected via Wi-Fi. You may need a direct USB connection to your computer to see Arduino serial output. Python console output works fine over the network.
What happens when you click “Run”
Understanding the startup sequence helps with debugging:
- App Lab reads app.yaml to understand what bricks are needed
- Arduino sketch compiles and uploads to the STM32 microcontroller
- Linux infrastructure checks run to ensure resources are available
- Python environment provisions
- Docker containers deploy – first your application container, then containers for each brick
- Containers start and health-check
- Callbacks register on the Python side
- Application starts processing
The first time you add a brick to an application, it takes longer because App Lab downloads the Docker container from the internet. Subsequent runs are faster.
Command line access
App Lab provides terminal access to the Uno Q’s Linux system. Click the console button in the bottom left, enter your password, and you have a full Debian shell.
Your applications live in ~/Arduino Apps/, organized by project name. Inside each project folder, you’ll find the same structure visible in App Lab: assets, Python, sketch, and configuration files.
This means you can:
- Use vim or other editors directly on the board
- Copy files via SCP from your development machine
- Use the Arduino CLI to manage applications
For example, to list running applications:
arduino-app-cli list
To stop or start applications by ID:
arduino-app-cli stop [app-id]
arduino-app-cli start [app-id]
The command line is excellent for automation, debugging, or if you prefer VS Code over the web interface.
Honest assessment: The good and the rough edges
After spending considerable time with this project, here’s my candid evaluation:
What Works Well:
- The concept is genuinely powerful. Combining a Linux processor with a traditional microcontroller and making AI accessible through simple Python callbacks and pre-built bricks—that’s compelling.
- Low barrier to entry for AI. I got a working AI application running with relatively little effort. You don’t need a machine learning degree to add person detection to your project.
- Unified development environment. Having Python, Arduino, and web interface code in one project that deploys together is convenient.
The Rough Edges:
- Performance limitations. Remember, this is a resource-constrained board. With 2GB RAM running Docker containers, AI models, a web server, and your application code, things can get slow. The 4GB model should help.
- App Lab is under heavy development. I encountered quirks with file editing, occasional connection drops, and the application crashing. The editor has limitations (can’t resize text, for example).
- Connection issues are common. The board can be finicky about USB hubs—some work, some don’t. Wi-Fi detection versus USB-C connection can show duplicates. Many users report boards not being detected on first setup.
- Platform-specific behavior. My board wouldn’t connect via USB-C on Linux Mint, but worked fine on my MacBook Pro. Wi-Fi connections have been reliable.
- Documentation is catching up. Some aspects of the system aren’t well documented yet.
I’m not alone in these observations. Forum users report similar experiences. One described thinking their boards were bricked for an entire day before getting them to work. Another review called App Lab’s current state “better-ish”; I think that’s fair. If you’re using App Lab version 0.3.x, expect rough edges and be patient.
The abstraction trade-off
Here’s something important I noticed: most of my time went to understanding how the platform works—bricks, the bridge, Docker containers, YAML configuration, file organization. I spent very little time understanding the underlying AI infrastructure: how detection actually works, how confidence scores are calculated, what happens during inference.
This is both good and bad.
Good: It frees your time to imagine and implement applications. The brick handles all the machine learning complexity.
Limiting: You’re working with a black box. If you want to understand why the model sometimes confuses a chair for a person, or how to optimize detection for your specific use case, that knowledge isn’t immediately accessible.
My hope is that once makers get hooked on the potential applications, they’ll become curious about how things actually work. They’ll explore Edge Impulse, learn about model training, understand the inference pipeline. The bricks are a great starting point, but they shouldn’t be the ending point.
Where the Uno Q fits
To be clear, the Uno Q can’t compete with a Raspberry Pi 5 for raw AI performance. That’s not the point. What you get is an all-in-one development platform where Python, Arduino, and AI work together seamlessly.
The brick system means you don’t have to be a machine learning expert to add AI to your projects. There’s ample room for improvement, and if Arduino and Qualcomm continue developing this platform—fixing bugs, improving documentation, maturing App Lab—makers will have a genuinely new hardware category to work with.
One that promises, and I believe can deliver, rapid prototyping for real-world AI-based applications.
What’s next
This person detector is just the beginning. The same architecture could be extended to:
- Count the number of people detected over time
- Trigger actions based on detection (control motors, send notifications)
- Combine multiple AI models for more complex applications
- Add voice control using the audio classification bricks
I’m considering developing a full course on the Arduino Uno Q. If that interests you, let me know in the comments what kind of applications you’d most want to build—object detection for robotics, voice-controlled devices, environmental monitoring with AI, or something else entirely.
Resources
- Arduino Uno Q Official Store
- Arduino Uno Q Documentation
- Edge Impulse – Platform for building custom AI models
- Arduino Uno Q Introduction – My first video covering setup and basic testing
Have you built anything with the Arduino Uno Q? What’s been your experience with App Lab? Share your projects and tips in the comments below.
