Для начала ролик с youtube для вдохновения:
Предупреждение: проект на видео — лишь образец, который можно сделать по туториалу в статье в части стереозрения и «поворотов головой». Танки с пультами xbox не прилагаются.
Не смотря на наглядность, скудный рассказ самого автора проекта на видео и наличие ссылок, сходу разобраться как все это работает непросто. Если есть желание собрать что-то подобное и в гораздо более удобном формате, рекомендуется к прочтению.
*Сразу оговорюсь, человек на ролике с ютюб мне незнаком, никаких секретных данных не передавал, в каком состоянии находится его проект сейчас, мне не известно.
**Делать управление движением робота на raspberry по поверхности через пульт от xbox мы не будем, с этим можно справиться самостоятельно.
***Просьба лапти не кидать, так как проект пока находится в разработке.
Итак, нас интересует две вещи:
Концепция, которая используется в ролике, если обобщить выгдядит так:
Все просто. Но diablo, как известно, в деталях и неудобствах, а именно:
Поэтому пересядем на stereopi, благо она появилась в российских магазинах (надеюсь, после этого поста не исчезнет):
Stereopi — это разработка нашего соотечественника, которая сейчас активно завоевывает рынок.
Прелесть ее вытекает из названия — можно подключить 2-е CSI камеры raspberry pi одновременно. При этом все это работает на базе одного raspberry pi Compute Module. К сожалению, сам модуль не входит в комплект, его надо покупать самостоятельно.
О stereopi есть статьи на Хабре.
От нее нам понадобятся 2-а видео потока и управление сервами через GPIO.
В качестве базы для stereopi будем использовать Raspberry Pi Compute Module 3+.
После сборки stereopi (вставка compute module в stereopi, камер), зальем софт.
Используем уже готовый образ для raspberry pi compute module — Raspbian (stretch). Он есть на сайте stereopi.com — Raspbian Stretch OpenCV image, Google Drive
Зальем его в raspberry.
Если есть сложности с заливкой, иные идем на wiki stereopi.
Проинсталлируем ПО webrtc на stereopi. Частично материал по установке взят с этой страницы: Installation for ARM (Raspberry Pi)
Избежим излишних комментариев, которые уже есть на вышеуказанной странице и попросту установим все, что потребуется.
Теперь надо (в инструкции это есть) сформровать ssl-ключи, так как Chrome может не показывать видео через соединение http (только через https):
*при формировании ключей будут задаваться вопросы о компании, регионе и т.п. — можно отвечать на них произвольно.
Сформированные ключи (selfsign.key и selfsign.crt появятся в текущей папке) надо положить в папку:
Все настройки webrtc хранятся в 2-х файлах:
Чтобы не утомлять перечислением позиций в файлах, которые необходимо раскоментировать или
подправить, перезапишем файлы настроек своими uv4l-raspicam.conf и uv4l-raspidisp.conf.
Перезагрузим raspberry и зайдем с телефона по ip raspberry, используя chrome:
WebRTC представляет из себя целый веер возможностей, но ограничимся одной — перейдем по вкладке webrtc:
Теперь проверим, работает ли видео со stereopi.
Нажмем внизу web страницы на телефоне кнопку «Call».
Должно появиться видео со стереокамер.
Нажмем на кнопку «Fullscreen» под окном с изображением с web-камер:
*Страницу на телефоне не перезагружать! Если все же это случилось, надо убить процессы на raspberry:
И перезагрузить сервисы на ней же:
Далее заново на странице в браузере телефона нажать «Call».
**Call не будет работать, если к raspberry не подключена камера.
Чтобы управлять сервами на raspberry с телефона понадобится код, который будет запускаться на raspberry, и действия на телефоне.
Но сначала определимся с сервами. В ютюб ролике используются сервы, подключенные к gpio raspberry напрямую. Так как сервы маломощные, пожалуй можно повесить 2 сервы на gpio raspberry. Эти трюки можно с легкостью проводить над сервами sg-90. Они не требовательны по питанию, но и не особо хороши для нагрузок. В принципе их должно быть достаточно, чтобы держать подвес с двумя камерами от stereopi. Сам подвес можно купить на том же aliexpress, по поиску «pan-tilt». Однако у этих серв есть так же серьезный минус — они «дрожат от страха». Именно этот эффект и наблюдает автор ролика с ютюб. Почему это происходит и что с этим делать не будем рассматривать здесь.
В нашем случае используются сервы mg-996n и сустав робота, который, надеюсь, ему в ближайшее время не понадобится.
*Mg-996N не «дрожат».
Stereopi имеет расположение gpio сходное со стандартным на raspberry 3.
Поэтому сигнальные провода от серв пойдут на gpio, а 5V лучше взять не с raspberry, а со стороны, GND серв объединить с GND raspberry и GND внешнего источника.
На raspberry нам понадобится демон, но не лермонтовский, а pigpio. Никаких особых действий по его настройке предпринимать не нужно, главное знать, что он висит на порту 8888 и его предварительно надо запустить:
Далее создадим файл, который и будет управлять сервами, получая данные с сокета, который сам же и создает:
В тексте оставлены комменты, чтобы понять, откуда код родился и, что еще можно подправить.
Общий смысл кода следующий:
*Проблема заключается втом, что x принимает значения от 0 до 360 (поворот телефона вокруг своей оси), как и y. И эти значения надо привязать к PWM, которые принимают значения от 1000 до 2000. В коде используется формула pitchPW = key1*5+500. 500 — это минимальное значение PWM servo (хотя в коде допущение 1000). И умножение на 5 условно. Этот момент требует доработки, так как при x=360, значение PWM выше максимального в разы. Сервы защищены от выхода за максимальные углы поворота во избежание их повреждения, но это не сильно радует.
Запустим код в терминале raspberry:
На телефоне включим GPS (в каждом телефоне есть соответствующий значок в настройках) и зайдем по ip raspberry.
Нажмем «Call». После того как соединение установится, на телефоне в браузере на странице поставим галочку «send device orientation angles alpha, beta, gamma».
В терминал со скриптом поедут значения x. И, если повращать телефоном, они будут изменяться.
Также будут двигаться сервы.
*На текущий момент одна из них (вторая закоментирована).
Из приятных бонусов webrtc также дает возможность:
1. Схалтурить, соединив на школьной линейке две разные камеры с рыбьими глазами не получилось. У рыб, оказывается, бывают разные глаза. Нужны однотипные камеры:

