Для начала ролик с 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 иногда отваливается, приходится переподключаться.
Приложение:
Tarson
А зачем ему интересно два приложения на телефоне? Можно же на одно выводить. Я только что на скорую руку сляпал, вроде работает
zoldaten Автор
Возможно, чтобы развернуть изображение либо такое решение на тот момент было доступнее.
Realizator
Вау! Круто! :-)
Про «картинки узковаты» — я не игрался с uv4l оберткой, но если она тянет штатные распивидовские стереорежимы, то там можно играть с режимом склейки стерео. Либо '-dec' — это сжатие по горизонтали в 2 раза, либо (дефолтно) — кроп каждого кадра посередине. В этом случае соотношение сторон не портится и геометрия каждого полукадра сохраняется.
UPD> Вот в приведенном конфиге есть закомментированные строчки:
### dual camera options:
#stereoscopic-mode = side_by_side
#camera-number = 1
#decimate = yes
#swap-eyes = yes
Параметр '-dec' тут выведен в строчке #decimate = yes
zoldaten Автор
Пардон, старый конфиг выложен. Естественно, стерео режим должен быть раскоментирован для работы.
decimate потестим.
Пробовался также режим top-bottom (читай over/under) вместо side-by-side, но тогда изображения хотя и в полную длину, но друг над другом.