工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

スマートフェイストラッキングロボットカー

コンポーネントと消耗品

>
Creator Ci20
× 1
SparkFunデュアルHブリッジモータードライバーL298
× 1
リチウムイオン電池1000mAh
× 1
サーボ(Tower Pro MG996R)
× 2
カメラ(汎用)
× 1
Dexter IndustriesGoPiGoロボットベースキット
× 1
Arduino Nano R3
× 1
超音波センサー-HC-SR04(汎用)
× 1

アプリとオンラインサービス

>
Arduino IDE
OpenCV

このプロジェクトについて

それはあなたの顔を追跡する車です、私が離れていれば彼が来ます!

これ(Ci20)をインストールしておく必要があります:

  • Opencv
  • Python
  • シリアルポートの修正権限

私はDistroDebian8のインストールとダウンロードを使用しました

使用したもの:

  • 古いノートパソコンのカメラ(リサイクル)
  • 超音波レンジングモジュール HC - SR04
  • x2バッテリー3.7v4000mah(リサイクルされた古いラップトップ)
  • x2サーボ
  • DC-DCコンバーター
  • Arduino nano
  • ロボットベースキット
  • x2 L298d

インストールするには、ターミナルで次のコマンドを使用します。

Linuxを更新するには。

  sudo apt-get update#利用可能なアップデートのリストを取得しますsudo apt-get upgrade#現在のパッケージを厳密にアップグレードしますsudo apt-get dist-upgrade#アップデート(新しいもの)をインストールします 

OpenCV。バージョン2.4.9.1は最新ではありませんが、正常に動作します。

  sudo apt-get install libopencv-dev python-opencv  

ソースからOpenCVをコンパイルしたい場合は、このチュートリアルを見つけました。

PySerialをインストールします。

  sudo apt-get install python python-serial  

USBまたはネイティブを使用した場合は、シリアルポートのアクセス許可を変更します。

  sudo chown ci20:ci20 / dev / ttyUSB0#Arduinosudo chownからのシリアルポートUSB ci20:ci20 / dev / ttyS1#Ci20でネイティブのシリアルポート 

Pythonスクリプトを実行します(複数のビデオソースがある場合はゼロを変更します。これによりソースが選択されます)。

  sudo python facetrackingcar.py 0  

パフォーマンスをわずかに向上させるために、表示したい場合はキャプチャされた画像が表示されないため、この行を検索してコメントを解除する必要があります。

 #cv.ShowImage( "result"、img)#cv.NamedWindow( "result"、1)#cv.DestroyWindow( "result") 

haarcascade_frontalface_alt.xml が必要です スクリプトと同じディレクトリにあるファイル。

Windowsでカメラを追跡するためのビデオ

Ci20のデモビデオ

フィードバックと改善を歓迎します。

コード

  • faceser.py
  • Car.ino
  • scanlinux.py
