Stereopi + WebRTC = telepresense em casa

Para começar, vídeo do youtube para inspiração:


Atenção: o projeto no vídeo é apenas uma amostra que pode ser realizada de acordo com o tutorial do artigo sobre visão estéreo e “virada de cabeça”. Tanques com controle remoto xbox não estão incluídos.

Apesar da clareza, a escassa história do autor do projeto no vídeo e a disponibilidade de links, imediatamente para descobrir como tudo funciona, não é fácil. Se você deseja coletar algo semelhante e em um formato muito mais conveniente, é recomendável ler.

* Farei uma reserva imediatamente, a pessoa no vídeo no YouTube não é familiar para mim, não transmiti dados secretos, qual é o estado do projeto dele agora, não sei.
** Não controlaremos o movimento do robô na framboesa na superfície através do controle remoto do xbox, isso pode ser tratado de forma independente.
*** Por favor, não jogue tênis, pois o projeto ainda está em desenvolvimento.

Então, estamos interessados ​​em duas coisas:

  • como obter uma imagem estéreo no telefone usando um capacete;
  • como controlar os servos girando a cabeça.

O conceito usado no vídeo, se resumido, fica assim:

  • 2 raspberry pi enviam fluxos de vídeo para a rede de suas câmeras via serviços webrtc;
  • o telefone (no capacete) aceita fluxos em 2 aplicativos idênticos no telefone - aplicativos flutuantes.
  • ao mesmo tempo, o telefone controla os servidores conectados à framboesa.

Tudo é simples. Mas o diablo, como você sabe, está nos detalhes e inconvenientes, a saber:

  • você precisa executar 2 raspberry, monitorar as configurações de 2 câmeras, power raspberry * 2.
  • aplicativos flutuantes constantemente deslizam no telefone, você precisa alinhar as imagens na tela.
  • ...

Portanto, transferiremos para o stereopi, felizmente, ele apareceu nas lojas russas (espero que não desapareça após este post):



Stereopi é o desenvolvimento de nosso compatriota, que agora está conquistando ativamente o mercado.

Seu charme segue o nome - você pode conectar duas câmeras CSI raspberry pi ao mesmo tempo. Ao mesmo tempo, tudo isso funciona com base em um módulo de computação raspberry pi. Infelizmente, o módulo em si não está incluído no pacote; você deve comprá-lo.

Sobre o stereopi, existem artigos sobre Habré.

A partir dele, precisaremos de 2 fluxos de vídeo e controle de servidores através do GPIO.
Como base para o stereopi, usaremos o Raspberry Pi Compute Module 3+.

Preparação para Stereopi


Depois de montar o stereopi (insira o módulo de computação no stereopi, câmeras), preencha o software.

Usamos a imagem pronta para o módulo de computação raspberry pi - Raspbian (estiramento). Está disponível em stereopi.com - Imagem Raspbian Stretch OpenCV, Google Drive
Encha com framboesa.

Se houver dificuldades com o preenchimento, outros vão para o wiki stereopi .

Instalando o webrtc.


Instale o software webrtc no stereopi. Parcialmente, o material de instalação é retirado desta página: Instalação para ARM (Raspberry Pi)


Evitaremos comentários desnecessários que já estão na página acima e simplesmente instalaremos tudo o que for necessário.

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 

Agora você precisa (conforme as instruções) gerar chaves ssl, pois o Chrome pode não mostrar o vídeo pela conexão http (somente via https):

 openssl genrsa -out selfsign.key 2048 && openssl req -new -x509 -key selfsign.key -out selfsign.crt -sha256 

* ao gerar chaves, perguntas serão feitas sobre a empresa, região etc. - Você pode respondê-las arbitrariamente.

As chaves geradas (selfsign.key e selfsign.crt aparecerão na pasta atual) devem ser colocadas na pasta:

 /etc/ssl/private/ 

Todas as configurações do webrtc são armazenadas em 2 arquivos:

 /etc/uv4l/uv4l-raspicam.conf /etc/uv4l/uv4l-raspidisp.conf 

Para não se cansar de listar itens em arquivos que precisam ser descomentados ou
para corrigir, sobrescreva os arquivos de configuração com o uv4l-raspicam.conf e o uv4l-raspidisp.conf.

Reinicie o raspberry e efetue login no ip raspberry usando o chrome:

 https://192.168.1.100:8080 

O WebRTC é um grande fã de possibilidades, mas nos limitaremos a uma coisa: iremos para a guia webrtc:

quadro


Agora verifique se o vídeo funciona com stereopi.

Pressione o botão “Ligar” na parte inferior da página da web no telefone.

quadro


Um vídeo das câmeras estéreo deve aparecer.

Clique no botão "Tela cheia" abaixo da janela com a imagem das câmeras da web:

quadro


* Não recarregue a página no telefone! Se isso ainda aconteceu, você precisa matar os processos na framboesa:

 sudo killall uv4l 

E reinicie os serviços:

 sudo service uv4l_raspidisp restart sudo service uv4l_raspicam restart 

