Управляемая веб-камера или же web-cam-бот


Управляемая веб-камера
Не так давно я уже похвастался, что мою(и Zoltberg-а) статью про Arduino — «Веб-камера на сервоприводах» опубликовали в журнале Хакер. Статья уже выложена на их сайте и её можно прочитать здесь.

Вкратце расскажу про создание такой камеры.

Как видно на фотографии, я собрал поворотную основу для камеры из самых простых и дешёвых маленьких сервSG-90.
Камера крепится прямо к качалке верхней сервы, которая привинчивается к Г-образной загогулине, вылепленной из ПКЛ (поликапролактон — замечательный пластик для моделирования и прототипирования!). Эта же загогулина другим концом крепится к качалке второй сервы.

Основу я недолго думая вырезал из пластиковой бутылки 🙂 Хотя можно было бы вылепить из того же пластика ПКЛ 😉

Вот и вся механика. Очень просто и быстро. Использовать ПКЛ для таких поделок сплошное удовольствие. Но если у вас нет под рукой паяльной станции с феном, то нужно держать наготове чайник с кипятком 😉
Так же обратите внимание, что массивные детали из пластика будут размегчаться дольше, чем мелкие. Это можно наблюдать по цвету. Нагреваясь пластик становится прозрачным, а в глубине у него может оставаться белый стержень более холодного и твёрдого пластика.

Далее обе сервомашинки напрямую подключаются к 7 и 8 портам контроллера Arduino/CraftDuino :

В данном случае Arduino/CraftDuino играет роль шлюза, т.е. углы поворота сервомашинок передаются контроллеру по последовательному порту от управляющей программы на ПК, а Arduino просто получает значение угла поворота и поворачивает нужную серву на заданный угол.

Для работы с сервомашинками воспользуемся библиотекой Servo, а для общения с контроллером через последовательный порт используем библиотеку Firmata, которая так же как и библиотека Servo уже входит в стандартный набор библиотек Arduino IDE.

Вот какая программа для Arduino у нас получится (фактически — это немного модифицированный пример, поставляемый с библиотекой Firmata)

#include <Firmata.h>
#include <Servo.h>

Servo servo7;
Servo servo8;

void analogWriteCallback(byte pin, int value)
{
    if(pin == 7)
      servo7.write(value);
    if(pin == 8)
      servo8.write(value);
}

void setup() 
{
    Firmata.setFirmwareVersion(0, 2);
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

    servo7.attach(7);
    servo8.attach(8);
   
    Firmata.begin(9600);
}

void loop() 
{
    while(Firmata.available())
        Firmata.processInput();
}

Вот и всё — механика и электроника готовы и остаётся только написать программу для управления этим мини-роботом!

Так как дальнейшие планы научить этого мини-web-cam-бота самостоятельно обнаруживать объекты и следить за ними, то для работы с камерой я воспользуюсь библиотекой OpenCV.

Управляющая программа довольно простая.
Подключаемся к web-камере и показывам её картинку. Так же выведем в окошко с картинкой пару ползунков, с помощью которых будем управлять положением сервомашинок.

Так как в моей конструкции робота web-камеру пришлось закрепить на боку, то в программе приходится это исправлять (поворачивать картинку на 90 градусов против часовой стрелки).
Эта процедура реализуется функцией rotate(), которая является обёрткой вокруг функции OpenCV: cvWarpAffine(), которая и выполняет поворот изображения (Аффинное преобразование).

//
// программа для управления 
// сервомашинками мини-web-cam-бота
// 
// robocraft.ru

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

#include "serial.h"

Serial sg; // для работы с COM-портом

// положение 1-й сервы
int A = 0;
int Amax = 180;

// положение 2-й сервы
int F = 0;
int Fmax = 180;

IplImage* dest = 0;