faceser.py Python
Python scripOpenCVフェイストラッキング
#!/ usr / bin / python "" "このプログラムは、haarのような機能を使用した顔とオブジェクトの検出のデモンストレーションです。このプログラムは、カメラ画像またはビデオストリームで顔を検出し、赤いボックスを表示します次に、2つのサーボを介してWebサイトを中央に配置し、顔が画面の中央にくるようにします。OpenCVサンプルディレクトリのfacedetect.pyに基づく "" "import sysfrom optparse import OptionParserimport serialimport cv2.cv as cvimport time#haar検出のパラメーター# APIから:#デフォルトのパラメーター(scale_factor =2、min_neighbors =3、flags =0)は、正確でありながら低速なオブジェクト検出のために調整されています。実際のビデオ#画像でより高速な操作を行うための設定は次のとおりです。 .CV_HAAR_DO_CANNY_PRUNINGmax_pwm =180min_pwm =1midScreenWindow =20#画面の中央で許容できる「エラー」panStepSize =1#各パンの変化度updatetiltStepSize =1#各傾斜更新の変化度ervoPanPosition =90#初期パン位置xservoTiltPosition =45 #初期傾斜位置ypanGpioPin =2#arduinoパンサーボID(ピン番号ではない)tiltGpioPin =1#arduino傾斜サーボID(ピン番号ではない)var =0; defdetect_and_draw(img、cascade):gray =cv.CreateImage((img .width、img.height)、8、1)small_img =cv.CreateImage((cv.Round(img.width / image_scale)、cv.Round(img.height / image_scale))、8、1)#色入力を変換画像からグレースケールcv.CvtColor(img、gray、cv.CV_BGR2GRAY) #入力画像を拡大縮小して処理を高速化cv.Resize(gray、small_img、cv.CV_INTER_LINEAR)cv.EqualizeHist(small_img、small_img)midFace =None if(cascade):t =cv.GetTickCount()#HaarDetectObjectsは0.02秒の面を取ります=cv .HaarDetectObjects(small_img、cascade、cv.CreateMemStorage(0)、haar_scale、min_neighbors、haar_flags、min_size)t =cv.GetTickCount()-t if faces:for((x、y、w、h)、n)in faces :#cv.HaarDetectObjectsへの入力のサイズが変更されたため、#各面の境界ボックスをスケーリングして2つのCvPointに変換しますpt1 =(int(x * image_scale)、int(y * image_scale))pt2 =(int((x + w)* image_scale)、int((y + h)* image_scale))cv.Rectangle(img、pt1、pt2、cv.RGB(255、0、0)、3、8、0)#xyコーナーを取得座標、midFaceの位置を計算しますx1 =pt1 [0] x2 =pt2 [0] y 1 =pt1 [1] y2 =pt2 [1] midFaceX =x1 +((x2-x1)/ 2)midFaceY =y1 +((y2-y1)/ 2)midFace =(midFaceX、midFaceY)#cv.ShowImage( "result "、img)return midFacedef move(servo、angle): '' '指定されたサーボを指定された角度に移動します。引数:サーボ番号をコマンドにサーボ制御し、1〜4度の整数で目的のサーボ角度、0〜180度の整数(例)>>> servo.move(2、90)...# "moveservo#2 90度まで "'' 'if(min_pwm <=angle <=max_pwm):ser.write(chr(255))ser.write(chr(servo))ser.write(chr(angle))else:print" Servo角度は0〜180の整数である必要があります。\ n "if__name__ =='__ main __':ser =serial.Serial(port ='/ dev / ttyUSB0'、baudrate =115200、timeout =1)#ser =serial.Serial (port ='/ dev / ttyS0'、baudrate =115200、timeout =1)#ser =serial.Serial(port ='COM14'、baudrate =115200、timeout =1)#cmd行オプションを解析し、Haar分類子パーサーを設定=OptionParser(usage ="usage:%prog [options] [camera_index]")parser.add_option( "-c"、 "--cascade"、action ="store"、dest ="cascade"、type ="str"、 help ="Haarカスケードファイル、デフォルト%default"、default ="./haarcascade_frontalface_alt.xml")(options、args)=parser.parse_args()カスケード=cv.Load(options.cascade)if len(args)!=1:parser.print_help()sys.exit(1)input_name =args [0] if input_name.isdigit():capture =cv.CreateCameraCapture(int (input_name))cv.SetCaptureProperty(capture、cv.CV_CAP_PROP_FRAME_WIDTH、320)cv.SetCaptureProperty(capture、cv.CV_CAP_PROP_FRAME_HEIGHT、240)else:print "カメラ入力が必要です!カメラインデックスを指定します。例: 0 "sys.exit(0)#cv.NamedWindow(" result "、1)if Capture:frame_copy =None move(panGpioPin、servoPanPosition)move(tiltGpioPin、servoTiltPosition)while True:start =time.time()frame =cv .QueryFrame(capture)if not frame:cv.WaitKey(0)break if not frame_copy:frame_copy =cv.CreateImage((frame.width、frame.height)、cv.IPL_DEPTH_8U、frame.nChannels)if frame.origin ==cv.IPL_ORIGIN_TL:cv.Copy(frame、frame_copy)else:cv.Flip(frame、frame_copy、0)midScreenX =(frame.width / 2)midScreenY =(frame.height / 2)midFace =detect_and_draw(frame_copy、cascade) midFaceがNoneでない場合:midFaceX =midFace [0] midFaceY =midFace [1]#顔のXコンポーネントがlにあるかどうかを確認します画面中央の左。 if(midFaceX <(midScreenX-midScreenWindow)):#パン位置変数を更新して、サーボを右に移動します。 ServoPanPosition + =panStepSize print str(midFaceX)+ ">" + str(midScreenX)+ ":Pan Right:" + str(servoPanPosition)#顔のXコンポーネントが画面の中央の右側にあるかどうかを確認します。 elif(midFaceX>(midScreenX + midScreenWindow)):#パン位置変数を更新して、サーボを左に移動します。 servoPanPosition- =panStepSize print str(midFaceX)+ "<" + str(midScreenX)+ ":Pan Left:" + str(servoPanPosition)else:print str(midFaceX)+ "〜" + str(midScreenX)+ ":" + str(servoPanPosition)servoPanPosition =min(servoPanPosition、max_pwm)servoPanPosition =max(servoPanPosition、min_pwm)move(panGpioPin、servoPanPosition)#顔のYコンポーネントが画面の中央より下にあるかどうかを確認します。 if(midFaceY <(midScreenY --midScreenWindow)):if(servoTiltPosition <=90):#傾斜位置変数を更新して傾斜サーボを下げます。 servoTiltPosition- =tileStepSize print str(midFaceY)+ ">" + str(midScreenY)+ ":Tilt Down:" + str(servoTiltPosition)#顔のYコンポーネントが画面の中央より上にあるかどうかを確認します。 elif(midFaceY>(midScreenY + midScreenWindow)):if(servoTiltPosition> =1):#傾斜位置変数を更新して傾斜サーボを上げます。 servoTiltPosition + =tileStepSize print str(midFaceY)+ "<" + str(midScreenY)+ ":ティルトアップ:" + str(servoTiltPosition)start =1;終了=1; else:print str(midFaceY)+ "〜" + str(midScreenY)+ ":" + str(servoTiltPosition)servoTiltPosition =min(servoTiltPosition、max_pwm)servoTiltPosition =max(servoTiltPosition、min_pwm)move(tiltGpioPin、servoTiltPos終了測定時間end =time.time()+ 0.1 var + =0.1#経過時間の取得time_elapsed =int(end --start + var)#印刷情報print '経過時間:\ t {}'。format(time_elapsed)print ' var:\ t {} '。format(var)if time_elapsed ==20:move(3、servoTiltPosition)servoPanPosition =90servoTiltPosition =45 var =0; if cv.WaitKey(1)> =0:#1ms遅延ブレーク#cv.DestroyWindow( "result")
Car.ino Arduino
 #include  #define MA_1 2#define MA_2 3#define MB_1 4#define MB_2 5#define MC_1 6#define MC_2 7#define MD_1 8#define MD_2 9#define SERVOX_PIN 11#define SERVOY_PIN 10 #define trigPin 13#define echoPin 12 //サーボと位置のユーザー入力サーボサーボx;サーボサーボx; intx =90、prevX; int y =45、prevY; int userInput [3]; //シリアルバッファからの生の入力、3バイトint startbyte; //バイトを開始し、inputintサーボの読み取りを開始します; //どのサーボをパルスしますか?int pos; //サーボ角度0-180inti; // iteratorint State =LOW; unsigned long previousMillis =0、val =100;; const long interval =100; bool scana =false; unsigned long currentMillis; void setup(){inicializate(); currentMillis =millis();} void loop(){//シリアル入力を待つ(バッファ内で最小3バイト)if(Serial.available()> 2){//最初のバイトを読み取るstartbyte =Serial.read(); //それが本当にstartbyte(255)の場合... if(startbyte ==255){// ...次の2バイトを取得します(i =0; i <2; i ++){userInput [i] =Serial.read(); } //最初のバイト=移動するサーボ?サーボ=userInput [0]; // 2番目のバイト=どの位置? pos =userInput [1]; //パケットエラーのチェックと回復if(pos ==255){servo =255; } //適切なサーボスイッチに新しい位置を割り当てます(servo){ケース1:servoy.write(pos); // servo1を 'pos'breakに移動します;ケース2:servox.write(pos); range(pos);壊す;ケース3:scan(45); scan(65);壊す;デフォルト:ブレーク; }}}} void scan(int val){while(Serial.available()==0){servoy.write(val); unsigned long currentMillis =millis(); if(currentMillis-previousMillis> =間隔){previousMillis =currentMillis; Servox.write(pos); if(State ==LOW){pos + =1; if(pos ==130){状態=HIGH; }} else {pos- =1; if(pos ==40){状態=LOW;壊す; }}}}} long distancia(){長い期間、距離; digitalWrite(trigPin、LOW); //この行を追加delayMicroseconds(2); //この行を追加しましたdigitalWrite(trigPin、HIGH); delayMicroseconds(10); //この行を追加しましたdigitalWrite(trigPin、LOW);期間=pulseIn(echoPin、HIGH);距離=(期間/ 2)/ 29.1; return distance;} void range(int pos){if((pos> =80)&(pos <=100)){moves(); } else if((pos> =100)&(pos <=180)){left(); delay(10);やめる(); } else if((pos> =1)&(pos <=80)){right(); delay(10);やめる(); }} void moves(){長距離、previusdistance;距離=distancia(); if(val <=80){reverse(); delay(50);やめる(); } else if(val> =140){forward(); delay(50);やめる(); } if(distance> =previusdistance){val =(distance-previusdistance); } else if(distance <=previusdistance){val =(previusdistance-distance); } previusdistance =distance;} void inicializate(){Serial.begin(115200); pinMode(MA_1、OUTPUT); pinMode(MA_2、OUTPUT); pinMode(MB_1、OUTPUT); pinMode(MB_2、OUTPUT); pinMode(MC_1、OUTPUT); pinMode(MC_2、OUTPUT); pinMode(MD_1、OUTPUT); pinMode(MD_2、OUTPUT); pinMode(trigPin、OUTPUT); pinMode(echoPin、INPUT); Servox.attach(SERVOX_PIN); Servoy.attach(SERVOY_PIN);} void forward(){digitalWrite(MA_1、HIGH); digitalWrite(MA_2、LOW); digitalWrite(MB_1、HIGH); digitalWrite(MB_2、LOW); digitalWrite(MC_1、HIGH); digitalWrite(MC_2、LOW); digitalWrite(MD_1、HIGH); digitalWrite(MD_2、LOW);} void reverse(){digitalWrite(MA_1、LOW); digitalWrite(MA_2、HIGH); digitalWrite(MB_1、LOW); digitalWrite(MB_2、HIGH); digitalWrite(MC_1、LOW); digitalWrite(MC_2、HIGH); digitalWrite(MD_1、LOW); digitalWrite(MD_2、HIGH);} void right(){digitalWrite(MA_1、LOW); digitalWrite(MA_2、HIGH); digitalWrite(MB_1、LOW); digitalWrite(MB_2、HIGH); digitalWrite(MC_1、HIGH); digitalWrite(MC_2、LOW); digitalWrite(MD_1、HIGH); digitalWrite(MD_2、LOW);} void left(){digitalWrite(MA_1、HIGH); digitalWrite(MA_2、LOW); digitalWrite(MB_1、HIGH); digitalWrite(MB_2、LOW); digitalWrite(MC_1、LOW); digitalWrite(MC_2、HIGH); digitalWrite(MD_1、LOW); digitalWrite(MD_2、HIGH);} void Stop(){digitalWrite(MA_1、LOW); digitalWrite(MA_2、LOW); digitalWrite(MB_1、LOW); digitalWrite(MB_2、LOW); digitalWrite(MC_1、LOW); digitalWrite(MC_2、LOW); digitalWrite(MD_1、LOW); digitalWrite(MD_2、LOW);} void StopH(){digitalWrite(MA_1、HIGH); digitalWrite(MA_2、HIGH); digitalWrite(MB_1、HIGH); digitalWrite(MB_2、HIGH); digitalWrite(MC_1、HIGH); digitalWrite(MC_2、HIGH); digitalWrite(MD_1、HIGH); digitalWrite(MD_2、HIGH);} 
