2017-07-28 6 views
0

まだラズベリーパイを使用している初心者で、これが意味をなさない場合はお詫び申し上げます。これはStackOverflowでの初めての投稿です。raspberry-piからuv4l-webrtc datacannelに送信されたkeypressを解釈する

私はラズベリーパイとの間でビデオをストリームすることができ、またキーコードを送信させるウェブアプリケーションを作っています。送信されたキーコードは最終的に無人機でサーボを制御することになります。インターネットを精査した後、私は、2ウェイビデオをストリーミングする最も簡単な方法はuv4lを使用することであると考えていたので、uv4l-webrtcをラズベリーパイにインストールしました。私はいくつかのGPIOピンをフライトコントローラに接続し、私はpigpioを使ってPWM信号を送信しています。それからCleanFlightを使って監視します。

今、VNCを使って遠隔操作でpiにアクセスすると、飛行制御器のロール、ピッチなどを操作して、パイソンスクリプトを使用して操作することができますが、私は最終的にこれを行うことができますuv4l-serverによって提供されているWebページ。私はWebRTCデータチャネルを使用しようとしていますが、データチャネルを介して送信されたメッセージを認識するために何が必要かを理解するのに問題があります。私は、ビデオ通話が開始されたときにデータチャネルが開かれていることを知っています。このlinkのテストを試して、私が本当にpiにキーコードを送ることができるかどうかを確認します。

今私の問題は、送信されたメッセージがどこに行くのか、どうやって入手できるのかわからないことです。そこで、それらを私のpythonスクリプトに組み込むことができます。私はπに送られるキーコードを聞くサーバーを作る必要はありますか?

tl; dr私はキープレスとWebRTCを使用してビデオをストリームする別のWebページを使用して、フライトコントローラのサーボを制御するために、ラズベリーパイのpythonスクリプトを持っていますが、WebRTCデータチャネルを使用して、

解決策のための@adminkiamのおかげです。ここでは、ソケットをリッスンするPythonスクリプトのバージョンがあります。それは本質的にthis code by the person who made pigpioのバリエーションです:

import socket 
import time 
import pigpio 

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  = 13 
PITCH_PIN = 14 
YAW_PIN  = 15 

MIN_PW = 1000 
MID_PW = 1500 
MAX_PW = 2000 

NONE  = 0 
LEFT_ARROW = 1 
RIGHT_ARROW = 2 
UP_ARROW = 3 
DOWN_ARROW = 4 
LESS_BTN = 5 
GREATER_BTN = 6 

print 'socket_path: %s' % socket_path 
s.bind(socket_path) 
s.listen(1) 

def getch(keyCode): 
    key = NONE 
    if keyCode == 188: 
     key = LESS_BTN 
    elif keyCode == 190: 
     key = GREATER_BTN 
    elif keyCode == 37: 
     key = LEFT_ARROW 
    elif keyCode == 39: 
     key = RIGHT_ARROW 
    elif keyCode == 38: 
     key = UP_ARROW 
    elif keyCode == 40: 
     key = DOWN_ARROW 
    return key 

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

     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: 
      data = connection.recv(16) 
      print 'received message"%s"' % data 

      time.sleep(0.01) 
      key = getch(int(data)) 

      rollPW  = rollPulsewidth 
      pitchPW = pitchPulsewidth 
      yawPW  = yawPulsewidth 

      if key == UP_ARROW: 
       pitchPW = pitchPW + 10 
       if pitchPW > MAX_PW: 
        pitchPW = MAX_PW 
      elif key == DOWN_ARROW: 
       pitchPW = pitchPW - 10 
       if pitchPW < MIN_PW: 
        pitchPW = MIN_PW 
      elif key == LEFT_ARROW: 
       rollPW = rollPW - 10 
       if rollPW < MIN_PW: 
        rollPW = MIN_PW 
      elif key == RIGHT_ARROW: 
       rollPW = rollPW + 10 
       if rollPW > MAX_PW: 
        rollPW = MAX_PW 
      elif key == GREATER_BTN: 
       yawPW = yawPW + 10 
       if yawPW > MAX_PW: 
        yawPW = MAX_PW 
      elif key == LESS_BTN: 
       yawPW = yawPW - 10 
       if yawPW < MIN_PW: 
        yawPW = 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(data) 
      else: 
       print 'no more data from', client_address 
       break 

    finally: 
     # Clean up the connection 
     cleanup() 
     connection.close() 

答えて

0

のWebRTCデータチャネルがUV4Lおよびその他のWebRTCピア(つまりブラウザ、ヤヌスゲートウェイなど)の間で作成されると、UV4Lは、全二重のUnixドメインを作成しますRaspberry Piでメッセージを送受信できるソケット(デフォルトでは/tmp/uv4l.socket)。あなたのpythonスクリプトは、受信したメッセージをソケットから受信して読み込んだり、読み込んだりするだけです。ウェブアプリケーションを受信し、および/またはそれらを受信するためにウェブアプリケーション用の同じソケットにメッセージを書き込む。 C++でこれをやってexampleは、あなたの質問で指摘チュートリアルへのリンクの下にある:

