Fabio henrique gomes de moura silva
Published © MIT

Skeeter-Scan 16

This code transforms your laptop into a defense control station (Skeeter-Scan V3). It integrates computer vision (motion detection)

AdvancedWork in progress257
Skeeter-Scan 16

Things used in this project

Story

Read more

Custom parts and enclosures

The Project: "Skeeter-Bunker V1" This case was designed to be compact, tactical, and to house: ESP

The Project: "Skeeter-Bunker V1"

This case was designed to be compact, tactical, and to house:

ESP32-CAM (Internally mounted)

HC-SR04 (Eyes on the outside)

6mm Laser (Below the sonar)

Schematics

"Skeeter-Bunker V1"

"Skeeter-Bunker V1"

Code

cpp

C/C++
/*
 * SKEETER-SCAN 16 - Tactical Radar Firmware
 * Board: ESP32-CAM (O Cérebro)
 */

// Definição dos Pinos (GPIOs)
const int PIN_TRIG = 13;   // Trigger do Sensor Ultrassônico
const int PIN_ECHO = 12;   // Echo do Sensor Ultrassônico
const int PIN_LASER = 4;   // Módulo Laser (Cilíndrico 6mm)

// Configurações do Radar
const int DISTANCIA_ALVO = 50; // Distância de detecção em cm (ajustável)

void setup() {
  Serial.begin(115200);
  
  // Configuração dos pinos
  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  pinMode(PIN_LASER, OUTPUT);
  
  // Garante que o laser comece desligado
  digitalWrite(PIN_LASER, LOW);
  
  Serial.println("SKEETER-SCAN 16: Sistema Iniciado...");
}

void loop() {
  // 1. Gera o pulso ultrassônico
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);

  // 2. Mede o tempo de resposta
  long duracao = pulseIn(PIN_ECHO, HIGH);

  // 3. Calcula a distância em cm
  int distancia = duracao * 0.034 / 2;

  // 4. Lógica de Detecção e Mira
  if (distancia > 0 && distancia <= DISTANCIA_ALVO) {
    Serial.print("ALVO DETECTADO! Distancia: ");
    Serial.print(distancia);
    Serial.println(" cm");
    
    digitalWrite(PIN_LASER, HIGH); // Ativa a Mira Laser
    delay(500); // Mantém o laser aceso por meio segundo
  } else {
    digitalWrite(PIN_LASER, LOW);  // Desliga o Laser
  }

  delay(100); // Pequena pausa para a próxima varredura
}




V2

/*
 * SKEETER-SCAN 16 - Virtual Sweep Upgrade
 * Simula a lógica de varredura de 0° a 180° para integração com o HUD
 */

#include <Arduino.h>

const int PIN_TRIG = 13;
const int PIN_ECHO = 12;
const int PIN_LASER = 4;

// Lógica de Varredura Virtual
int anguloAtual = 0;
int direcao = 1; // 1 para aumentar, -1 para diminuir
const int PASSO = 10; // Incremento de 10 graus por leitura

void setup() {
  Serial.begin(115200);
  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  pinMode(PIN_LASER, OUTPUT);
  
  Serial.println("SKEETER-SCAN 16: Modo Varredura Virtual Ativo");
}

void loop() {
  // 1. Lógica de Movimentação do Ângulo (Simulada)
  // Se você adicionar um servo no futuro, o comando 'servo.write(anguloAtual)' viria aqui.
  anguloAtual += (direcao * PASSO);

  if (anguloAtual >= 180 || anguloAtual <= 0) {
    direcao *= -1; // Inverte a direção ao chegar nos limites
  }

  // 2. Medição Ultrassônica
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);

  long duracao = pulseIn(PIN_ECHO, HIGH);
  int distancia = duracao * 0.034 / 2;

  // 3. Output Formatado para o Framework 16 / HUD
  // Enviamos o ângulo e a distância para que o processamento 3D no PC mapeie o arco
  Serial.print("ANG:"); 
  Serial.print(anguloAtual);
  Serial.print("|DIST:");
  Serial.println(distancia);

  // 4. Lógica de Disparo (Laser)
  // O laser só deve disparar se o alvo estiver no "centro" ou em um ângulo de interesse
  if (distancia > 0 && distancia <= 50) {
    digitalWrite(PIN_LASER, HIGH);
    // No HUD, isso apareceria como um "Lock-on" no ângulo X
    Serial.printf("!!! ALVO DETECTADO NO ANGULO %d !!!\n", anguloAtual);
  } else {
    digitalWrite(PIN_LASER, LOW);
  }

  delay(50); // Delay menor para uma varredura mais fluida
}

New CPP

C/C++
The original design does not include a physical servo motor. However, it is possible to simulate the scanning logic via software or prepare the code so that one of the ESP32 cores processes the data as if it were in an expanded field of view.
To actually move the sensor without a motor, some makers use multiple sensor or vibration techniques, but the most efficient way to implement "scanning" via pure code on the ESP32-CAM (which is dual-core) is to create a Virtual Sampling Scan.
/*
 * SKEETER-SCAN 16 - Virtual Sweep Upgrade
 * Simula a lgica de varredura de 0 a 180 para integrao com o HUD
 */

