Управляємо веб-камерою за допомогою джойстика


Доброго дня. Мотивовану численними постами на Хабре про саморобних роботах вирішив зробити і що-небудь своє більш менш вартісне і цікаве.

Взагалі роботами я захоплююся давно, але до нормального проекту руки не доходили, в основному тільки грався. Трохи подумавши, придумав свій проект, пошукав деталі, намалював ескізи, пофантазував на тему майбутніх можливостей робота. Деталі замовити не відомому сайті, і поки деталі долають шлях з-під неба вирішив реалізувати один з модулів майбутнього робота з того що є під рукою. Вірніше навіть не реалізувати сам модуль, а зібрати прототип і написати софт, щоб потім не відволікатися на написання програми, та й тим більше поки йдуть всі деталі є море вільного часу, а бажання що-небудь зробити, не дає спокою.







Під рукою у мене виявилася хустки Arduino Diecimila, кілька сервоприводів, веб-камера, джойстик і ультразвукової далекомір. Відповідно відразу виникло бажання зробити «комп'ютерний зір» на основі веб-камери, з можливістю як автономної роботи, так і ручного управління (джойстиком).

Що мене спонукало написати цю статтю?


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

Завдання ж тривіальна, надсилати інформацію з джойстика на Arduino, яка на певний кут буде повертати 2 сервоприводу з прикріпленою веб-камерою, і в разі потреби зчитувати інформацію з далекоміра, відсилаючи її в SerialPort.
Обміркувавши всі ще раз, вирішив приступити до створення даного прототипу самостійно. Поїхали!

Основна частина

збірка прототипу


Прототип був створений протягом 5 хвилин. Зовнішній вигляд прототипу не цікавить взагалі, основна його мета - відпрацювання програмної частини до приїзду деталей для робота.
А зробив я його з першою-ліпшою баночки з під якихось вітамінів, двох сервоприводів, веб-камери, скріпки, ізоляційної стрічки і клейового пістолета. Вийшло таке:

Управляємо веб-камерою за допомогою джойстика

Збірка завершена, сервоприводи і ультразвукової далекомір підключені до Arduino, Arduino до ПК, приступаємо до програмування Arduino.

програмуємо Arduino

Забігаючи трохи вперед відразу скажу, тут і сталася помилка, до якої мені довелося повернутися вже після написання програми на C #. Помилка була ось у чому - я, наївний і повний ентузіазму, написав програму яка розбирає надходить в Serial Port рядок приблизно наступного вигляду «90:90» на дві частини, відповідно перша частина це градуси по координаті X, друга частина Y. За допомогою монітора порту все було відтестувати і працювало прекрасно, але коли була написана програма для управління з джойстика, при посиленій атаці порту рядками до мінливих значеннями, Arduino просто не встигала прочитувати все послідовно, тому часто рядки перетворювалися в «0: 909», «: 9090" і тому п одобное.






Відповідно сервоприводи божеволіли і брали всі положення, крім тих, що потрібні нам.

Тому, не довго думаючи, я прийшов до висновку що нам потрібен символ початку рядка і символ кінця рядка. Знову ж, не довго думаючи, символом початку рядка був обраний перший символ латинського алфавіту - «a», кінцем рядка останній - «z», а символи початку значень осей «x» і «y» відповідно. Разом вхідний рядок приймала такий вигляд: «ax90y90z».

Все б добре, якби не далекомір. Далекомір ультразвукової, відстань він визначає на ура, але є кілька нюансів. По-перше, якщо кут між далекоміром і стіною гостріше 45 градусів (плюс-мінус), то звук відбивається від стіни по дотичній, і значення, не відповідає дійсності. По-друге досить великий кут випускання сигналу, близько 30 градусів (по мануалу), а змиритися відстань до найближчого об'єкта, благо що сигнал від об'єктів до яких датчик знаходиться під кутом, відбивається в іншу сторону, і ми отримуємо більш менш реальне відстань по прямій , але перешкоди все ж бувають, і досить часто. Тому я дописав ще одну функцію, яка бере n вимірів відстані, складає їх і ділить на кількість, виставив n = 10, так перешкоди стали більш згладжені і менш помітні.