Então, novamente, na página do navegador do telefone, clique em "Ligar".
** A chamada não funcionará se nenhuma câmera estiver conectada à framboesa.

Nós vamos lidar com os servos.


Para gerenciar os servos em framboesa a partir do telefone, você precisa de um código que será executado em framboesa e ações no telefone.

Mas primeiro, vamos decidir sobre os servos. O vídeo do YouTube usa servos conectados diretamente ao gpio raspberry. Como os servos são de baixa potência, você provavelmente pode pendurar 2 servos no gpio raspberry. Esses truques podem ser facilmente executados em servidores sg-90. Eles não são exigentes em nutrição, mas também não são particularmente bons para cargas. Em princípio, eles devem ser suficientes para manter uma suspensão com duas câmeras da stereopi. O próprio cardan pode ser comprado no mesmo aliexpress, para a pesquisa “pan-tilt”. No entanto, esses servos também têm um sinal negativo negativo - eles "tremem de medo". É esse efeito que o autor do vídeo do YouTube observa. Por que isso está acontecendo e o que fazer com isso não será considerado aqui.

No nosso caso, os servos mg-996n e a junta do robô são usados, o que espero que ele não precise no futuro próximo.

Imagem


* O Mg-996N não "treme".

O Stereopi possui um layout gpio semelhante ao padrão do raspberry 3 .

Portanto, os fios de sinal dos servos irão para gpio, e é melhor usar 5V não da framboesa, mas de lado, combine o serviço GND com o GND raspberry e o GND de uma fonte externa.

Agora, o mais importante é o software


Em framboesa, precisamos de um demônio, mas não de Lermontov, mas de pigpio. Você não precisa executar nenhuma etapa especial para configurá-lo. O principal é saber que ele está travado na porta 8888 e você deve primeiro executá-lo:

 sudo systemctl start pigpiod.service 

Em seguida, crie um arquivo que gerencie os servidores, recebendo dados do soquete, que ele próprio cria:

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() 


Os comentários são deixados no texto para entender de onde veio o código e o que mais pode ser corrigido.
O significado geral do código é o seguinte:

  • no início, os servos são definidos na posição do meio.
  • Existem 3 pinos (gpio) nos quais os fios de sinal dos servos estão pendurados. No nosso caso, 2 pinos (suspensão de 2 servos).
  • O gpio é controlado através da aplicação de um sinal no intervalo PWM de 1000 a 2000.
  • chega uma linha do telefone, que é analisada por json (você pode fazer outra coisa) e, em seguida, os valores xey são tirados dela. Em seguida, esses valores são convertidos em valores PWM para girar os servos.

* O problema é que x assume valores de 0 a 360 (o telefone gira em torno de seu eixo), como y. E esses valores devem estar vinculados ao PWM, que aceita valores de 1000 a 2000. O código usa a fórmula pitchPW = key1 * 5 + 500. 500 é o valor mínimo do servo PWM (embora a suposição seja 1000 no código). E a multiplicação por 5 é condicional. Esse ponto precisa ser aprimorado, pois em x = 360, o valor do PWM é muitas vezes maior que o máximo. Os servos são protegidos de exceder os ângulos máximos de rotação para evitar danos, mas isso não é muito agradável.

Execute o código no terminal raspberry:

 sudo python3 datachannel_server_tele.py 

Ativaremos o GPS no telefone (cada telefone tem um ícone correspondente nas configurações) e passaremos o ip raspberry.

 https://192.168.1.100:8080/stream/webrtc 

Clique em "Ligar". Após a conexão ser estabelecida, no telefone do navegador da página, marque "enviar ângulos de orientação do dispositivo alfa, beta, gama".

Os valores x irão para o terminal com o script. E, se você girar o telefone, eles mudarão.
Servos também se moverão.

* Atualmente um deles (o segundo está comentado).

Dos bons bônus, o webrtc também oferece a oportunidade :

  • crie uma aparência de um telebridge entre o telefone e a framboesa (seu interlocutor será volumoso),
  • transmitir som nas duas direções (não testado, mas levado em consideração nas configurações),
  • Transmitir para uma página da web, youtube em 3d.
  • crie uma teleconferência de vários amigos (jitsi meet).
  • altere as configurações da câmera rapidamente através da interface da Web (por que girar! &? não funciona).

Agora sobre o triste.


1. Shalturit, conectando duas câmeras diferentes com olhos de peixe na régua da escola, não funcionou. Acontece que os peixes têm olhos diferentes. Precisamos do mesmo tipo de câmera:



2. Não foi possível expandir a imagem das câmeras estéreo através das configurações da interface da web webrtc. Enquanto as fotos são estreitas, como as calças de um francês.



3. O servo MG996N é limitado a -180 ângulos de rotação. De fato - 160. Talvez alguém irá aconselhar com 360, mas sem rotação contínua.

4. O software requer moagem.

5. A chamada às vezes cai, você precisa se reconectar.

Aplicação:

Source: https://habr.com/ru/post/pt473750/


All Articles