2. Развернуть картинку со стереокамер через настройки web-интерфейса webrtc не удалось. Пока картинки узковаты, как штаны француза.

3. Сервы MG996N ограничены углами поворота -180. По факту — 160. Возможно, кто-то посоветует с 360, но без continuous rotation.
4. Софт требует шлифовки.
5. Call иногда отваливается, приходится переподключаться.
Приложение:
Предупреждение: проект на видео — лишь образец, который можно сделать по туториалу в статье в части стереозрения и «поворотов головой». Танки с пультами xbox не прилагаются.
Не смотря на наглядность, скудный рассказ самого автора проекта на видео и наличие ссылок, сходу разобраться как все это работает непросто. Если есть желание собрать что-то подобное и в гораздо более удобном формате, рекомендуется к прочтению.
*Сразу оговорюсь, человек на ролике с ютюб мне незнаком, никаких секретных данных не передавал, в каком состоянии находится его проект сейчас, мне не известно.
**Делать управление движением робота на raspberry по поверхности через пульт от xbox мы не будем, с этим можно справиться самостоятельно.
***Просьба лапти не кидать, так как проект пока находится в разработке.
Итак, нас интересует две вещи:
- как получить стерео картинку на телефон в шлеме;
- как управлять сервами поворотами головы.
Концепция, которая используется в ролике, если обобщить выгдядит так:
- 2 raspberry pi посылают видеопотоки в сеть со своих камер через сервисы webrtc;
- телефон (в шлеме) принимает потоки в 2 одинаковых приложения на телефоне — float apps.
- одновременно телефон управляет сервами, подключенными к raspberry.
Все просто. Но diablo, как известно, в деталях и неудобствах, а именно:
- надо запускать 2 raspberry, следить за настройками 2-х камер, питание raspberry * 2.
- float apps постоянно сползают в телефоне, приходится выравнивать картинки на экране.
- ...
Поэтому пересядем на stereopi, благо она появилась в российских магазинах (надеюсь, после этого поста не исчезнет):
Stereopi — это разработка нашего соотечественника, которая сейчас активно завоевывает рынок.
Прелесть ее вытекает из названия — можно подключить 2-е CSI камеры raspberry pi одновременно. При этом все это работает на базе одного raspberry pi Compute Module. К сожалению, сам модуль не входит в комплект, его надо покупать самостоятельно.
О stereopi есть статьи на Хабре.
От нее нам понадобятся 2-а видео потока и управление сервами через GPIO.
В качестве базы для stereopi будем использовать Raspberry Pi Compute Module 3+.
Подготовка stereopi
После сборки stereopi (вставка compute module в stereopi, камер), зальем софт.
Используем уже готовый образ для raspberry pi compute module — Raspbian (stretch). Он есть на сайте stereopi.com — Raspbian Stretch OpenCV image, Google Drive
Зальем его в raspberry.
Если есть сложности с заливкой, иные идем на wiki stereopi.
Установка webrtc.
Проинсталлируем ПО webrtc на stereopi. Частично материал по установке взят с этой страницы: Installation for ARM (Raspberry Pi)
Избежим излишних комментариев, которые уже есть на вышеуказанной странице и попросту установим все, что потребуется.
curl http://www.linux-projects.org/listing/uv4l_repo/lpkey.asc | sudo apt-key add - sudo nano /etc/apt/sources.list deb http://www.linux-projects.org/listing/uv4l_repo/raspbian/stretch stretch main sudo apt-get update sudo apt-get install uv4l uv4l-raspicam sudo apt-get install uv4l-raspicam-extras sudo raspi-config далее Anvanced Options далее Memory Split далее написать 256 и нажать enter sudo apt-get install uv4l-server uv4l-uvc uv4l-xscreen uv4l-mjpegstream uv4l-dummy uv4l-raspidisp sudo apt-get install uv4l-webrtc sudo apt-get install uv4l-demos sudo apt-get install uv4l-xmpp-bridge sudo apt-get install uv4l-raspidisp-extras
Теперь надо (в инструкции это есть) сформровать ssl-ключи, так как Chrome может не показывать видео через соединение http (только через https):
openssl genrsa -out selfsign.key 2048 && openssl req -new -x509 -key selfsign.key -out selfsign.crt -sha256
*при формировании ключей будут задаваться вопросы о компании, регионе и т.п. — можно отвечать на них произвольно.
Сформированные ключи (selfsign.key и selfsign.crt появятся в текущей папке) надо положить в папку:
/etc/ssl/private/
Все настройки webrtc хранятся в 2-х файлах:
/etc/uv4l/uv4l-raspicam.conf /etc/uv4l/uv4l-raspidisp.conf
Чтобы не утомлять перечислением позиций в файлах, которые необходимо раскоментировать или
подправить, перезапишем файлы настроек своими uv4l-raspicam.conf и uv4l-raspidisp.conf.
Перезагрузим raspberry и зайдем с телефона по ip raspberry, используя chrome:
https://192.168.1.100:8080
WebRTC представляет из себя целый веер возможностей, но ограничимся одной — перейдем по вкладке webrtc:
картинка