//
// функции-обработчики ползунков
//
void myTrackbarA(int pos) {
	A = pos;
	// Firmata
	char buf[3];
	buf[0] = 0xE0 | 7;
	buf[1] = A & 0x7F;
	buf[2] = (A >> 7) & 0x7F;
	sg.Send(buf, 3);
	Sleep(100);
}

void myTrackbarF(int pos) {
	F = pos;
	// Firmata
	char buf[3];
	buf[0] = 0xE0 | 8;
	buf[1] = F & 0x7F;
	buf[2] = (F >> 7) & 0x7F;
	sg.Send(buf, 3);
	Sleep(100);

}

// функция поворота изображения на заданный угол
void rotate(IplImage* _image, double _angle=90)
{
	// матрицы трансформации
	CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1);
	// вращение относительно центра изображения
	CvPoint2D32f center = cvPoint2D32f(_image->width/2, _image->height/2);
	double angle = _angle;
	double scale = 1;
	cv2DRotationMatrix(center,angle,scale,rot_mat);
	
	IplImage* Temp = 0;
	Temp = cvCreateImage(cvSize(_image->width, _image->height) , _image->depth, _image->nChannels);

	// выполняем вращение
	cvWarpAffine(_image,Temp,rot_mat);

	// сохраняем результат
	cvCopy(Temp, _image);

	cvReleaseImage(&Temp);
	cvReleaseMat(&rot_mat);
}

int main(int argc, char* argv[])
{
	// получаем любую подключённую камеру
	CvCapture* capture = cvCaptureFromCAM(CV_CAP_ANY);
	assert( capture );

	// устанавливаем ширину и высоту кадра
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);//1280); 
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);//960); 


	IplImage* frame=0;

     // окно для вывода изображения
	cvNamedWindow("capture", CV_WINDOW_AUTOSIZE);

	// инициализация COM-порта
	int port=19; // номер виртуального COM-порта Arduino
	printf("[i] try to open COM-port %d\n", port);
	bool b = sg.Open(port, 9600);
	if(!b)
	{
		printf("[!] Error open COM-port!\n");
		return 1;
	}
	printf("[i] ok\n");

	// добавляем ползунки для управления положением сервомашинок
	cvCreateTrackbar("A", "capture", &A, Amax, myTrackbarA);
	cvCreateTrackbar("F", "capture", &F, Fmax, myTrackbarF);

     // цикл обработки кадров с камеры
	while(true){
		// получаем кадр
		frame = cvQueryFrame( capture );
          // копируем изображение
		dest = cvCloneImage(frame);

		// поворачиваем картинку на 90 градусов
		rotate(dest);

		// показываем
		cvShowImage("capture", dest);

		// освобождаем изображение
		cvReleaseImage(&dest);
	
		char c = cvWaitKey(33);
		if (c == 27) { // нажата ESC
			break;
		}
	}
	// освобождаем ресурсы
	sg.Close();
	cvReleaseCapture( &capture );
	cvDestroyWindow("capture");
	return 0;
}

Вот и всё!
Главное — желание и хорошая идея! 😉

исходники к статье можно скачать по адресу:
/files/opencv/servobot/servobot.zip


