亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

智能人脸追踪机器人车

组件和用品

Creator Ci20
× 1
SparkFun 双 H 桥电机驱动器 L298
× 1
锂离子电池 1000mAh
× 1
舵机(Tower Pro MG996R)
× 2
相机(通用)
× 1
Dexter Industries GoPiGo 机器人基础套件
× 1
Arduino Nano R3
× 1
超声波传感器 - HC-SR04(通用)
× 1

应用和在线服务

Arduino IDE
OpenCV

关于这个项目

跟踪你脸的车,我不在他就来!

你需要安装这个(Ci20):

  • Opencv
  • Python
  • 串口修复权限

我使用发行版 Debian 8 install &download

我用过:

  • 旧笔记本电脑相机(回收)
  • 超声波测距模块HC - SR04
  • x2 电池 3.7v 4000mah(回收旧笔记本电脑)
  • x2 伺服
  • DC-DC 转换器
  • Arduino nano
  • 机器人基础套件
  • x2 L298d

对于安装,请在终端中使用以下命令。

更新linux。

sudo apt-get update # 获取可用更新列表sudo apt-get upgrade # 严格升级当前包sudo apt-get dist-upgrade # 安装更新(新的) 

开放简历。 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 串口 USB sudo chown 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.pyPython
Python 脚本 OpenCV face traking
#!/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=>>servo.move(2, 90) ... # "move server #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 分类器 parser =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 =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.CV_CAP_PROP_FRAME_FRAME) "else20我们需要一个相机输入!指定相机索引,例如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) if midFace is not 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屏幕中间的右侧。 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 -=tiltStepSize print str(midFaceY) + "> " + str(midScreenY) + " :Tilt Down :" + str(servoTiltPosition) #找出人脸的Y分量是否在屏幕中间上方。 elif(midFaceY> (midScreenY + midScreenWindow)):if(servoTiltPosition>=1):#更新倾斜位置变量以提升倾斜伺服。伺服倾斜位置 +=倾斜步长打印 str(midFaceY) + " <" + str(midScreenY) + " :向上倾斜 :" + str(servoTiltPosition) start =1;结束 =1; else:打印 str(midFaceY) + " ~ " + str(midScreenY) + " :" + str(servoTiltPosition)servoTiltPosition =min(servoTiltPosition, max_pwm)servoTiltPosition =max(servoTiltPosition, min_pwm) move(tiltGpioPin) else #servoTiltPosition结束测量时间 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=90servoTiltPosition=45var=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 SERVOY_PIN 10 #define trigPin 13#define echoPin 12// 伺服和位置伺服伺服的用户输入;伺服伺服x;int x =90, prevX;int y =45, prevY;int userInput[3]; // 来自串行缓冲区的原始输入,3 bytesint startbyte; // 开始字节,开始读取 inputint 伺服; //哪个伺服脉冲?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) { // ... 然后获取接下来的两个字节 for (i =0; i <2; i++) { userInput[i] =串行读取(); } // 第一个字节 =要移动的伺服器?伺服 =用户输入 [0]; // 第二个字节 =哪个位置? pos =用户输入[1]; // 数据包错误检查和恢复 if (pos ==255) { 伺服 =255; } // 将新位置分配给适当的伺服开关(伺服){ case 1:servoy.write(pos); // 将伺服 1 移动到 'pos' break;情况 2:servox.write(pos);范围(位置);休息;案例3:扫描(45);扫描(65);休息;默认值:中断; } } }}void scan(int val) { while (Serial.available() ==0) {servoy.write(val); unsigned long currentMillis =millis(); if (currentMillis - previousMillis>=间隔) { previousMillis =currentMillis;伺服x.写(位置); if (State ==LOW ) { pos +=1; if (pos ==130) { 状态 =HIGH; } } else { 位置-=1;如果(pos ==40){状态=低;休息; } } } }}long distancia() { 持续时间长,距离;数字写入(trigPin,低); // 添加这一行 delayMicroseconds(2); // 添加这一行 digitalWrite(trigPin, HIGH);延迟微秒(10); // 添加这一行 digitalWrite(trigPin, LOW);持续时间 =脉冲输入(echoPin,高);距离=(持续时间/2)/29.1;返回距离;}void range(int pos) { if ((pos>=80 ) &(pos <=100)) { move(); } else if ((pos>=100 ) &(pos <=180)) { left();延迟(10);停止(); } else if ((pos>=1 ) &(pos <=80)) { right();延迟(10);停止(); }}void move() { 长距离,previusdistance;距离 =距离();如果(val <=80){ 反向();延迟(50);停止(); } else if (val>=140) { forward();延迟(50);停止(); } if (distance>=previusdistance) { val =(distance - previusdistance); } else if (distance <=previusdistance) { val =(previusdistance - distance); } previusdistance =distance;}void inicializate() { Serial.begin(115200); pinMode(MA_1,输出); pinMode(MA_2,输出); pinMode(MB_1,输出); pinMode(MB_2,输出); pinMode(MC_1,输出); pinMode(MC_2,输出); pinMode(MD_1,输出); pinMode(MD_2,输出); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT);伺服x.attach(SERVOX_PIN);伺服.attach(SERVOY_PIN);}void forward() { digitalWrite(MA_1, HIGH);数字写入(MA_2,低);数字写入(MB_1,高);数字写入(MB_2,低);数字写入(MC_1,高);数字写入(MC_2,低);数字写入(MD_1,高); digitalWrite(MD_2, LOW);}void reverse () { digitalWrite(MA_1, LOW);数字写入(MA_2,高);数字写入(MB_1,低);数字写入(MB_2,高);数字写入(MC_1,低);数字写入(MC_2,高);数字写入(MD_1,低); digitalWrite(MD_2, HIGH);}void right() { digitalWrite(MA_1, LOW);数字写入(MA_2,高);数字写入(MB_1,低);数字写入(MB_2,高);数字写入(MC_1,高);数字写入(MC_2,低);数字写入(MD_1,高); digitalWrite(MD_2, LOW);}void left() { digitalWrite(MA_1, HIGH);数字写入(MA_2,低);数字写入(MB_1,高);数字写入(MB_2,低);数字写入(MC_1,低);数字写入(MC_2,高);数字写入(MD_1,低); digitalWrite(MD_2, HIGH);}void Stop() { digitalWrite(MA_1, LOW);数字写入(MA_2,低);数字写入(MB_1,低);数字写入(MB_2,低);数字写入(MC_1,低);数字写入(MC_2,低);数字写入(MD_1,低); digitalWrite(MD_2, LOW);}void StopH() { digitalWrite(MA_1, HIGH);数字写入(MA_2,高);数字写入(MB_1,高);数字写入(MB_2,高);数字写入(MC_1,高);数字写入(MC_2,高);数字写入(MD_1,高);数字写入(MD_2,高);}
scanlinux.pyPython
扫描linux串口
#! /usr/bin/env python"""\扫描串行端口。Linux 特定变体,还包括 USB/Serialadapters。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/*')if __name__==' __main__':打印“找到的端口:”扫描()中的名称:打印名称

定制零件和外壳

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. 光序列创建器
  11. 人脸解锁智能门
  12. 智能插头