Теперь проверим, работает ли видео со stereopi.
Нажмем внизу web страницы на телефоне кнопку «Call».
картинка


Должно появиться видео со стереокамер.
Нажмем на кнопку «Fullscreen» под окном с изображением с web-камер:
картинка


*Страницу на телефоне не перезагружать! Если все же это случилось, надо убить процессы на raspberry:
sudo killall uv4l
И перезагрузить сервисы на ней же:
sudo service uv4l_raspidisp restart sudo service uv4l_raspicam restart
Далее заново на странице в браузере телефона нажать «Call».
**Call не будет работать, если к raspberry не подключена камера.
Разберемся с сервами.
Чтобы управлять сервами на raspberry с телефона понадобится код, который будет запускаться на raspberry, и действия на телефоне.
Но сначала определимся с сервами. В ютюб ролике используются сервы, подключенные к gpio raspberry напрямую. Так как сервы маломощные, пожалуй можно повесить 2 сервы на gpio raspberry. Эти трюки можно с легкостью проводить над сервами sg-90. Они не требовательны по питанию, но и не особо хороши для нагрузок. В принципе их должно быть достаточно, чтобы держать подвес с двумя камерами от stereopi. Сам подвес можно купить на том же aliexpress, по поиску «pan-tilt». Однако у этих серв есть так же серьезный минус — они «дрожат от страха». Именно этот эффект и наблюдает автор ролика с ютюб. Почему это происходит и что с этим делать не будем рассматривать здесь.
В нашем случае используются сервы mg-996n и сустав робота, который, надеюсь, ему в ближайшее время не понадобится.
Картинка