Код на Arduino був тут же переписаний і прийняв такий вигляд:

Проблема з неправильним розбором координат зникла на зовсім, 100 з 100 випробувань пройдені успішно.

Основна керуюча програма (C #)


Спочатку хотів писати все на C ++ під Qt, але надалі все ж довелося писати на C #, ну да ладно.

Що хотілося отримати:
1. Розпізнавання облич людей.
2. Стеження за обличчям людини.
3. Ручне управління за допомогою джойстика.
4. Визначення відстані до об'єкта.

Для розпізнавання осіб і виведення зображення з веб-камери, без всяких питань, була обрана бібліотека OpenCV, а вірніше її оболонка для C # - Emgu CV.

Для зчитування положення джойстика по початку використовувалася бібліотека Microsoft.DirectX.DirectInput, яка мені страшенно не сподобалася, і я застосував бібліотеку SharpDX, до того ж досить успішно.

Що потрібно від програми:
1. Захоплювати зображення з веб-камери і виводити його на екран.
2. Розпізнавати особи на зображенні, обводити їх і отримувати координати особи на зображенні.
3. Формувати рядок виду «ax90y90z» і відправляти її в Serial Port для управління сервоприводами.
4. Зчитувати значення положення джойстика.
5. Зчитувати показання з далекоміра.

Сформулювавши завдання, приступаємо до програмування.

Бібліотечка SharpDX дозволяє нам знаходити підключений джойстик і отримувати з нього значення осей (від 0 до 65535), натискання і відпускання клавіш джойстика. Сервоприводи можуть повертатися від 0 до 180 градусів, відповідно потрібно перетворювати значення осей джойстика від 0 до 180. Я просто поділив повертається значення на 363, і отримав на виході значення від 0 до 180. Далі написав функцію яка формує рядок положення сервоприводів і відправляє її в порт.

Висновок зображення і розпізнавання осіб написані з використанням OpenCV і нічого складного не уявляють (для нас).

Далі цікавіше, маючи під рукою далекомір, звичайно ж захотілося зробити радар, і побудувати хоч якусь приблизну картину місцевості.

Повторивши тригонометрію і вектора, написав процедуру, яка обчислює координати точки відносно нашого далекоміра з камерою по куту повороту сервоприводу і відстані до об'єкта, і малює отримані результати в PictureBox, по кнопці запускаю процедуру в потоці, все працює, але все ж через рельєфу кімнати виходять досить великі перешкоди, але приблизний обрис збігається з дійсністю. Намагався згладжувати дані з датчика, вибираючи лише пікові значення і малюючи між ними відрізки, в принципі вийшло не погано, але вирішив відмовитися від цього, так як часто піковими значеннями стають саме перешкоди.

У підсумку отримуємо все, що хотіли. Комп'ютер розпізнає обличчя і автоматично стежить за ними. ручне управління джойстиком працює на ура. Радар, хоч і не зовсім точно, але працює. Основні функції модуля зору робота відпрацьовані і залишається лише допрацьовувати і вдосконалити їх.


Ось, що вийшло по завершенні.

висновок


Виявилося все досить просто. Мета досягнута, прототип готовий. Є над чим працювати і зайнятися у вільний час, чекаючи посилку з компонентами для робота.

Плани на майбутнє


Наступним кроком буде побудова колісної платформи для робота, настройка віддаленого управління (WiFi, 3G). навішування датчиків (температура, тиск та інше), синтез мови. У списку бажань так само є плани з приводу механічної руки.

Думаю, якщо буде інтерес до даної статті і її продовження, то воно обов'язково піде! Виправлення і критика вітаються!

Дякую за увагу!