В нашей лаборатории, с некоторых пор, живут тараканы. Если конкретнее — тараканы «Мёртвая голова» (Blaberus craniifer) (см. справку про данный вид таракана в конце статьи).
И решил я сделать для них экзоскелет.
Идея экзоскелета состоит в том, чтобы при помощи камеры отслеживать движения таракана и в соответствии с его перемещением — выдавать команды управления на моторы мобильной платформы.
За основу экзоскелета, взял шасси из конструктора Makeblock от робота Элвина.
В дело пошёл контроллер CraftDuino с мотор-шилдом, который был изготовлен из прото-шилда с прикрученным мотор-модулем на базе микросхемы L298.
DC-DC преобразователь с кнопкой включения, который используется для преобразования 12В от литий-ионного аккумулятора в 5В для питания одноплатного компьютера Raspberry Pi.
И разумеется, на роботе закрепил Raspberry Pi с модулем камеры и USB-хабом и Wi-Fi-свистком (для удалённого доступа к компьютеру).
Кроме того, на роботе присутствуют 2 ИК-датчика и 1 ультазвуковой дальномер, но в данный момент они не используются.
Получилась вот такая мобильная платформа и она же — экзоскелет для таракана:
На переднюю балку шасси (прямо под камерой), при помощи двухстороннего скотча закрепил пустое ведро от ПКЛ-а.
Это ведро будет рабочим пространством для таракана-водителя.
Чтобы таракан контрастнее выделялся на фоне — на дно ведра вырезал круг из белой бумаги, а чтобы таракан не убежал, края бортов ведра смазал вазелином (почерпнул этот метод у американских исследователей [1]).
Делаем несколько тестовых снимков таракана, чтобы на них подобрать пороги для его детектирования.
Напишем простой скрипт на Питоне, который использует открытую библиотеку компьютерного зрения OpenCV и адаптивное пороговое преобразования (cv2.adaptiveThreshold()) для детектирования таракана.
Подберём пороги при помощи ползунков, а для улучшения быстродействия выделем прямоугольник (зелёная рамка на скриншоте), где вообще нужно искать таракана (ROI).
def find_roach(img): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blockSize = cv2.getTrackbarPos('blockSize', 'roacha') C = cv2.getTrackbarPos('C', 'roacha') if blockSize % 2 == 0: blockSize = blockSize+1 print("blockSize: {0} C: {1}".format(blockSize, C)) bina = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize, C) cv2.imshow('roacha', bina)
тестовая картинка для поиска таракана:
Таракана нет:
Таракан есть:
Таракан обнаружен:
После порогового преобразования, выполняем поиск контуров (cv2.findContours()) и для найденного контура вычисляем прямоугольник, которым его можно обвести (cv2.boundingRect()).
findroach.py
def find_roach(img): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blockSize = 109 C = 53 x1 = 55 y1 = 16 x2 = 258 y2 = 219 print("blockSize: {0} C: {1}".format(blockSize, C)) bina = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize, C) cv2.imshow('roacha', bina) roi = bina[y1:y2, x1:x2] cv2.imshow('roach', roi) roi2 = img[y1:y2, x1:x2] contours, hierarchy = cv2.findContours(roi, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # Choose largest contour best = 0 maxsize = 0 count = 0 for cnt in contours: if cv2.contourArea(cnt) > maxsize : maxsize = cv2.contourArea(cnt) best = count count = count + 1 x,y,w,h = cv2.boundingRect(contours[best]) cv2.rectangle(roi2, (x,y), (x+w,y+h), (0,255,0), 2) cv2.circle(roi2, (x+w/2, y+h/2), 2, (0, 255, 0), -1) cv2.imshow('roi2', roi2)
Результат — наш таракан найден и обведён рамкой:
Теперь напишем скетч для контроллера CraftDuino, который принимает управляющие команды через последовательный порт и выдаёт соответствующие команды на управление моторами (вперёд-назад, вправо-влево, стоп).
Команды соответствуют стандартным для геймеров клавишам упавления движением: ‘w’, ‘s’, ‘a’, ‘d’ и ‘ ‘ — пробел для остановки.
void loop() { // read message from serial int c = 0; if(Serial.available()) { c = Serial.read(); if(c == 'w') { motor_drive(0, SPEED); motor_drive(1, SPEED); } else if(c == 's') { motor_drive(0, -SPEED); motor_drive(1, -SPEED); } else if(c == 'a') { motor_drive(0, SPEED); motor_drive(1, -SPEED); } else if(c == 'd') { motor_drive(0, -SPEED); motor_drive(1, SPEED); } else if(c == ' ') { motor_drive(0, 0); motor_drive(1, 0); } } }
Т.о., если скетч считает из последовательного порта символ ‘w’, то на моторы выдаётся команда «вперёд», и так далее.
Осталось адаптировать питоноский скрипт для работы не с картинкой, а с видеокамерой и добавить взаимодействие с CraftDuino через последовательный порт — при помощи модуля serial.
Итоговый скрипт — отслеживает таракана и выдаёт команды в последовательный порт:
roach_follow.py
prev_x = -1 prev_y = -1 while True: ret, frame = cap.read() #cv2.imwrite("frame.png", frame) x,y = find_roach(frame) print("x: {0} y: {1}".format(x, y)) if x != -1 and y != -1: if prev_x == -1 and prev_y == -1: prev_x = x prev_y = y if abs(prev_x - x) > 2 or abs(prev_y - y) > 2 : if x > prev_x : print("left") ser.write("a") elif prev_x > x : print("right") ser.write("d") if y > prev_y : print("back") ser.write("s") elif prev_y > y: print("forward") ser.write("w") else: print("stop") ser.write(" ") prev_x = x prev_y = y ch = cv2.waitKey(150) if ch == 27: break
Для обнаружения в какую сторону двигается наш таракан-водитель, скрипт запоминает — где он был задетектирован на прошлом кадре и, таким образом, определяет в какую сторону он сместился.
В результате, получился такой вот замечательный экзоскелет для таракана:
Делать и программировать этакую био-механическую кибер-штуковину было очень забавно.
Ни один таракан при изготовлении и испытании экзоскелета не пострадал.
Через некоторое время таракан, вернее, как оказалась — тараканиха — даже разродилась потомством.
Вот такой вот счастливый вышел финал.
Ссылки
проект на гитхабе — roach_driver
Справка о таракане:
Blaberus craniifer — вид южноамериканского таракана сем. Blaberidae рода Blaberus.
Название «Мёртвая голова» получил из-за рисунка находящегося на переднеспинке, который напоминает череп.
Ареал обитания — тропики Центральной и Южной Америки. Живет в лесной подстилке.
В дневное время суток насекомое скрывается в опавшей листве или около корней деревьев.
Активно избегают света. Питаются, в основном, листовым опадом.
Имеет крылья, которые позволяют таракану планировать.
Условия содержания: температура +28…39 градусов Цельсия, влажность воздуха от 60 до 70%.
В домашних условиях живёт от 1 до 2.5 лет.
В основном, приобретается как декоративное и кормовое насекомое (на корм паукам, ящерицам, хамелеонам, игуанам, змеям и т.п.).
Используются на тараканьих бегах.
Один из самых крупных тараканов: длина взрослой особи составляет 60—75 мм (крупные самки иногда до 80 мм).
Самки отличаются от самцов срастающимися последними сегментами брюшка с нижней стороны (характерный признак семейства).
Живородящи (яйцеживорождение), одна самка приносит до 30 нимф. Оотека инкубируется от 60 до 90 дней (в зависимости от температуры).
Личинка широкая, плоская, 6-7 мм в длину. После рождения, зарываются в субстрат и проводят в нём большую часть времени.
Личинки проходят от 9 до 13 стадий в развитии. Линяют, сидя на вертикальной поверхности. Время превращения нимфы во взрослое насекомое занимает 4-5 месяцев.Википедия
Blaberus craniifer
Blaberus
Литература
1. Brian R Tietz (2012) Models of Cockroach Shelter Seeking Implemented on a Robotic Test Platform (PDF)
По теме
OpenCV шаг за шагом. Обработка изображения — пороговое преобразование
OpenCV шаг за шагом. Нахождение контуров и операции с ними
RoboCraft на HackDay #34 в Калининграде
Сборка мощного моторшилда (на базе L298)
OpenCV шаг за шагом. Захват видео с камеры
Питание для Raspberry Pi
Подключение Raspberry Pi к Wi-Fi
Подключение модуля камеры к Raspberry Pi
Аквариум на колёсах на базе Arduino и Beagleboard
0 комментариев на «“Экзоскелет для таракана”»
А видео есть?
Сенсация! По лаборатории RoboCraft разгуливают тараканы-нацисты. Шокирующие эксперименты российских учёных.