Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Умный автомобиль-робот с отслеживанием лиц

Компоненты и расходные материалы

Creator Ci20
× 1
Драйверы двигателя SparkFun Dual H-Bridge L298
× 1
Литий-ионный аккумулятор 1000 мАч
× 1
Сервоприводы (Tower Pro MG996R)
× 2
Камера (общая)
× 1
Базовый комплект робота GoPiGo Dexter Industries
× 1
Arduino Nano R3
× 1
Ультразвуковой датчик - HC-SR04 (общий)
× 1

Приложения и онлайн-сервисы

IDE Arduino
OpenCV

Об этом проекте

Это машина, которая отслеживает ваше лицо, если меня нет, он приедет!

Вам необходимо установить это (Ci20):

  • Opencv
  • Python
  • Разрешения на исправление последовательного порта

Я использовал дистрибутив Debian 8:установить и скачать

Я использовал:

  • Старая камера ноутбука (переработанная)
  • Ультразвуковой дальномер HC - SR04
  • Аккумулятор x2 3,7 В, 4000 мАч (переработанный старый ноутбук)
  • сервопривод x2
  • преобразователь постоянного тока в постоянный
  • Ардуино нано
  • Базовый комплект робота
  • x2 L298d

Для установки используйте в терминале следующие команды.

Чтобы обновить linux.

  sudo apt-get update # Выбирает список доступных обновлений sudo apt-get upgrade # Строго обновляет текущий пакетudo 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 # Последовательный порт USB от Arduinosudo chown ci20:ci20 / dev / ttyS1 # Последовательный порт, встроенный в Ci20  

Запускает скрипт python (меняет ноль, если у вас более одного источника видео, это выбирает источник).

  sudo python facetrackingcar.py 0  

Чтобы немного повысить производительность, захваченное изображение не отображается, если вы хотите его увидеть, вы должны выполнить поиск и раскомментировать эти строки.

  # cv.ShowImage ("результат", img) # cv.NamedWindow ("результат", 1) # cv.DestroyWindow ("результат")  

У вас должен быть haarcascade_frontalface_alt.xml файл в том же каталоге, что и скрипт.

Видео только для слежения за камерой в Windows

Демо-ролик о Ci20

Отзывы и улучшения приветствуются.

Код

  • faceser.py
  • Car.ino
  • scanlinux.py