#include <Arduino.h>

const int PIN_TRIG = 13;
const int PIN_ECHO = 12;
const int PIN_LASER = 4;

// Lgica de Varredura Virtual
int anguloAtual = 0;
int direcao = 1; // 1 para aumentar, -1 para diminuir
const int PASSO = 10; // Incremento de 10 graus por leitura

void setup() {
  Serial.begin(115200);
  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  pinMode(PIN_LASER, OUTPUT);
  
  Serial.println("SKEETER-SCAN 16: Modo Varredura Virtual Ativo");
}

void loop() {
  // 1. Lgica de Movimentao do ngulo (Simulada)
  // Se voc adicionar um servo no futuro, o comando 'servo.write(anguloAtual)' viria aqui.
  anguloAtual += (direcao * PASSO);

  if (anguloAtual >= 180 || anguloAtual <= 0) {
    direcao *= -1; // Inverte a direo ao chegar nos limites
  }

  // 2. Medio Ultrassnica
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);

  long duracao = pulseIn(PIN_ECHO, HIGH);
  int distancia = duracao * 0.034 / 2;

  // 3. Output Formatado para o Framework 16 / HUD
  // Enviamos o ngulo e a distncia para que o processamento 3D no PC mapeie o arco
  Serial.print("ANG:"); 
  Serial.print(anguloAtual);
  Serial.print("|DIST:");
  Serial.println(distancia);

  // 4. Lgica de Disparo (Laser)
  // O laser s deve disparar se o alvo estiver no "centro" ou em um ngulo de interesse
  if (distancia > 0 && distancia <= 50) {
    digitalWrite(PIN_LASER, HIGH);
    // No HUD, isso apareceria como um "Lock-on" no ngulo X
    Serial.printf("!!! ALVO DETECTADO NO ANGULO %d !!!\n", anguloAtual);
  } else {
    digitalWrite(PIN_LASER, LOW);
  }

  delay(50); // Delay menor para uma varredura mais fluida
}

Skeeter Scan in Python

Python
Skeeter Scan in Python This code transforms your laptop into a defense control station (Skeeter-Scan V3). It integrates computer vision (motion detection) with telemetry
import cv2
import numpy as np
import serial
import time
import threading
import sys

# ==========================================
# CONFIGURAES DO USURIO (AJUSTE AQUI)
# ==========================================
# IP da ESP32-CAM (veja no Monitor Serial ao iniciar o ESP32)
ESP32_IP = "192.168.1.100" 
URL_STREAM = f"http://{ESP32_IP}:81/stream"

# Porta Serial (Windows: 'COM3', 'COM4' | Linux/Mac: '/dev/ttyUSB0')
SERIAL_PORT = 'COM3' 
BAUD_RATE = 115200

# Parmetros de Deteco (Calibragem)
AREA_MINIMA = 50   # Tamanho mnimo do objeto (filtra rudo)
AREA_MAXIMA = 800  # Tamanho mximo (filtra pessoas/mos)
DISTANCIA_TIRO = 50 # Distncia mxima em cm para disparo

# ==========================================
# VARIVEIS GLOBAIS DE ESTADO
# ==========================================
telemetria = {
    "distancia": 0,
    "sistema_ativo": True,
    "laser_ativo": False,
    "lock_visual": False
}

# ==========================================
# THREAD DE COMUNICAO SERIAL
# ==========================================
def serial_comms():
    """Gerencia envio e recebimento de dados com o ESP32 em paralelo."""
    try:
        ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=0.1)
        time.sleep(2) # Tempo para estabilizar conexo
        print(f"[SERIAL] Conectado na porta {SERIAL_PORT}")
        
        while telemetria["sistema_ativo"]:
            # 1. LEITURA (Recebe dados do Sonar)
            if ser.in_waiting:
                try:
                    linha = ser.readline().decode('utf-8', errors='ignore').strip()
                    if "DIST:" in linha:
                        # Formato esperado: "ANG:0|DIST:45" ou apenas "DIST:45"
                        partes = linha.split("DIST:")
                        if len(partes) > 1:
                            telemetria["distancia"] = int(partes[1])
                except ValueError:
                    pass
            
            # 2. ESCRITA (Envia comando do Laser)
            # Protocolo: 'L' = Laser ON, 'O' = Laser OFF
            comando = b'L' if telemetria["laser_ativo"] else b'O'
            ser.write(comando)
            
            time.sleep(0.05) # Evita sobrecarga da CPU
            
        ser.close()
    except Exception as e:
        print(f"[ERRO SERIAL] Falha na conexo: {e}")
        telemetria["distancia"] = -1