scanlinux.py Python
Linuxシリアルポートをスキャンする
#! / usr / bin / env python "" "\シリアルポートをスキャンします。USB/ Serialadaptersを含むLinux固有のバリアント。pySerialの一部(http://pyserial.sf.net)(C)2009  "" "import serialimport globdef scan():" ""使用可能なポートをスキャンします。デバイス名のリストを返します。pvergain@ houx:〜/ PDEV1V160_CodesRousseau / Soft / PC / test_boost / serialport / pyserial $ pythonscanlinux.py見つかったポート:/ dev / ttyS0 / dev / ttyS3 / dev / ttyS2 / dev / ttyS1 / dev / ttyACM0 / dev / serial / by-id / usb-id3_semiconductors_MEABOARD_00000000-if00 "" "return glob.glob( '/ dev / ttyS *' )+ glob.glob( '/ dev / ttyUSB *')+ glob.glob( '/ dev / ttyACM *')+ glob.glob( '/ dev / serial / by-id / *')if __name __ ==' __main __ ':scan()の名前に「Foundports:」を出力:名前を出力

カスタムパーツとエンクロージャー

PythonスクリプトOpenCVフェイストラッキングとArduinoコード FaceTrakingCar.rar

回路図

arduinoを使用してモーターとサーボを制御すると、ピン配置が異なる場合があります。

製造プロセス

  1. Arduino Digital Dice
  2. DIY 37LEDルーレットゲーム
  3. ATtiny85ミニアーケード:スネーク
  4. ポータブルレンジ検出器
  5. MobBob:Androidスマートフォンで制御されるDIY Arduino Robot
  6. Arduino制御ピアノロボット:PiBot
  7. 銅による電気めっき
  8. NeoMatrix Arduino Pong
  9. フレンドリーなロボットを追跡する全方向性の人々
  10. ライトシーケンスクリエーター
  11. フェイスアンロック付きスマートドア