산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

스마트 얼굴 추적 로봇 자동차

구성품 및 소모품

Creator Ci20
× 1
SparkFun 듀얼 H-Bridge 모터 드라이버 L298
× 1
리튬 이온 배터리 1000mAh
× 1
서보(타워 프로 MG996R)
× 2
카메라(일반)
× 1
Dexter Industries GoPiGo 로봇 베이스 키트
× 1
Arduino Nano R3
× 1
초음파 센서 - HC-SR04(일반)
× 1

앱 및 온라인 서비스

Arduino IDE
OpenCV

이 프로젝트 정보

당신의 얼굴을 추적하는 자동차입니다. 내가 없으면 그가 옵니다!

이것을 설치해야 합니다(Ci20):

<울>
  • Opencv
  • <울>
  • 파이썬
  • <울>
  • 직렬 포트 수정 권한
  • Debian 8 설치 및 다운로드 배포판을 사용했습니다.

    나는 다음을 사용했다:

    <울>
  • 오래된 노트북 카메라(재활용)
  • <울>
  • 초음파 측정 모듈 HC - SR04
  • <울>
  • x2 배터리 3.7v 4000mah(오래된 노트북 재활용)
  • <울>
  • x2 서보
  • <울>
  • DC-DC 컨버터
  • <울>
  • 아두이노 나노
  • <울>
  • 로봇 베이스 키트
  • <울>
  • x2 L298d
  • 설치를 위해 터미널에서 다음 명령을 사용하십시오.

    리눅스를 업데이트하려면.

    sudo apt-get update # 사용 가능한 업데이트 목록을 가져옵니다.sudo apt-get upgrade # 현재 패키지를 엄격하게 업그레이드합니다.sudo apt-get dist-upgrade # 업데이트 설치(새 항목) 

    오픈CV. 버전 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 #Arduino의 직렬 포트 USBsudo chown ci20:ci20 /dev/ttyS1 #Ci20의 직렬 포트 기본 

    파이썬 스크립트를 실행합니다(두 개 이상의 비디오 소스가 있는 경우 0을 변경하면 소스가 선택됨).

    sudo 파이썬 facetrackingcar.py 0 

    성능을 약간 향상시키려면 캡처한 이미지가 표시되지 않습니다. 보고 싶은 경우 이 줄을 검색하고 주석 처리를 제거해야 합니다.

    #cv.ShowImage("결과", img)#cv.NamedWindow("결과", 1)#cv.DestroyWindow("결과") 

    haarcascade_frontalface_alt.xml이 있어야 합니다. 스크립트와 동일한 디렉토리에 있는 파일.

    Windows에서 카메라 추적 전용 동영상

    Ci20에 대한 데모 비디오

    피드백 및 개선 사항을 환영합니다.

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • faceser.py
  • 카.이노
  • scanlinux.py
  • faceser.py파이썬
    Python scrip OpenCV 얼굴 추적
    #!/usr/bin/python"""이 프로그램은 haar와 유사한 기능을 사용하여 얼굴 및 개체 감지를 위한 데모입니다. 이 프로그램은 카메라 이미지 또는 비디오 스트림에서 얼굴을 찾고 빨간색 상자를 표시합니다. 그런 다음 두 개의 서보를 통해 웹캠을 중앙에 배치하여 얼굴이 화면 중앙에 오도록 OpenCV 샘플 디렉토리의 facedetect.py 기반"""import sysfrom optparse import OptionParserimport serialimport cv2.cv as cvimport time# Haar 감지용 매개변수# API에서:# 정확하지만 느린 개체 감지를 위해 기본 매개변수(scale_factor=2, min_neighbors=3, flags=0)가 조정되었습니다. 실제 비디오# 이미지에서 더 빠른 작업을 위해 설정은 다음과 같습니다.# scale_factor=1.2, min_neighbors=2, flags=CV_HAAR_DO_CANNY_PRUNING,# min_size=<가능한 최소 얼굴 크기min_size =(20, 20)image_scale =2haar_scale =1.2min_neighbors =1.2min_neighbors =2 .CV_HAAR_DO_CANNY_PRUNINGmax_pwm =180min_pwm =1midScreenWindow =20 # 화면 중앙에 허용되는 '오류'.panStepSize =1 # 각 팬에 대한 변경 정도 updatetiltStepSize =1 # 각 틸트에 대한 변경 정도 updateervoPanPosition =90 =# # 초기 틸트 위치 ypanGpioPin =2 # arduino 팬 서보 ID(핀 번호 아님)tiltGpioPin =1 # arduino 틸트 서보 ID(핀 번호 아님)var =0;def detect_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) # 빠른 처리를 위해 입력 이미지 크기 조정 essing cv.Resize(gray, small_img, cv.CV_INTER_LINEAR) cv.EqualizeHist(small_img, small_img) midFace =None if(cascade):t =cv.GetTickCount() # HaarDetectObjects는 0.02s 면을 사용 =cv.HaarDetectObjects(small_im , 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의 크기가 조정되었으므로 # 각 면의 경계 상자 크기를 조정하고 두 개의 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] y1 =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) ... # "move servo #2 90도까지"''' if (min_pwm <=angle <=max_pwm):ser.write(chr(255)) ser.write(chr(servo)) ser.write(chr(angle)) else:print "서보 angle은 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(사용 ="사용:%prog [옵션] [카메라_색인]") parser.add_option("-c", "--cascade", action="store", dest="cascade", type="str", help="Haar 캐스케이드 파일, 기본 %default", 기본값 ="./haarcascade_frontalface_alt.xml") (옵션, 인수) =parser.parse_args() cascade =cv.Load(options.cascade) if len(args) !=1:parser.print_help() sys.exit(1) input_name =arg s[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.CVIGHT_CAP_PROP_FRAM 카메라 입력이 필요합니다! 카메라 인덱스를 지정하십시오. 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) 프레임이 아닌 경우:cv.WaitKey(0) 프레임이 아닌 경우 중단: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) if midFace가 None이 아닌 경우:midFaceX =midFace[0] midFaceY =midFace[1] #얼굴의 X 구성요소가 화면 중앙의 왼쪽에 있는지 확인합니다. if(midFaceX <(midScreenX - midScreenWindow)):#서보를 오른쪽으로 이동하도록 팬 위치 변수를 업데이트합니다.servoPanPosition +=panStepSize print str(midFaceX) + "> " + str(midScreenX) + " :Pan Right :" + str(servoPanPosition) #X 얼굴의 구성 요소는 r 화면 중앙의 ight. elif(midFaceX> (midScreenX + midScreenWindow)):# 서보를 왼쪽으로 이동하기 위해 팬 위치 변수를 업데이트합니다. servoPanPosition -=panStepSize print str(midFaceX) + " <" + str(midScreenX) + " :왼쪽으로 이동 :" + 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 -=tiltStepSize print str(midFaceY) + "> " + str(midScreenY) + " :Tilt Down :" + str(servoTiltPosition) #얼굴의 Y 구성 요소가 화면 중앙보다 위에 있는지 확인합니다. elif(midFaceY> (midScreenY + midScreenWindow)):if(servoTiltPosition>=1):#기울기 서보를 올리기 위해 기울기 위치 변수를 업데이트합니다. ServoTiltPosition +=tiltStepSize 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, servoTilt) 종료 시간 측정 end =time.time()+0.1 var +=0.1 # 경과 시간 가져오기 time_elapsed =int(end - start + var) # 정보 출력 print 'time elapsed:\t{}'.format(time_elapsed) print ' var:\t{}'.format(var) if time_elapsed ==20:move(3, servoTiltPosition) servoPanPosition =90 servoTiltPosition =45 var=0; if cv.WaitKey(1)>=0:# 1ms 지연 중단 #cv.DestroyWindow("result")
    Car.inoArduino
    #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 SERVOX_PIN 11#define #define trigPin 13#define echoPin 12// 서보 및 위치에 대한 사용자 입력Servo servoy;Servo servox;int x =90, prevX;int y =45, prevY;int userInput[3]; // 직렬 버퍼의 원시 입력, 3 bytesint startbyte; // 시작 바이트, 입력 읽기 시작 int 서보; // 펄스에 대한 서보?int pos; // 서보 각도 0-180int i; // 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) { // ... then 다음 2바이트를 얻습니다 for (i =0; i <2; i++) { userInput[i] =직렬.읽기(); } // 첫 번째 바이트 =이동할 서보? 서보 =사용자 입력[0]; // 두 번째 바이트 =어느 위치? pos =사용자 입력[1]; // 패킷 오류 검사 및 복구 if (pos ==255) {servo =255; } // 적절한 서보 스위치에 새 위치를 할당합니다. (servo) { case 1:servoy.write(pos); // 서보1을 'pos'로 이동 break; 사례 2:서보x.write(pos); 범위(위치); 부서지다; 사례 3:스캔(45); 스캔(65); 부서지다; 기본값:중단; } } }} 무효 스캔(int val) { 동안 (Serial.available() ==0) {servoy.write(val); 부호 없는 긴 currentMillis =millis(); if (currentMillis - previousMillis>=간격) { previousMillis =currentMillis; Servox.write(pos); if (상태 ==낮음) { 위치 +=1; if (pos ==130) { 상태 =HIGH; } } else { 위치 -=1; if (pos ==40) { 상태 =LOW; 부서지다; } } } }}long distancia() { 긴 기간, 거리; digitalWrite(trigPin, LOW); // 다음 라인을 추가했습니다. delayMicroseconds(2); // 이 라인을 추가했습니다. digitalWrite(trigPin, HIGH); 지연마이크로초(10); // 이 라인을 추가했습니다. digitalWrite(trigPin, LOW); 지속 시간 =pulseIn(echoPin, HIGH); 거리 =(지속시간 / 2) / 29.1; 반환 거리;} 무효 범위(int pos) { if ((pos>=80 ) &(pos <=100)) { moves(); } else if ((pos>=100 ) &(pos <=180)) { 왼쪽(); 지연(10); 중지(); } else if ((pos>=1 ) &(pos <=80)) { right(); 지연(10); 중지(); }}void moves() { 장거리, previusdistance; 거리 =거리(); if (val <=80) { reverse(); 지연(50); 중지(); } else if (val>=140) { forward(); 지연(50); 중지(); } if (distance>=previusdistance) { val =(distance - previusdistance); } else if (거리 <=previusdistance) { val =(previusdistance - 거리); } previusdistance =거리;} 무효 초기화() { Serial.begin(115200); 핀모드(MA_1, 출력); 핀모드(MA_2, 출력); 핀모드(MB_1, 출력); 핀모드(MB_2, 출력); 핀모드(MC_1, 출력); 핀모드(MC_2, 출력); 핀모드(MD_1, 출력); 핀모드(MD_2, 출력); 핀모드(trigPin, 출력); 핀모드(에코핀, 입력); Servox.attach(SERVOX_PIN); 서보y.attach(SERVOY_PIN);}앞으로 무효() { digitalWrite(MA_1, HIGH); 디지털 쓰기(MA_2, LOW); 디지털 쓰기(MB_1, 높음); 디지털 쓰기(MB_2, LOW); 디지털 쓰기(MC_1, 높음); 디지털 쓰기(MC_2, LOW); 디지털 쓰기(MD_1, 높음); digitalWrite(MD_2, LOW);} 역방향 무효() { digitalWrite(MA_1, LOW); 디지털 쓰기(MA_2, 높음); 디지털 쓰기(MB_1, LOW); 디지털 쓰기(MB_2, 높음); 디지털 쓰기(MC_1, LOW); 디지털 쓰기(MC_2, 높음); 디지털 쓰기(MD_1, LOW); digitalWrite(MD_2, HIGH);} 무효 right() { digitalWrite(MA_1, LOW); 디지털 쓰기(MA_2, 높음); 디지털 쓰기(MB_1, LOW); 디지털 쓰기(MB_2, 높음); 디지털 쓰기(MC_1, 높음); 디지털 쓰기(MC_2, LOW); 디지털 쓰기(MD_1, 높음); digitalWrite(MD_2, LOW);}왼쪽() 무효 { digitalWrite(MA_1, HIGH); 디지털 쓰기(MA_2, LOW); 디지털 쓰기(MB_1, 높음); 디지털 쓰기(MB_2, LOW); 디지털 쓰기(MC_1, LOW); 디지털 쓰기(MC_2, 높음); 디지털 쓰기(MD_1, LOW); digitalWrite(MD_2, HIGH);} 무효 Stop() { digitalWrite(MA_1, LOW); 디지털 쓰기(MA_2, LOW); 디지털 쓰기(MB_1, LOW); 디지털 쓰기(MB_2, LOW); 디지털 쓰기(MC_1, LOW); 디지털 쓰기(MC_2, LOW); 디지털 쓰기(MD_1, LOW); digitalWrite(MD_2, LOW);} 무효 StopH() { digitalWrite(MA_1, HIGH); 디지털 쓰기(MA_2, 높음); 디지털 쓰기(MB_1, 높음); 디지털 쓰기(MB_2, 높음); 디지털 쓰기(MC_1, 높음); 디지털 쓰기(MC_2, 높음); 디지털 쓰기(MD_1, 높음); digitalWrite(MD_2, HIGH);}
    scanlinux.py파이썬
    리눅스 직렬 포트 스캔
    #! /usr/bin/env python"""\직렬 포트 스캔. USB/직렬 어댑터도 포함하는 Linux 특정 변형. pySerial의 일부(http://pyserial.sf.net)(C) 2009 """import serialimport globdef scan():"""사용 가능한 포트를 검색합니다. 장치 이름 목록을 반환합니다. pvergain@houx:~/PDEV1V160_CodesRousseau/Soft/PC/test_boost/serialport/pyserial$ python scanlinux.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/*') __name__=='인 경우 __main__':scan()의 이름에 대해 "발견된 포트:" 인쇄:이름 인쇄

    맞춤형 부품 및 인클로저

    Python 스크립 OpenCV 얼굴 추적 및 Arduino 코드 FaceTrakingCar.rar

    회로도

    arduino를 사용하여 모터 및 서보를 제어하는 ​​경우 핀아웃이 다를 수 있습니다.

    제조공정

    1. Arduino 디지털 주사위
    2. DIY 37 LED 룰렛 게임
    3. ATtiny85 미니 아케이드:뱀
    4. 휴대용 거리 감지기
    5. MobBob:Android 스마트폰으로 제어되는 DIY Arduino 로봇
    6. Arduino 제어 피아노 로봇:PiBot
    7. 구리로 전기도금
    8. NeoMatrix Arduino Pong
    9. 전방향 사람 추적 친화적 로봇
    10. 광 시퀀스 생성기