# ==========================================
# VISO COMPUTACIONAL E HUD
# ==========================================
def desenhar_hud(frame, largura, altura):
    """Desenha a interface ttica sobre o vdeo."""
    centro_x, centro_y = largura // 2, altura // 2
    cor_hud = (0, 255, 0) # Verde Hacker
    cor_alerta = (0, 0, 255) # Vermelho
    
    # 1. Retcula Central
    if telemetria["laser_ativo"]:
        cv2.circle(frame, (centro_x, centro_y), 40, cor_alerta, 2)
        cv2.putText(frame, "ENGAGED", (centro_x-35, centro_y-50), cv2.FONT_HERSHEY_SIMPLEX, 0.6, cor_alerta, 2)
    else:
        cv2.circle(frame, (centro_x, centro_y), 20, cor_hud, 1)
        cv2.line(frame, (centro_x-30, centro_y), (centro_x+30, centro_y), cor_hud, 1)
        cv2.line(frame, (centro_x, centro_y-30), (centro_x, centro_y+30), cor_hud, 1)

    # 2. Painel de Dados
    cv2.rectangle(frame, (10, 10), (250, 110), (0, 0, 0), -1) # Fundo preto semi-transparente
    cv2.rectangle(frame, (10, 10), (250, 110), cor_hud, 1)
    
    cv2.putText(frame, "SKEETER-SCAN V3", (20, 35), cv2.FONT_HERSHEY_SIMPLEX, 0.6, cor_hud, 2)
    
    # Status do Sonar
    dist = telemetria["distancia"]
    txt_dist = f"SONAR: {dist} cm" if dist != -1 else "SONAR: ERRO"
    cv2.putText(frame, txt_dist, (20, 65), cv2.FONT_HERSHEY_SIMPLEX, 0.6, cor_hud, 1)
    
    # Status do Sistema
    status = "ARMED" if telemetria["lock_visual"] else "SCANNING"
    cor_sts = cor_alerta if telemetria["lock_visual"] else cor_hud
    cv2.putText(frame, f"STATUS: {status}", (20, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.6, cor_sts, 2)

def main():
    # Inicia a thread serial
    t_serial = threading.Thread(target=serial_comms)
    t_serial.daemon = True
    t_serial.start()

    print(f"[VIDEO] Conectando ao stream: {URL_STREAM}")
    cap = cv2.VideoCapture(URL_STREAM)
    
    # Subtrator de fundo para detectar movimento
    fgbg = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=50, detectShadows=False)

    while True:
        ret, frame = cap.read()
        if not ret:
            print("[VIDEO] Falha ao capturar frame. Verifique o IP.")
            time.sleep(2)
            continue

        altura, largura, _ = frame.shape
        centro_x, centro_y = largura // 2, altura // 2
        
        # --- PROCESSAMENTO DE IMAGEM ---
        # Aplica mscara de movimento
        mask = fgbg.apply(frame)
        _, mask = cv2.threshold(mask, 200, 255, cv2.THRESH_BINARY)
        
        # Limpeza de rudo (eroso e dilatao)
        mask = cv2.erode(mask, None, iterations=2)
        mask = cv2.dilate(mask, None, iterations=2)
        
        contornos, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        telemetria["lock_visual"] = False
        alvo_no_centro = False

        for cnt in contornos:
            area = cv2.contourArea(cnt)
            
            # Filtra objetos pelo tamanho (mosquito vs ventilador vs pessoa)
            if AREA_MINIMA < area < AREA_MAXIMA:
                x, y, w, h = cv2.boundingRect(cnt)
                
                # Desenha caixa ao redor do alvo
                cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
                
                # Verifica se o alvo est na "zona de tiro" (centro da tela)
                zona_tiro_x = (centro_x - 50, centro_x + 50)
                zona_tiro_y = (centro_y - 50, centro_y + 50)
                
                centro_obj_x = x + w//2
                centro_obj_y = y + h//2
                
                if (zona_tiro_x[0] < centro_obj_x < zona_tiro_x[1]) and \
                   (zona_tiro_y[0] < centro_obj_y < zona_tiro_y[1]):
                    alvo_no_centro = True
                    telemetria["lock_visual"] = True

        # --- LGICA DE DISPARO (FUSO DE SENSORES) ---
        # Dispara SE: (Alvo Visual no Centro) E (Distncia Sonar < Limite)
        dist = telemetria["distancia"]
        if alvo_no_centro and (0 < dist <= DISTANCIA_TIRO):
            telemetria["laser_ativo"] = True
        else:
            telemetria["laser_ativo"] = False

        # --- RENDERIZAO ---
        desenhar_hud(frame, largura, altura)
        
        cv2.imshow("SKEETER-SCAN 16 - CONTROL STATION", frame)

        # 'q' para sair
        if cv2.waitKey(1) & 0xFF == ord('q'):
            telemetria["sistema_ativo"] = False
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

Credits

Fabio henrique gomes de moura silva
2 projects • 3 followers

Comments