faceser.py Python
Сценарий Python Отслеживание лиц OpenCV
 #! / Usr / bin / python "" "Эта программа представляет собой демонстрацию обнаружения лиц и объектов с использованием функций, похожих на волосы. Программа находит лица на изображении с камеры или в видеопотоке и отображает красную рамку вокруг них, затем центрирует веб-камеру с помощью двух сервоприводов так, чтобы лицо находилось в центре экрана Из 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 =2haar_flags =cv .CV_HAAR_DO_CANNY_PRUNINGmax_pwm =180min_pwm =1midScreenWindow =20 # приемлемая 'ошибка' для центра экрана .panStepSize =1 # степень изменения для каждого панорамирования updatetiltStepSize =1 # степень изменения для каждого наклона updatePosition panPosition =45 # начальное положение резервуара # начальная позиция наклона ypanGpioPin =2 # идентификатор сервопривода панорамирования arduino (НЕ номер вывода) tiltGpioPin =1 # идентификатор сервопривода наклона arduino (НЕ номер вывода) 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,02 с. facesargjects, cv. , 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 был изменен, поэтому масштабируйте # ограничивающий прямоугольник каждой грани и преобразуйте его в два CvPoints 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) ... # "перемещение сервопривода # 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, настроить парсер классификатора Хаара =OptionParser (usage ="usage:% prog [options] [camera_index]") parser.add_option ("- c", "--cascade", action ="store", dest ="cascade", type ="str", help ="Каскадный файл Хаара, по умолчанию% default", default ="./haarcascade_frontalface_alt.xml") (options, args) =parser.parse_args () cascade =cv.Load (options.cascade) if len (args)! =1:parser.print_help () sys.exit (1) input_name =arg s [0] если input_name.isdigit ():capture =cv.CreateCameraCapture (int (имя_входа)) cv.SetCaptureProperty (capture, cv.CV_CAP_PROP_FRAME_WIDTH, 320) cv.SetCaptureProperty (print, cv.CV_CAP_PROPAME, cv.CV_CAP_PROPAME Нам нужен вход камеры! Укажите индекс камеры, например 0 "sys.exit (0) # cv.NamedWindow (" результат ", 1) если захват:frame_copy =None move (panGpioPin, servoPanPosition) move (tiltGpioPin, servoTiltPosition) while True:start =time.time () frame =cv .QueryFrame (захват), если не кадр:cv.WaitKey (0) break, если не 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 не 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):# Обновите переменную положения наклона, чтобы поднять сервопривод наклона. servoTiltPosition + =tiltStepSize print str (midFaceY) + "<" + str (midScreenY) + ":Tilt Up:" + 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, 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 =90 servoTiltPosition =45 var =0; if cv.WaitKey (1)> =0:# 1ms delay break # 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 // Пользовательский ввод для сервопривода и сервопривода PositionServo; Servo servox; int x =90, prevX; int y =45, prevY; int userInput [3]; // необработанный ввод из последовательного буфера, 3 байта int startbyte; // начальный байт, начало чтения inputint servo; // какой сервопривод импульсный? 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 (); // Если это действительно начальный байт (255) ... if (startbyte ==255) {// ... тогда получаем следующие два байта for (i =0; i <2; i ++) {userInput [i] =Serial.read (); } // Первый байт =сервопривод для перемещения? серво =userInput [0]; // Второй байт =какая позиция? pos =userInput [1]; // Проверка ошибок пакета и восстановление if (pos ==255) {servo =255; } // Присваиваем новое положение соответствующему сервопереключателю (серво) {case 1:servoy.write (pos); // перемещаем servo1 в 'pos' break; случай 2:servox.write (pos); диапазон (поз.); ломать; случай 3:сканирование (45); сканирование (65); ломать; по умолчанию:перерыв; }}}} пустое сканирование (int val) {while (Serial.available () ==0) {servoy.write (val); беззнаковый длинный currentMillis =millis (); если (текущийМиллис - предыдущийМиллис> =интервал) {предыдущийМиллис =текущийМиллис; servox.write (pos); если (Состояние ==НИЗКИЙ) {pos + =1; if (pos ==130) {Состояние =ВЫСОКОЕ; }} else {pos - =1; if (pos ==40) {Состояние =НИЗКОЕ; ломать; }}}}} long distancia () {длительность, расстояние; digitalWrite (trigPin, LOW); // Добавил эту строку delayMicroseconds (2); // Добавил эту строку digitalWrite (trigPin, HIGH); delayMicroseconds (10); // Добавил эту строку digitalWrite (trigPin, LOW); duration =pulseIn (echoPin, HIGH); расстояние =(продолжительность / 2) / 29,1; расстояние возврата;} void range (int pos) {if ((pos> =80) &(pos <=100)) {move (); } иначе, если ((pos> =100) &(pos <=180)) {left (); задержка (10); Останавливаться(); } иначе, если ((pos> =1) &(pos <=80)) {right (); задержка (10); Останавливаться(); }} void move () {большое расстояние, предыдущее расстояние; расстояние =distancia (); если (значение <=80) {обратный (); задержка (50); Останавливаться(); } иначе, если (значение> =140) {вперед (); задержка (50); Останавливаться(); } если (расстояние> =предыдущее расстояние) {val =(расстояние - предыдущее расстояние); } else if (расстояние <=previusdistance) {val =(previusdistance - расстояние); } 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, ВЫХОД); pinMode (echoPin, ВХОД); servox.attach (SERVOX_PIN); servoy.attach (SERVOY_PIN);} недействительно вперед () {digitalWrite (MA_1, HIGH); digitalWrite (MA_2, LOW); digitalWrite (MB_1, ВЫСОКИЙ); digitalWrite (MB_2, LOW); digitalWrite (MC_1, ВЫСОКИЙ); digitalWrite (MC_2, LOW); digitalWrite (MD_1, ВЫСОКИЙ); digitalWrite (MD_2, LOW);} void reverse () {digitalWrite (MA_1, LOW); digitalWrite (MA_2, ВЫСОКИЙ); digitalWrite (MB_1, LOW); digitalWrite (MB_2, ВЫСОКИЙ); digitalWrite (MC_1, LOW); digitalWrite (MC_2, ВЫСОКИЙ); digitalWrite (MD_1, LOW); digitalWrite (MD_2, HIGH);} право недействительно () {digitalWrite (MA_1, LOW); digitalWrite (MA_2, ВЫСОКИЙ); digitalWrite (MB_1, LOW); digitalWrite (MB_2, ВЫСОКИЙ); digitalWrite (MC_1, ВЫСОКИЙ); digitalWrite (MC_2, LOW); digitalWrite (MD_1, ВЫСОКИЙ); digitalWrite (MD_2, LOW);} void left () {digitalWrite (MA_1, HIGH); digitalWrite (MA_2, LOW); digitalWrite (MB_1, ВЫСОКИЙ); digitalWrite (MB_2, LOW); digitalWrite (MC_1, LOW); digitalWrite (MC_2, ВЫСОКИЙ); 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, ВЫСОКИЙ); digitalWrite (MB_1, ВЫСОКИЙ); digitalWrite (MB_2, ВЫСОКИЙ); digitalWrite (MC_1, ВЫСОКИЙ); digitalWrite (MC_2, ВЫСОКИЙ); digitalWrite (MD_1, ВЫСОКИЙ); digitalWrite (MD_2, HIGH);} 
scanlinux.py Python
Сканировать последовательные порты 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__ ':вывести «Найденные порты:» для имени в scan ():напечатать имя 

Изготовленные на заказ детали и корпуса

Сценарий Python для отслеживания лиц OpenCV и код Arduino FaceTrakingCar.rar

Схема

При использовании Arduino для управления двигателями и сервоприводами расположение выводов может отличаться.

Производственный процесс

  1. Цифровые игральные кости Arduino
  2. Рулетка DIY 37 LED
  3. Мини-аркада ATtiny85:Змейка
  4. Переносимый детектор дальности
  5. MobBob:самостоятельный робот Arduino, управляемый смартфоном Android
  6. Робот-пианино, управляемый Arduino:PiBot
  7. Гальваника медью
  8. NeoMatrix Arduino Pong
  9. Всенаправленное отслеживание людей дружелюбного робота
  10. Создатель световой последовательности