Building the "Squirial Sentinel" with Arduino’s New Dual-Brain Power
Every bird lover knows the struggle: you set out a fresh tray of premium sunflower seeds for the local cardinals, only to have a neighborhood squirrel perform an Olympic-level gymnastic routine to devour the entire hoard in minutes. It is an eternal battle of wits. But as a developer, you don't just buy a "squirrel-proof" feeder—you build a better one.
Enter the Squirrel Sentinel. This isn't just a bird feeder; it’s an intelligent guardian designed to distinguish feathered friends from furry intruders using AI at the edge. By leveraging the new Arduino UNO Q and Arduino App Lab, we can transform a simple garden fixture into a sophisticated edge node capable of computer vision and real-time deterrent response.
If your interested in learning more about the Arduino UNO Q and Arduino App Lab , check out my review of the UNO Q Review Arduino's Uno Q (https://www.hackster.io/skruglewicz/review-arduino-s-uno-q-d0d67d#toc-pros-and-cons-18 ), which offers an in-depth architectural and performance evaluation of this hybrid board. The review evaluates the system across two main areas:
- Hardware Performance: It compares how the 2GB and 4GB RAM models perform in real-world scenarios.
- Software and Integration: It explores the software tools used to manage the device (Arduino App Lab and containerized "Bricks") and examines the RPC Bridge, which is the communication layer that allows the two "brains" (the Linux microprocessor and the microcontroller) to work together seamlessly.
The Squirrel Sentinel requires two distinct types of intelligence: a high-level "thinker" to recognize a squirrel, and a low-level "doer" to instantly trigger a deterrent. Historically, this meant tethering a microcontroller to a separate single-board computer, creating a bulky mess of wires and power management headaches.
The Arduino UNO Q solves this with a dual-architecture platform. The "Thinker" is a Qualcomm Dragonwing QRB2210 microprocessor (MPU). This is a powerhouse featuring a quad-core Arm Cortex-A53 running at 2.0 GHz, an Adreno GPU for 3D graphics acceleration, and dual ISPs. This silicon handles the heavy lifting of AI vision, utilizing GPU and ISP acceleration to process image data without breaking a sweat.
The "Doer" is an STMicroelectronics STM32U585 microcontroller (MCU). Built on the Arm Cortex-M33 architecture, it runs Zephyr RTOS, providing the deterministic precision and real-time responsiveness required for hardware interrupts.
This hybridization allows the Sentinel to process high-definition camera data on the Linux side while the MCU stays ready to react to sensors or drive actuators with sub-millisecond reliability.
The traditional challenge of dual-architecture development is the "context switch"—the friction of managing fragmented CLI tools. The Arduino App Lab acts as the unified "glue, " allowing you to manage Python scripts, Arduino sketches, and containerized AI models from a single, streamlined interface. The following table provides a side-by-side comparison highlighting how the Arduino App Lab Experience simplifies development compared to a Traditional Linux Dev Experience.
To give the Sentinel "eyes, " I use Bricks—pre-packaged software building blocks that run as Docker containers on the MPU. For this project, I utilize the “Video Object Detection” example Brick.
This Brick provides a Python interface for detecting objects in real time from a USB camera video stream.It connects to a model runner over WebSocket, continuously analyzes incoming frames, and produces detection events with predicted labels, bounding boxes, and confidence scores. Beyond visualization, it allows you to register callbacks that react to detections, either for specific objects or for all detections, enabling event-driven logic in your applications.
It supports both pre-trained models provided by the framework and custom models trained with Edge Impulse.
Instead of training a model from scratch, you add the Brick through the App Lab UI. It automatically deploys Your model, which is optimized to use the Dragonwing's hardware acceleration. Once the Brick is active, you import it into your Linux-side Python logic with a few lines of code.
This abstraction allows the Squirial Sentinel to receive class labels (like "squirrel") and confidence scores directly, leaving the complex container orchestration to the App Lab.
The User interfaceTo display squirrel detection to the user, I utilized the “WebUI - HTML” example Brick.
This Brick is a simplified, embeddable web server designed for hosting frontend applications and exposing APIs or WebSocket communication channels.
To make it easier, I borrowed the web server code from the “Detect Objects on Camera” example that lets you detect objects on a live feed from a USB camera and visualize bounding boxes around the detections in real-time.
The Server code is located in the “assets” directory of the project. I just copied the entire assets directory and changed a few titles” you can run the example if your interested in seeing how it works.
The most critical feature is the communication between the two brains. When the Python script detects a squirrel, it must command the MCU to sound the alarm. This is handled by the Bridge (RPC) tool.
The Hardware SetupThe physical build of the Squirrel Sentinel mirrors another UNO Q project (Industrial Line Sentinel (ILS) by utilizing the Grove ecosystem for solderless, plug-and-play expansion
The system uses a Grove Base Shield V3 "piggybacked" onto the Arduino UNO Q headers, providing standardized connectors for sensors and actuators
To effectively scare away squirrels without harming them, the system employs multiple humane deterrents
Grove Buzzer (Port D3): Can be programmed to emit high-frequency alarms or hawk sounds
Grove Red LED (Port D2): Serves as a visual beacon to reinforce the audio deterrentGrove RGB LCD (I2C): Displays system status, detection counts, or warning messages.
Grove Button (Port D4): Provides a physical interface for resetting the alarm state after a confirmed event. NOTE: You will need to make sure the Grove - LCD RGB Backlight library (usually called rgb_lcd by Seeed Studio) is included in your App Lab project dependencies.
The input for the vision system is a standard UVC (USB Video Class) camera connected to the UNO Q's high-speed USB-C host port. For outdoor deployments, the OV5647-62 camera module is recommended due to its high-quality image capture and compatibility with the board's MIPI-CSI headers if a carrier board is utilized.
To move beyond pre-trained models, developers use Edge Impulse Studio to create a custom (Edge Impulse Model) tailored for the UNO Q.
The 5-Step Edge Impulse Workflow
Data Acquisition: Collect images using a smartphone, computer, or the UNO Q. A minimum of 160 photos is recommended for accurate training.
- Data Acquisition: Collect images using a smartphone, computer, or the UNO Q. A minimum of 160 photos is recommended for accurate training.
- Labeling: Assign categories (e.g., "squirrel") to images to establish ground truth. Edge Impulse automatically generates a "background" class to teach the model what to ignore.
- Impulse Design: Structure the pipeline by setting the Input block (e.g., 320x320 Image resolution), the Processing block (Image/RGB), and the Learning block (Object Detection).
- Training: The cloud servers process the data to learn the visual patterns.
- Deployment: Export the .eim file, which acts as a container holding the model's logic and parameters, directly into App Lab.
I used the following video and accompanying document to create my model. Instead of apples and bananas, I used pictures of squirrels to train my model.
Video: Custom AI Models for Arduino App Lab
Documentation: Custom AI Models for Arduino App Lab
Investing the time to walk through the documentation and video for custom models is highly rewarding. I explored the guide on how to build and integrate a model within my App Lab project, and the experience was truly exceptional.
The FirmwareTo visualize how information travels through our system. The UNO Q is special because it has a "Dual-Brain": a Qualcomm processor (for AI) and an STM32 microcontroller (for hardware)
[ QUALCOMM MPU ] (Python via App Lab)
├──▶ Checks USB camera
└──▶ Calls Edge Impulse Model to detect a "Squirrel"
│
▼ (Arduino Bridge API triggers alert)
[ STM32 MCU ] (C++ Sketch via App Lab)
├──▶ Receives "ALERT" signal
└──▶ Controls hardware pins
│
▼ (Signals sent through Base Shield)
[ GROVE BASE SHIELD V3 ]
├─ (Port D2) ──▶ [ Grove LED ] (Visual Alert)
├─ (Port D3) ──▶ [ Grove Buzzer ] (Audio Siren)
├─ (Port I2C) ─▶ [ Grove RGB LCD ] (Text Warning)
└─ (Port D4) ──▶ [ Grove Button ] (Reset Input)
Flow Breakdown:
Vision & AI (The First Brain): The Qualcomm MPU runs Python scripts to monitor the USB camera. It passes this visual data to an Edge Impulse AI model looking for a "Squirial".
The Bridge: When a "Squirrel" is detected, the MPU sends an alert down to the MCU using the Arduino Bridge API.
Hardware Control (The Second Brain): The STM32 MCU receives this alert through its C++ sketch and takes over hardware control.
Outputs & Inputs: The MCU routes signals through the Grove Base Shield V3, triggering the LED, Buzzer, and LCD warnings, while monitoring the Button for a reset command.
Putting It all togetherFor my project I used the Example code available in App Lab as a start. Instead of creating a new app in app lab I made a copy of the “”Detect Objects on Camera”
The example app does just what I need for my design.It lets you detect objects on a live feed from a USB camera and visualize bounding boxes around the detections in real-time.
The workflow involves continuously getting the frames from a USB camera, processing it through an AI model using the video_objectdetection Brick, and displaying the bounding boxes around detections. The App is managed from an interactive web interface.
The example uses the following Bricks:
- web_ui: Brick to create a web interface to display the classification results and model controls.
- video_objectdetection: Brick to classify objects within a live video feed from a camera.
Hardware
- Arduino® UNO Q or Arduino VENTUNO Q
- USB camera (x1)
- USB-C® hub adapter with external power (x1) (only for UNO Q)
- A power supply (5 V, 3 A) for the USB hub (e.g. a phone charger) (only for UNO Q)
- Personal computer with internet access
Note: This example must be run in Network Mode in the Arduino App Lab, since it requires a USB-C hub and a USB camera.
This example uses a pre-trained model to detect objects on a live video feed from a camera. But for my use I built a Custom AI Model using Edge Impulse right from App Lab.
I also created 2 pieces of code MCU side in Python and MPU side C++ Sketch. This code is described below and is contained in the code section.
I added a LCD Library (Grove - LCD RGB Backlight 1.0.2) to support the LCD camera for the MCU side
Step by step workflow to modify the Detect Objects on CameraOpen app Lab and connect over the network to your UNO Q
In Examples scroll down to the “”Detect Object on Camera” and click on it
You can not edit just run the apps in examples, so you need to make a copy of the app example you wish to modify.
In the upper right hand part of the screen click on the “Copy and edit app” button.. Name your app and click the “create new” button. This will create an app in the My Apps section. Go now to that section and run it .If it is working you then can proceed to modifying this copy to detect squirrels
Now since there is no Sketch file in the app, you will need to create one. This is a 2 step operation.
In the upper left on the nav bar press the Folder icon
First create a folder and call it sketch, Next create a file called sketch.ino
Next in the sketch folder, create a file called “sketch.yaml”
And Add the following text:
profiles:
default:
fqbn:
platforms:
- platform: arduino:zephyr
default_profile: defaultNOTE: as of this writing, I could create the file , but could not add text to it. Must be a file permission problem
The workaround: was to create a text file on your host machine and name it sketch.yaml. Add the text and save. Then in App LAB select the “import file” option from the folder icon list. And drag and drop the file into the app Lab dialog box.
Now you copy the code from the code attachments section into the perspective file.
The “The MPU Code (Python)” code goes into the main.py. file . Be sure to delete the contents of the example code first.
The “The MCU Code (Sketch)” code goes into the sketch.ino file you just created.
Since we are adding an I2C display, you will need to make sure the Grove - LCD RGB Backlight library (usually called rgb_lcd by Seeed Studio) is included in your App Lab project dependencies.
To do this:
Open the library icon (Top left next to the file folder icon). Search for “Grove - LCD RGB Backlight” use the one by Seeed Studio. Press install.
At this point if you click on the Brick: "Video Object Detection”, it will open the brick info file, go to the “Ai Tab” and notice that the “General purpose object detection - YoloX nano” is selected.you will come back to this tab after you create your model to detect your objects.
For now try and run the app and observe the outcome. What occurred?
Now you will create a custom model by following the the tutorial for detecting bananas but use squirrel images instead
Custom AI Models for Arduino App Lab
Custom AI Models for Arduino App Lab
I suggest you watch the video first and then use the documentation to train your model.
Since you already have an app you can open the brick and go to the “Ai Tab” and scroll to the bottom and skip to the “To start training your custom model, click on Train new AI model. Then, click on Ok, let's start.“ section of the documentation.
When the tutorial is completed. You will see it on the AI Model Tab and you can select it and run.
I’m still fine tuning my squirrel model so I have not included it in the project , but I’m leaving it as an exercise for you to create your own model for now. You could use the banana and the apple model from the tutorial and see how it works on detecting banana?
The MCU (Sketch)The MCU "provides" a service. The code is located in the code attachment section below
Code Breakdown:
1. High-Level Overview
This C++ code is written for an STM32 microcontroller (like those found on some Arduino-compatible development boards). It serves as the hardware control layer for a "Squirrel Detection" alarm system.
However, this microcontroller isn't actually detecting the squirrels itself. Instead, it is designed to work in tandem with a more powerful Linux-based system (likely running Python code with a camera and AI image recognition). The Linux side handles the heavy lifting (detecting the squirrel) and sends commands to this microcontroller to control the physical hardware (LEDs, buzzers, and screens).
2. The "Bridge" Architecture
The most important part of this code is the #include "Arduino_RouterBridge.h" and the Bridge commands.
- This indicates the board has two "brains" communicating with each other: a Linux brain and a Microcontroller (MCU) brain.
- The MCU uses RPC (Remote Procedure Calls). This allows the Python script on the Linux side to trigger C++ functions on the MCU as if they were local Python functions.
3. Hardware Components Used
Based on the pin definitions and libraries, the hardware includes:
- Grove RGB LCD (#include "rgb_lcd.h"): An I2C screen to display system status and colors.
- Reset Button (Pin 2): A physical button a user can press.
- Red LED Beacon (Pin 3): A visual warning light.
- Audio Siren/Buzzer (Pin 4): An audible alarm.
4. Section-by-Section Breakdown
Setup & Initialization (setup())
This block runs exactly once when the board powers on.
- Pin Modes: It configures the reset button as an input (to read it) and the LED/buzzer as outputs (to turn them on/off).
- LCD Setup: It turns on the LCD screen, sets the backlight color to Green (RGB: 0, 255, 0), and prints "System Active".
- Bridge Initialization: Bridge.begin() starts the communication channel with the Linux side.
- Exposing Functions: The Bridge.provide() lines are crucial. They register three specific C++ functions (get_reset_button, trigger_alarm, clear_alarm) so the Linux/Python system is allowed to execute them over the bridge.
The Main Loop (loop())
void loop() {
// Keep the loop clear of blocking code like delay().
}
In most Arduino sketches, the loop() contains the main logic. Here, it is completely empty. This is because the system is event-driven. The Arduino_RouterBridge library handles incoming commands from Linux in the background using interrupts or timers. Keeping the loop empty ensures the MCU reacts instantly when the Linux side says "Sound the alarm!"
The RPC Functions
These are the three commands the Linux/Python side can trigger:
get_reset_button()
- Checks the physical button connected to Pin 2.
- Returns a 1 (HIGH) if pressed, or a 0 (LOW) if not pressed. The Python script likely checks this constantly to know if a human wants to turn off the alarm.
trigger_alarm()
- This is called by the Linux side when it sees a squirrel.
- It turns ON the Red LED and the Buzzer.
- It changes the LCD backlight to solid Red (255, 0, 0).
- It clears the screen and prints "SQUIRREL DETECTED!"
- Returns 1 to tell the Linux side the command was successful.
clear_alarm()
- This is called to reset the system (likely triggered by the Python script after it reads that get_reset_button() is pressed).
- It turns OFF the LED and Buzzer.
- It resets the LCD backlight to Green.
- It changes the text back to "System Safe
- Returns 1 to confirm success.
The Python script "calls" the service when the AI detects a furry intruder. The code is located in the code attachment section below
Code Breakdown: (MPU Side)
1. High-Level Overview
This Python script runs on the MPU (Microprocessor Unit) side of the system, which is a more powerful Linux environment (specifically on a Qualcomm processor in this context).
If the MCU (C++ code) was the "muscle" controlling the hardware, this Python script is the "brain." It is responsible for handling AI video object detection, managing a Web-based User Interface (UI), and sending commands over to the MCU when it detects a target (like a squirrel).
2. Key Components & Libraries
Instead of standard Arduino libraries, this script relies on powerful Python modules:
- VideoObjectDetection: A custom wrapper that handles reading a camera stream and passing frames through a trained AI machine learning model to detect objects.
- WebUI: A framework to serve a live dashboard to a web browser, allowing remote monitoring.
- Bridge: The Python counterpart to the C++ Arduino_RouterBridge. It allows this script to "call" the C++ functions we defined earlier.
- App: A system manager that runs the main loop and background tasks (like the video stream) asynchronously.
3. Section-by-Section Breakdown
Setup & Initialization
ui = WebUI()
detection_stream = VideoObjectDetection(confidence=0.5, debounce_sec=0.0)
ui.on_message("override_th", lambda sid, threshold: detection_stream.override_threshold(threshold))
- Instances: It creates the Web UI and initializes the AI video stream, setting a minimum confidence threshold of 50% (0.5) for detections.
- Interactivity: It sets up a listener (ui.on_message) so that if a user adjusts a slider on the Web UI labeled "override_th", it dynamically updates the AI's confidence threshold on the fly.
The AI Detection Callback (print_detections)
This function doesn't run in a standard loop; it is a callback. It is triggered automatically by the VideoObjectDetection stream whenever the AI processes a frame and finds objects.
- Data Formatting: It loops through everything the AI found (detections.items()). It packages the object's name, the AI's confidence score, and a precise UTC timestamp into a dictionary (entry).
- Updating the UI: ui.send_message("detection", message=entry) pushes this live data to the Web Dashboard so the user can see what the AI sees.
- Triggering the Alarm State: If the detected object is not "SAFE" (e.g., it's a "Squirrel"), it updates the global variables detection and sets alarm_active = True.
The Main Application Loop (loop)
This is the heartbeat of the Python script, running repeatedly in the background. It acts as a basic state machine managing the hardware via the Bridge.
Handling an Active Alarm (if alarm_active:):
- While the alarm is going off, the system needs to know if a human has pressed the physical reset button to turn it off.
- It executes Bridge.call("get_reset_button"). This sends a message to the MCU to run the C++ function we saw earlier and return the result.
- If the result is 1 (button pressed), it executes Bridge.call("clear_alarm"), which tells the MCU to turn off the buzzer and red LED. It then resets the alarm_active state to False.
- Note: The try...except block ensures that if the communication between the Linux side and MCU fails, the Python script doesn't crash.
Triggering the Hardware (if detection != "SAFE":):
- If the callback function flagged a hazard, this block catches it.
- It immediately calls Bridge.call("trigger_alarm"). This fires over the RPC bridge, telling the MCU to turn on the siren, light the red LED, and update the LCD screen.
- It then resets detection = "SAFE" so it doesn't repeatedly trigger the RPC call thousands of times a second.
Starting the Engine
detection_stream.on_detect_all(print_detections)
App.run(user_loop=loop)
- The first line wires up the AI stream to our print_detections callback.
- App.run(user_loop=loop) starts the entire system. It launches the Web UI server, starts the camera feed, begins running the AI models, and continuously cycles the loop() function to monitor states and hardware.
The "Squirrel Sentinel" is an intelligent, edge-AI-powered garden guardian designed to distinguish birds from squirrels and deploy real-time, humane deterrents to protect bird feeders. The core of the system relies on the dual-brain architecture of the Arduino UNO Q, which bridges high-level computer vision processing with deterministic, real-time hardware control.
The "Thinker" utilizes a USB camera and containerized "Bricks" via the Arduino App Lab to run an Edge Impulse object detection model written in Python. When a squirrel is identified, it sends an alert via the Arduino RouterBridge (RPC) to the "Doer". The microcontroller’s C++ sketch instantly triggers a physical response through a Grove Base Shield V3, activating a red LED beacon, a high-frequency audio buzzer, and a warning display on an RGB LCD screen. The system also features a physical reset button and a web-based UI for live video feed monitoring and threshold adjustments.
Key Learnings
Building this prototype served as a deep dive into modern edge-AI integration and hybrid-board development. Key takeaways include:
Mastering Dual-Architecture Systems: Successfully navigating the hardware and software bridge between a powerful Linux MPU and a real-time MCU, eliminating the traditional friction and messy wiring of using separate single-board computers and microcontrollers.
Containerized Edge Deployment: Utilizing the Arduino App Lab to easily deploy Docker-based "Bricks" (like the Video Object Detection and WebUI modules), which abstracted away the complex container orchestration and allowed for immediate focus on application logic.
Custom Vision AI Workflow: Executing the complete Edge Impulse pipeline—from raw data acquisition and image labeling to structuring the processing blocks, training the model, and deploying the optimized .eim container directly to the MPU.
Cross-Environment Communication: Implementing Remote Procedure Calls (RPC) using the Arduino_RouterBridge library, which allowed the high-level Python AI scripts to seamlessly execute C++ functions and trigger low-level hardware interrupts with zero latency.
Future EnhancementsTo take the Squirrel Sentinel from a functional prototype to an advanced, fully automated ecosystem, here are three logical upgrades for the next iteration:
Automated Mechanical Deterrents:
While lights and buzzers are effective initial warnings, squirrels are notorious for adapting to static alarms. By utilizing the MCU's capabilities, you could integrate a servo motor or relay module. When triggered, the servo could spin the bird feeder, drop a physical baffle, or trigger a harmless water-spritzing mechanism, providing a physical deterrent that cannot be ignored.
Cloud Telemetry and Remote Notifications:
Upgrade the Python logic to push detection events to an IoT dashboard (such as Arduino Cloud or AWS IoT). By logging timestamps, detection confidence scores, and total intrusion counts, you can analyze squirrel activity patterns over time. Additionally, this integration could push SMS or push notifications directly to a smartphone whenever an intruder triggers the system.
Multi-Class Avian Classification:
Expand the Edge Impulse AI model to do more than just hunt for squirrels. By gathering a broader dataset, the model can be trained to classify different bird species (e.g., cardinals, blue jays, finches). The Web UI could then double as an automated "bird-watching log," and the logic could be adjusted to capture and save video clips specifically when rare or specific bird species are detected at the feeder.
Thank you for taking the time to read through the Squirrel Sentinel project! I hope this documentation proves helpful as you explore the dual-brain capabilities of the Arduino UNO Q and build your own edge-AI applications. Please feel free to leave me any feedback, questions, or suggestions in the comments section below—I’d love to hear what you think!












Comments