Interpreting keypresses sent to raspberry-pi through uv4l-webrtc datachannel -
i apologize if doesn't make sense since i'm still newbie using raspberry pi , first time posting on stackoverflow.
i making web app lets me stream video , raspberry pi while letting me send keycodes. sent keycodes let me control servos on drone. after scouring internet, figured simplest way stream 2-way video using uv4l have installed along uv4l-webrtc on raspberry pi. hooked gpio pins flight controller , using pigpio send pwm signals it, monitor using cleanflight.
right now, can manipulate keypresses roll, pitch, etc. of flight controller using python script if access pi remotely using vnc, able through custom web page being served uv4l-server. trying use webrtc data channels, i'm having trouble understanding need recognize messages sent through data channels. know data channels opened when video call initiated , i've tried test in link see if can indeed send keycodes pi (and can).
my problem right have no idea sent messages go or how can them can incorporate them python script. need make server listen keycodes being sent pi?
tl;dr have python script on raspberry pi control servos on flight controller using keypresses , separate webpage streams video using webrtc, have no idea how combine them using webrtc data channels.
thanks @adminkiam solution. here's version of python script listens socket. it's variation of this code person 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 client' connection.sendall(data) else: print 'no more data from', client_address break finally: # clean connection cleanup() connection.close()
when webrtc data channel created between uv4l , other webrtc peer (i.e. browser, janus gateway, etc...), uv4l creates full-duplex unix domain socket (/tmp/uv4l.socket default) from/to can receive/send messages on raspberry pi. python script should open, listen , read socket incoming messages e.g. web application and/or write messages same socket web app receive them. example doing in c++ under link tutorial pointed out in question:
/* copyright (c) 2016 info@linux-projects.org rights reserved. redistribution , use in source , binary forms permitted provided above copyright notice , paragraph duplicated in such forms , documentation, advertising materials, , other materials related such distribution , use acknowledge software developed linux-projects.org. name of linux-projects.org may not used endorse or promote products derived software without specific prior written permission. software provided ``as is'' , without express or implied warranties, including, without limitation, implied warranties of merchantability , fitness particular purpose. */ /* * simple echo server. * creates unix domain socket of type sock_seqpacket specified * command line, listens waiting incoming messages clients * (e.g. uv4l) , replies received messages senders. * * example: * $ ./datachannel_server /tmp/uv4l.socket * * compile program need boost v1.60 or greater, 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 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) /// 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 { (;;) { seqpacket_protocol::socket::message_flags in_flags = msg_waitall, out_flags = msg_waitall; // wait message client auto bytes_transferred = socket_.async_receive(boost::asio::buffer(data_), in_flags, yield); // write same message 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 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])); (;;) { 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; } }
Comments
Post a Comment