*Mg-996N не «дрожат».
Stereopi имеет расположение gpio сходное со стандартным на raspberry 3.
Поэтому сигнальные провода от серв пойдут на gpio, а 5V лучше взять не с raspberry, а со стороны, GND серв объединить с GND raspberry и GND внешнего источника.
Теперь самое главное, софт
На raspberry нам понадобится демон, но не лермонтовский, а pigpio. Никаких особых действий по его настройке предпринимать не нужно, главное знать, что он висит на порту 8888 и его предварительно надо запустить:
sudo systemctl start pigpiod.service
Далее создадим файл, который и будет управлять сервами, получая данные с сокета, который сам же и создает:
datachannel_server_tele.py
# python 3 # Taken from: # https://stackoverflow.com/questions/45364877/interpreting-keypresses-sent-to-raspberry-pi-through-uv4l-webrtc-datachannel # based on: # https://raspberrypi.stackexchange.com/questions/29480/how-to-use-pigpio-to-control-a-servo-motor-with-a-keyboard # public domain # systemctl status pigpiod.service # sudo systemctl start pigpiod.service # goto http://raspberrypi:8080/stream/webrtc and press Call! # video from raspberry pi appear # run from cmd raspberry: sudo python3 datachannel_server.py # turn on gps on phone # put V on 'send device orientation' from phone import socket import time import pigpio import os import re import json socket_path = '/tmp/uv4l.socket' try: os.unlink(socket_path) except OSError: if os.path.exists(socket_path): raise s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) ROLL_PIN = 4 #gpio PITCH_PIN = 17 #gpio ! not phisical pin YAW_PIN = 15 MIN_PW = 1000 # 0 degree MID_PW = 1500 # 90 degree MAX_PW = 2000 # 180 degree print ('socket_path: %s' % socket_path) s.bind(socket_path) s.listen(1) def cleanup(): pi.set_servo_pulsewidth(ROLL_PIN, 0) pi.set_servo_pulsewidth(PITCH_PIN, 0) pi.set_servo_pulsewidth(YAW_PIN, 0) pi.stop() while True: print ('awaiting connection...') connection, client_address = s.accept() print ('client_address %s' % client_address) try: print ('established connection with', client_address) pi = pigpio.pi() #pi = pigpio.pi('soft', 9080) rollPulsewidth = MID_PW pitchPulsewidth = MID_PW yawPulsewidth = MID_PW pi.set_servo_pulsewidth(ROLL_PIN, rollPulsewidth) pi.set_servo_pulsewidth(PITCH_PIN, pitchPulsewidth) pi.set_servo_pulsewidth(YAW_PIN, yawPulsewidth) while True: try: data = json.loads(connection.recv(200).decode('utf-8')) # dict except ValueError: # no data return continue # data #{"do":{"alpha":0.1,"beta":-0.3,"gamma":-0.2,"absolute":false}, # "dm":{"x":0,"y":0,"z":-0.2,"gx":0,"gy":0,"gz":-9.6,"alpha":-0.1,"beta":-0.1,"gamma":0.1} #print ('received message"%s"' % data) #print ('received message"%s"' % data['dm']['x']) # coordinate x from data #print ('received message"%s"' % data['dm']['y']) # coordinate y from data time.sleep(0.01) key1 = float(data['do']['alpha']) # os x 0 to 360 degree #key2 = float(data['do']['beta']) # os y #print(key1) #print(key2) rollPW = rollPulsewidth pitchPW = pitchPulsewidth yawPW = yawPulsewidth pitchPW = key1*5+500 print ('x: '+str(pitchPW)) #if pitchPW > MAX_PW: # pitchPW = MAX_PW #elif pitchPW < MIN_PW: # pitchPW = MIN_PW #rollPW = int(key2 + 1000) #print ('y: '+ str(int(rollPW))) #if rollPW > MAX_PW: # rollPW = MAX_PW #elif rollPW < MIN_PW: # rollPW = MIN_PW if rollPW != rollPulsewidth: rollPulsewidth = rollPW pi.set_servo_pulsewidth(ROLL_PIN, rollPulsewidth) if pitchPW != pitchPulsewidth: pitchPulsewidth = pitchPW pi.set_servo_pulsewidth(PITCH_PIN, pitchPulsewidth) if yawPW != yawPulsewidth: yawPulsewidth = yawPW pi.set_servo_pulsewidth(YAW_PIN, yawPulsewidth) #if data: #print ('echo data to client') #connection.sendall(str(data)) #else: #print ('no more data from', client_address) #break finally: # Clean up the connection cleanup() connection.close()
В тексте оставлены комменты, чтобы понять, откуда код родился и, что еще можно подправить.
Общий смысл кода следующий:
- при старте сервы выставляются в среднее положение.
- есть 3 пина (gpio), на которых висят сигнальные провода серв. В нашем случае 2 пина (подвес из 2 серв).
- gpio управлются путем подачи сигнала в диапазоне PWM от 1000 до 2000.
- с телефона прилетает строка, которая парсится json (можно чем-то еще), далее из нее берутся значения x и y. Далее эти значения переводятся в значения PWM для поворота сервы.
*Проблема заключается втом, что x принимает значения от 0 до 360 (поворот телефона вокруг своей оси), как и y. И эти значения надо привязать к PWM, которые принимают значения от 1000 до 2000. В коде используется формула pitchPW = key1*5+500. 500 — это минимальное значение PWM servo (хотя в коде допущение 1000). И умножение на 5 условно. Этот момент требует доработки, так как при x=360, значение PWM выше максимального в разы. Сервы защищены от выхода за максимальные углы поворота во избежание их повреждения, но это не сильно радует.
Запустим код в терминале raspberry:
sudo python3 datachannel_server_tele.py
На телефоне включим GPS (в каждом телефоне есть соответствующий значок в настройках) и зайдем по ip raspberry.
https://192.168.1.100:8080/stream/webrtc
Нажмем «Call». После того как соединение установится, на телефоне в браузере на странице поставим галочку «send device orientation angles alpha, beta, gamma».
В терминал со скриптом поедут значения x. И, если повращать телефоном, они будут изменяться.
Также будут двигаться сервы.
*На текущий момент одна из них (вторая закоментирована).
Из приятных бонусов webrtc также дает возможность:
- создать подобие телемоста между телефоном и raspberry (ваш собеседник будет объемным),
- транслировать звук в обе стороны (не проверялось, но в настройках учтено),
- стримить на web-страницу, youtube в 3d.
- создать конферец-call из нескольких товарищей (jitsi meet).
- через web-интерфейс на лету менять настройки камер (почему не работает rotate!&?).
Теперь о грустном.
1. Схалтурить, соединив на школьной линейке две разные камеры с рыбьими глазами не получилось. У рыб, оказывается, бывают разные глаза. Нужны однотипные камеры:

2. Развернуть картинку со стереокамер через настройки web-интерфейса webrtc не удалось. Пока картинки узковаты, как штаны француза.

3. Сервы MG996N ограничены углами поворота -180. По факту — 160. Возможно, кто-то посоветует с 360, но без continuous rotation.
4. Софт требует шлифовки.
5. Call иногда отваливается, приходится переподключаться.
Приложение:
