Arduino UNO搭載DIY顔追跡カメラ
部品と材料
| Arduino UNO | ×1 |
| ウェブカメラ | ×1 |
| ゴムバンド | ×1 |
| 9V 1A ACアダプター | ×1 |
| MG-90sサーボ | ×2 |
| 2.1×5.5mm DCジャックプラグ | ×1 |
| リニアレギュレーター (7805) | ×1 |
| M2×10mmタッピングネジ | ×15 |
| クリップ(ペーパークリップ) | ×1 |
| フックアップワイヤーキット (22 AWG) | ×1 |
| ピンヘッダー | ×1 |
| 5mm LED: 赤 | ×1 |
| 5mm LED: 緑 | ×1 |
| 5mm LED: 黄 | ×1 |
| 抵抗 220 Ω | ×3 |
| 熱収縮チューブ | ×1 |
必要な工具と機械
- ワイヤーストリッパー&カッター (18-10 AWG / 0.75-4mm²)
- ラジオペンチ(ロングノーズ)
- はんだごて(汎用)
- マルチメーター
- ドライバー
- 3Dプリンター(汎用)
アプリとオンラインサービス
- Microsoft Windows 10
このプロジェクトについて
数ヶ月前、同僚の頭部をモデリングして3Dプリントしたのをきっかけに、人を検知して部屋の中を動き回る人の顔を追い続けるメカニズムを作ろうと思いつきました。機構を3Dプリントサイズに収めるのに苦労しましたが、プロジェクトを放置する代わりに、誰でも組み立てやすく、ソフトウェアも使いやすいモデルとして公開することにしました。
仕組み
カメラは2つのサーボで動かし、Arduino Unoで制御します。カメラはPCに接続され、Pythonソフトウェアがカメラ画像から顔を検出します。
- 顔が検出された場合:検出された顔が画面中央に来るようArduinoに指令を送信し、カメラを移動
- 顔が検出されない場合:ランダムな位置に移動するよう指令送信
ソフトウェアは柔軟性を持たせており、以下のオプションがあります:
- サーボ可動範囲の変更
- サーボ回転方向の反転
- 手動制御モード
3つのLEDで検出状態を表示:赤=検出なし、黄=顔検出だが中央外、緑=顔検出かつ中央。LED自体は単純ですが、有用なアクション(アラーム等)に置き換え可能です。Arduinoとソフトウェア間はUSBシリアル通信で行います。
顔検出ソフトウェアはPythonで作成。GitHubにコードを公開しています(自学自習のコードなので品質は保証しません)。Pythonが苦手な方向けに、Webサイトで実行ファイル版も配布しています。
製作方法は以下の動画で解説しています。できるだけ分かりやすく作りました。
必要なもの
組み立て
配線
ソフトウェアとセットアップ
コード
Arduinoコード
// Robin2氏のArduinoフォーラムでの作業に基づくスケッチ
// 詳細: https://forum.arduino.cc/index.php?topic=225329.msg1810764#msg1810764
#include
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(""); // PCへメッセージ送信
}
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;
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() {
if(LED_state == 2){
digitalWrite(redledPin, LOW);
digitalWrite(yellowledPin, HIGH);
digitalWrite(greenledPin, LOW);
} else if(LED_state == 1){
digitalWrite(redledPin, LOW);
digitalWrite(yellowledPin, LOW);
digitalWrite(greenledPin, HIGH);
} else if(LED_state == 0){
digitalWrite(redledPin, HIGH);
digitalWrite(yellowledPin, LOW);
digitalWrite(greenledPin, LOW);
} else if(LED_state == 3){
digitalWrite(redledPin, HIGH);
digitalWrite(yellowledPin, HIGH);
digitalWrite(greenledPin, HIGH);
} else{
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(redledPin, LOW); digitalWrite(yellowledPin, LOW); 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);
}
顔検出ソフトウェア
顔検出ソフトウェアのファイルは以下のリポジトリで入手可能です。Webサイトでも実行ファイル版を配布しています。
GitHubリポジトリ
カスタムパーツとエンクロージャ
顔追跡カメラパーツ
顔追跡カメラミニの構築に必要な全パーツ。
Webサイト または Thingiverse からダウンロード可能。
回路図
配線図が提供されています。
製造プロセス
- Raspberry Piでリアルタイムパン/チルト顔追跡 - 実践ガイド
- 名刺サイズPCBで作る4×4三目並べゲーム - 設計・製作・プログラミングガイド
- スマートホーム連携向けマルチポジション温度センサーシステム
- 862D+はんだごて用DIY温度コントローラー:精度と信頼性を両立
- MotionSense: ArduinoとESP8266で作るスマート侵入検知システム
- 3Dプリンター火災予防:スマートセンサーセーフティシステム
- Arduino、Yaler、IFTTTでWeb対応IoTゲージを構築する
- Arduinoで作る斥力式磁気浮上装置: シンプル回路とDIYガイド
- 高度なリモートコントロールグリッパーロボット: 精密ハンドリング向け
- 高性能 Arduino 気象観測気球データロガーの製作ガイド
- CoroFenceサーマルディテクター:Grid-EYE & PIRセンサー搭載IoT体温監視