DIY камера с распознаванием лиц на Arduino UNO — Face Tracking
Компоненты и материалы
| Компонент | Количество |
|---|---|
| Arduino UNO | 1 |
| Веб-камера (USB) | 1 |
| Резиновая лента (для крепления камеры) | 1 |
| Блок питания 9В 1А (DC jack 2.1×5.5 мм) | 1 |
| Сервоприводы MG-90S (металлические шестерни) | 2 |
| Линейный стабилизатор 7805 (5В) | 1 |
| Саморезы M2×10 мм | 15 |
| Обычная скрепка (для механизма) | 1 |
| Провода 22 AWG | 1 набор |
| Pin header (разъёмы) | 1 |
| LED 5 мм: красный, зелёный, жёлтый | по 1 |
| Резисторы 220 Ом (для LED) | 3 |
| Термоусадочная трубка | 1 |
Инструменты
- Кусачки/обкусыватель, длиннонощные плоскогубцы
- Паяльник
- Мультиметр
- Отвёртка
- 3D-принтер (для печати корпуса)
Программное обеспечение
- Microsoft Windows 10
- Python (скрипт распознавания лиц)
- Arduino IDE
О проекте
Автор напечатал на 3D-принтере голову коллеги и решил добавить механизм, который следит за людьми в комнате. Получился компактный, легко собираемый робот-камера с открытым ПО.
Принцип работы
- Камера движется двумя сервоприводами (пан/тилт) от Arduino Uno.
- Камера подключена к ПК — Python-скрипт (OpenCV) ищет лица в кадре.
- Если лицо найдено — Python отправляет команды Arduino по Serial (USB), чтобы центрировать лицо.
- Если лицо не найдено — камера движется в случайную позицию (поиск).
- 3 LED показывают статус: красный — нет лица, жёлтый — лицо есть, но не в центре, зелёный — лицо в центре.
- Протокол: текстовые пакеты
<pan,tilt,state>(например,<90.5,45.0,1>). - Настройки: диапазоны серв, инверсия осей, ручное управление.
Сборка и настройка
- Детали: STL-файлы на сайте автора и Thingiverse.
- Сборка механики: см. видео на сайте.
- Схемотехника: см. раздел Schematics.
- Прошивка Arduino: загрузите скетч ниже.
- Python-софт: исходники на GitHub или готовый .exe на сайте автора.
Код Arduino (C++)
// Based on Robin2's Serial Input Basics
// https://forum.arduino.cc/index.php?topic=225329.msg1810764
#include <Servo.h>
Servo panServo;
Servo tiltServo;
byte redLedPin = 2;
byte yellowLedPin = 3;
byte greenLedPin = 4;
const byte buffSize = 40;
char inputBuffer[buffSize];
const char startMarker = '<';
const char endMarker = '>';
byte bytesRecvd = 0;
boolean readInProgress = false;
boolean newDataFromPC = false;
float panServoAngle = 90.0;
float tiltServoAngle = 90.0;
int LED_state = 0;
void setup() {
Serial.begin(115200);
panServo.attach(8);
tiltServo.attach(9);
pinMode(redLedPin, OUTPUT);
pinMode(yellowLedPin, OUTPUT);
pinMode(greenLedPin, OUTPUT);
start_sequence();
delay(200);
Serial.println("<Hasta la vista baby>");
}
void loop() {
getDataFromPC();
replyToPC();
moveServo();
setLED();
}
void getDataFromPC() {
if (Serial.available() > 0) {
char x = Serial.read();
if (x == endMarker) {
readInProgress = false;
newDataFromPC = true;
inputBuffer[bytesRecvd] = 0;
processData();
}
if (readInProgress) {
inputBuffer[bytesRecvd] = x;
bytesRecvd++;
if (bytesRecvd == buffSize) bytesRecvd = buffSize - 1;
}
if (x == startMarker) {
bytesRecvd = 0;
readInProgress = true;
}
}
}
void processData() {
char *strtokIndx = strtok(inputBuffer, ",");
panServoAngle = atof(strtokIndx);
strtokIndx = strtok(NULL, ",");
tiltServoAngle = atof(strtokIndx);
strtokIndx = strtok(NULL, ",");
LED_state = atoi(strtokIndx);
}
void replyToPC() {
if (newDataFromPC) {
newDataFromPC = false;
Serial.print("<");
Serial.print(panServo.read());
Serial.print(",");
Serial.print(tiltServo.read());
Serial.println(">");
}
}
void moveServo() {
panServo.write(panServoAngle);
tiltServo.write(tiltServoAngle);
}
void setLED() {
switch (LED_state) {
case 2: // Жёлтый — лицо есть, не в центре
digitalWrite(redLedPin, LOW);
digitalWrite(yellowLedPin, HIGH);
digitalWrite(greenLedPin, LOW);
break;
case 1: // Зелёный — лицо в центре
digitalWrite(redLedPin, LOW);
digitalWrite(yellowLedPin, LOW);
digitalWrite(greenLedPin, HIGH);
break;
case 0: // Красный — нет лица
digitalWrite(redLedPin, HIGH);
digitalWrite(yellowLedPin, LOW);
digitalWrite(greenLedPin, LOW);
break;
case 3: // Все горят (тест/ошибка)
digitalWrite(redLedPin, HIGH);
digitalWrite(yellowLedPin, HIGH);
digitalWrite(greenLedPin, HIGH);
break;
default:
digitalWrite(redLedPin, LOW);
digitalWrite(yellowLedPin, LOW);
digitalWrite(greenLedPin, LOW);
}
}
void start_sequence() {
panServo.write(90); tiltServo.write(90); delay(300);
digitalWrite(redLedPin, HIGH); delay(100); digitalWrite(redLedPin, LOW);
digitalWrite(yellowLedPin, HIGH); delay(100); digitalWrite(yellowLedPin, LOW);
digitalWrite(greenLedPin, HIGH); delay(100); digitalWrite(greenLedPin, LOW);
delay(100);
digitalWrite(redLedPin, HIGH); digitalWrite(yellowLedPin, HIGH); digitalWrite(greenLedPin, HIGH);
delay(100);
digitalWrite(redLedPin, LOW); digitalWrite(yellowLedPin, LOW); digitalWrite(greenLedPin, LOW);
}
Python-софт (Face Detection)
Репозиторий: GitHub. Там же — исполняемый файл для Windows (не нужен Python). Использует OpenCV Haar Cascade или DNN для детекта лиц. Настраиваемые порты, скорость, инверсия осей.
3D-модели (CAD)
Все детали для печати: сайт автора / Thingiverse.
Схема подключения
В разделе Schematics (PNG). Основные связи:
- Pan-серво → D8, Tilt-серво → D9
- LED: D2 (Red), D3 (Yellow), D4 (Green) через 220 Ом
- Питание серв: 7805 от 9В, общий GND с Arduino
- USB — связь с ПК
Производственный процесс
- Практическое руководство: real-time панорамирование/наклон для отслеживания лиц на Raspberry Pi
- Визитка-PCB с игрой «Крестики-нолики» 4×4: руководство по проектированию, сборке и программированию
- Многопозиционная система датчиков температуры для интеграции в умный дом
- DIY-контроллер паяльника 862D+ — точность и надёжность
- MotionSense: умная система обнаружения проникновения на Arduino и ESP8266
- Пожарная безопасность 3D-принтера: умная система обнаружения дыма
- Веб-управляемый IoT-индикатор на Arduino, Yaler и IFTTT
- Магнитная левитация на отталкивании с Arduino: Простая схема и DIY-руководство
- Продвинутый дистанционно управляемый манипулятор-робот для точной работы
- CoroFence: термический детектор на GridEye + PIR с IoT