24 комментария на «“Управляемая веб-камера или же web-cam-бот”»

  1. а с serial.h случайм serial.lib и serial.dll нет???, а то чёто ругается на неразрешенные внешние элементы… и она тока для Arduino или можно с чем угодно юзать?

    • исходники класса Serial есть в архиве. Ничего дополнительного ему не требуется. Как я уже указал — для передачи углов поворота используется протокол Firmata, но от него можно отказаться и использовать что-то другое — для этого нужно просто изменить содержимое функций

      void myTrackbarA(int pos);
      void myTrackbarF(int pos);
  2. В общем остаточно оригинально и технически интересно, но имхо можно было бы и по красивей. Например самая нижняя серва отвечает не за горизантальный а за вертикальный угол, к ней в притык серва за горизонталь, камера весит на трубке. Тогда весь механизм и электронику можно спрятать в коробку с прорезью, и снаружи только камера. Так красивей смотреться будет.

  3. Я конечно извиняюсь, но конструкция у вас выглядит как-то не очень 🙂
    Я тож управляемую камеру делал (это наверное первая мысля у всех ардуиновцев, купивших первую серву), но управление по сети. Мало того — из браузера. Ардуина пашет независимо от компа, спасибо езернет шылду. Перемещение либо клавишами вверх-вниз-влево-вправо, либо мышой щёлкать по соответсвующим ссылкам. Но намного интересней пропорциональное управление — в брауере нарисован квадрат, все движения мыши с нажатой левой кнопкой фиксируются и пишутся в БД, откуда читаются и обрабатываются ардуиной.

    Пара ссылок на эту мою управляемую хреновинку. Первая ссылка эт первый рабочий вариант, там сервы местами перепутаны были 🙂 Вторая ссылка — видеоролик уже с окончательной крутилкой, правда я там больше процесс движения камеры снимал, а не само управление. Вроде виден там зелёный квадрат для управления.
    http://www.g0l.ru/blog/n2436
    http://www.g0l.ru/blog/n2446

    Сейчас камера отключена, ибо хочу доработать механику и на балкон поставить. Скетчи тож пока не выкладываю, ибо там сплошь тестовый говнокод 😀 Но вот свою капельку опыта подкидываю, мож кому пригодится.

    • Отличная работа! На счёт конструкции вы правы — просто делал всё очень быстро — хотел по-быстрее реализовать идею. Нужно будет переделать 🙂
      Управление через Ethernet-шылд — тоже супер. Но у меня в планах добавить обработку видео и реализовать слежение за объектом 😉

  4. Статья была написана больше года назад… но надеюсь мне ещё ктонибудь ответит… Пытался повторить вышеуказаный проект у себя, в качестве языка программирования использовал JavaSE в связке с библиотекой RXTX для общения по COM порту… столкнулся с проблеммой, как передавать сообщение контроллеру… Дело в том что функция myTrackbarF передает сообшения в виде массива char, а Java может отправлять либо массив байт, либо число типа int… Пробовал явное приведение типов (byte) char, никакого эффекта не получил… пробовал передавать последовательно 3 числа тоже не проходит… Подскажите как можно передать данные так, чтобы Firmata их схавал… Заранее спасибо.

    • Всё, разобрался — моя ошибка незнание… byte — это тоже по сути своей char, только в числовом представлении… а сообщение у меня отправлялось… вот только отправлял я его всего один раз… А при первой отправки данных контроллеру он их куда то теряет, зато все последующие идут прямо на ура)

    • уж точно не больше года назад, а в конце 2010-го :)))))
      хм… а в примере как передаётся?

      char buf[3];
              buf[0] = 0xE0 | 7;
              buf[1] = A & 0x7F;
              buf[2] = (A >> 7) & 0x7F;
              sg.Send(buf, 3);

      — передаётся тот же массив байт О_о

  5. Доброго времени суток. Подскажите, как следует искать нужные точки на изображении и по ним уже делать поворот? Например что бы книга всегда была в вертикальном положение. Центрировать ее как то по углам же надо? Меня интересует поиск таких точек и дальнейший поворот на основе этих точек.

  6. Здравствуйте, а можно ли подключить еще одну серво-машинку (третью) чтобы она поворачивалась на запрограммированный угол когда камера находит движущийся объект? это нужно прописать в ардуино, но и в опен Cv? какие строки добавить и куда, спасибо

    • Привет! Можно. Разумеется, нужно будет прописать обработку и на контроллер Arduino и в программу на ПК.

    • я просто хотел чтоб вы дописали код под третью серву конечно не за просто так.

    • Программа одна написана для ардуино, а другая я так понял для питона 2.

    • В данном случае, приводится программа на C++, но, разумеется, ничего не мешает реализовать подобное и на питоне.

    • А лучше этот проект на чем запускать?

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение