edge lab LIVE! starts Tuesday in Munich. Grab a workshop seat and take home the board you build on. Code FRIEND-HACKSTER saves 20%. () Learn more!
Stephen
Published

Squirrel Sentinel

Building the "Squirial Sentinel" with Arduino’s New Dual-Brain Power

IntermediateFull instructions provided24 hours134
Squirrel Sentinel

Things used in this project

Story

Read more

Code

The MPU Code (Python) :

Python
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".
# main.py - MPU Side (Qualcomm Linux) - Mock AI Dashboard
import cv2
import time
import random

from arduino.app_utils import Bridge
from arduino.app_utils import App
from arduino.app_bricks.video_objectdetection import VideoObjectDetection
from arduino.app_bricks.web_ui import WebUI
from datetime import datetime, UTC
#from arduino.app_bricks.streamlit_ui import st

#globals
alarm_active = False
detection = ""

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))

# Register a callback for when all objects are detected
def print_detections(detections: dict):
    global alarm_active
    global detection
    
    for key, values in detections.items():
        for value in values:
          entry = {
            "content": key,
            "confidence": value.get("confidence"),
            "timestamp": datetime.now(UTC).isoformat()
          }
          ui.send_message("detection", message=entry)
        
    print(entry)
    print(key)
    if key != "SAFE":
        detection = key
        # Hazard detected! Trigger the MCU hardware alarms!
        alarm_active = True
            

def loop():
    # This logic runs repeatedly on the Linux side
    global alarm_active
    global detection

    
    # --- STATE 1: ALARM IS ACTIVE ---
    if alarm_active:
        # Check the physical reset button via RPC Bridge
        try:
            button_pressed = Bridge.call("get_reset_button")
            if button_pressed == 1:
                Bridge.call("clear_alarm") # Tell MCU to turn off LED/Buzzer

                # reset globals
                alarm_active = False
                
                #last_scan_time = time.time() # Reset the 5-second timer
                #status_placeholder.success("System Reset by Operator. Resuming monitoring...")
                time.sleep(1) # Small debounce delay
        except Exception as e:
            print(f"Bridge error: {e}")
            
    
        # --- STATE 2: SYSTEM IS SAFE, MONITORING ---
        if detection != "SAFE":
            print(detection)
            # Hazard detected! Trigger the MCU hardware alarms!
            try:
                Bridge.call("trigger_alarm")
            except Exception as e:
                print(f"Bridge error: {e}")
            
            detection = "SAFE"

    # Small delay to prevent maxing out the CPU
    time.sleep(0.05)

# call detection stream to once that will call the print_detection function HERE if it detects an image you have trained
detection_stream.on_detect_all(print_detections)

# Start the App and run the loop() function above
#App.run
App.run(user_loop=loop)

The MCU Code (Sketch) :

Arduino
Hardware Control (The Second Brain): The STM32 MCU receives this alert through its C++ sketch and takes over hardware control.
// SPDX-License-Identifier: MPL-2.0
// sketch.ino - MCU Side (STM32)
#include "Arduino_RouterBridge.h"
#include <Wire.h>
#include "rgb_lcd.h"
// Define Grove Shield Pins
const int resetButtonPin = 2; // Digital pin for Reset Button
const int ledPin = 3;         // Digital pin for Red LED Beacon
const int buzzerPin = 4;      // Digital pin for Audio Siren


rgb_lcd lcd;


void setup() {
  // Initialize the digital pins
  pinMode(resetButtonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
 
  // Initialize the I2C LCD
  lcd.begin(16, 2);
  lcd.setRGB(0, 255, 0); // Default to Green (Safe status)
  lcd.print("System Active");


  // Start the Bridge communication layer
  Bridge.begin();


  // Expose these C++ functions to the Linux Python environment
  Bridge.provide("get_reset_button", get_reset_button);
  Bridge.provide("trigger_alarm", trigger_alarm);
  Bridge.provide("clear_alarm", clear_alarm);
}


void loop() {
  // The Bridge handles incoming RPC calls automatically in the background.
  // Keep the loop clear of blocking code like delay().
}


// --- Registered RPC Functions ---


int get_reset_button() {
  // Reads the digital state (0 or 1) from the Reset button
  return digitalRead(resetButtonPin);
}


int trigger_alarm() {
  // Activates the LED, Buzzer, and turns the LCD Red
  digitalWrite(ledPin, HIGH);
  digitalWrite(buzzerPin, HIGH);
  lcd.setRGB(255, 0, 0);
  lcd.clear();
  lcd.print("SQUIRREL DETECTED!");
  return 1;
}


int clear_alarm() {
  // Deactivates the LED, Buzzer, and turns the LCD Green
  digitalWrite(ledPin, LOW);
  digitalWrite(buzzerPin, LOW);
  lcd.setRGB(0, 255, 0);
  lcd.clear();
  lcd.print("System Safe");
  return 1;
}

Credits

Stephen
50 projects • 33 followers
I am a retired software engineer, with a Bachelor of Science degree in Computer Science from Boston University.

Comments