/* 
    Copyright (c) 2016 [email protected] 
    All rights reserved. 

    Redistribution and use in source and binary forms are permitted 
    provided that the above copyright notice and this paragraph are 
    duplicated in all such forms and that any documentation, 
    advertising materials, and other materials related to such 
    distribution and use acknowledge that the software was developed 
    by the linux-projects.org. The name of the 
    linux-projects.org may not be used to endorse or promote products derived 
    from this software without specific prior written permission. 
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
*/ 

/* 
* This is a simple echo server. 
* It creates to a unix domain socket of type SOCK_SEQPACKET specified by 
* command line, listens to it waiting for incoming messages from clients 
* (e.g. UV4L) and replies the received messages back to the senders. 
* 
* Example: 
*  $ ./datachannel_server /tmp/uv4l.socket 
* 
* To compile this program you need boost v1.60 or greater, for example: 
* g++ -Wall -I/path/to/boost/include/ -std=c++11 datachannel_server.cpp -L/path/to/boost/lib -l:libboost_coroutine.a -l:libboost_context.a -l:libboost_system.a -l:libboost_thread.a -pthread -o datachannel_server 
*/ 

#include <boost/asio/io_service.hpp> 
#include <boost/asio/spawn.hpp> 
#include <boost/asio/write.hpp> 
#include <boost/asio/buffer.hpp> 
#include <boost/asio.hpp> 
#include <memory> 
#include <cstdio> 
#include <array> 
#include <functional> 
#include <iostream> 

#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) 
#error Local sockets not available on this platform. 
#endif 

constexpr std::size_t MAX_PACKET_SIZE = 1024 * 16; 

namespace seqpacket { 

    struct seqpacket_protocol { 

     int type() const { 
      return SOCK_SEQPACKET; 
     } 

     int protocol() const { 
      return 0; 
     } 

     int family() const { 
      return AF_UNIX; 
     } 

     using endpoint = boost::asio::local::basic_endpoint<seqpacket_protocol>; 
     using socket = boost::asio::generic::seq_packet_protocol::socket; 
     using acceptor = boost::asio::basic_socket_acceptor<seqpacket_protocol>; 

#if !defined(BOOST_ASIO_NO_IOSTREAM) 
     /// The UNIX domain iostream type. 
     using iostream = boost::asio::basic_socket_iostream<seqpacket_protocol>; 
#endif 
    }; 
} 

using seqpacket::seqpacket_protocol; 

struct session : public std::enable_shared_from_this<session> { 
    explicit session(seqpacket_protocol::socket socket) : socket_(std::move(socket)) {} 

    ~session() { 
     //std::cerr << "session closed\n"; 
    } 

    void echo(boost::asio::yield_context yield) { 
     auto self = shared_from_this(); 
     try { 
      for (;;) { 
       seqpacket_protocol::socket::message_flags in_flags = MSG_WAITALL, out_flags = MSG_WAITALL; 

       // Wait for the message from the client 
       auto bytes_transferred = socket_.async_receive(boost::asio::buffer(data_), in_flags, yield); 

       // Write the same message back to the client 
       socket_.async_send(boost::asio::buffer(data_, bytes_transferred), out_flags, yield); 
      } 
     } catch (const std::exception& e) { 
      std::cerr << e.what() << '\n'; 
      socket_.close(); 
     } 
    } 

    void go() { 
     boost::asio::spawn(socket_.get_io_service(), std::bind(&session::echo, this, std::placeholders::_1)); 
    } 

private: 
    seqpacket_protocol::socket socket_; 
    std::array<char, MAX_PACKET_SIZE> data_; 
}; 

int main(int argc, char* argv[]) { 
    try { 
     if (argc != 2) { 
      std::cerr << "Usage: datachannel_server <file> (e.g. /tmp/uv4l.socket)\n"; 
      std::cerr << "*** WARNING: existing file is removed ***\n"; 
      return EXIT_FAILURE; 
     } 

     boost::asio::io_service io_service; 

     std::remove(argv[1]); 

     boost::asio::spawn(io_service, [&](boost::asio::yield_context yield) { 
        seqpacket_protocol::acceptor acceptor_(io_service, seqpacket_protocol::endpoint(argv[1])); 
        for (;;) { 
         boost::system::error_code ec; 
         seqpacket_protocol::socket socket_(io_service); 
         acceptor_.async_accept(socket_, yield[ec]); 
         if (!ec) 
          std::make_shared<session>(std::move(socket_))->go(); 
        } 
       }); 

     io_service.run(); 

    } catch (std::exception& e) { 
     std::cerr << "Exception: " << e.what() << "\n"; 
     return EXIT_FAILURE; 
    } 
} 
+0

このリンクは質問に答えるかもしれないが、ここでは答えの重要な部分を含めると、リンクを提供することをお勧めします参考のため。リンクされたページが変更された場合、リンクのみの回答は無効になります。 –

+0

「リンク専用」の回答ではありません。これは、より良い答えがない限り、本質的な部分の答えです。公式の例へのリンクもあります。これはOPの質問にも参照されています。 – adminkiam

+0

あなたの答えを説明するコードの抜粋をここに追加してください。 –

関連する問題