LoginSignup
1
3

More than 5 years have passed since last update.

Syma X5SW のFPVカメラをPCから見る

Last updated at Posted at 2015-12-28

ドローン X5SW のFPV Cameraは公式iPhone/Androidアプリから見ることができますが、工夫するとPCからも閲覧できます。その方法は

  • PCでドローンにWiFi接続
  • http://192.168.1.1/request_av.cgi にアクセス
  • var id=40463458; の部分の数字を記憶する。
  • http://192.168.1.1/Videostream.cgi?User=admin&pwd=&id=40463458 先ほど記憶したIDと同じIDをURLに入れてアクセスする
    • MotionJPEGで降ってくる。Firefoxでは直に見れた。Chromeではただのjpegとされるらしく無理だった。
  • Digest認証を求められたときはユーザー名 admin でパスワードは空白

表示する

これを手動でやるのは面倒なので、JSONP(もどき)とiframeでSame origin policyを回避しつつ表示できるようにした。以下のHTMLをローカルに保存してFirefoxとかで開くと、リアルタイム中継が見られる。

<!DOCTYPE html>
<body onLoad="start()">
<script src="http://192.168.1.1/request_av.cgi"></script>
<script>
function start(){
console.log(id);
document.getElementById("fpv").src = "http://192.168.1.1/Videostream.cgi?User=admin&pwd=&id="+id;
}
</script>
<iframe src="" id="fpv" width="640" height="480" style="border:none;overflow:hidden;" scrolling="no"></iframe>
</body>

Screenshot from 2015-12-28 13:54:39.png

複数接続はできるが、つなげばつなぐほどきっと重くなる。
Digest認証を求められたときはユーザー名 admin でパスワードは空白にする。

表示をリレーする

from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import threading
import urllib.request # high-level http client
import re
import http.client # low-level http client for continuous stream

BUFSZ = 1024
HOST="192.168.1.1"
PORT="80"
url_reqav = "http://{0}:{1}/request_av.cgi?User=admin&pwd=".format(HOST,PORT)
url_reqvs = "/Videostream.cgi?User=admin&pwd=&id={0}"
id_pat = re.compile("\d+")


# 1対1 ブラウザ <=> ドローン
# 接続の例
class Handler(BaseHTTPRequestHandler):

    def do_GET(self):
        with urllib.request.urlopen(url=url_reqav) as resp:
            id_line = resp.readlines()[1].decode("utf8")
            self.id_num = id_pat.search(id_line).group(0)

            self.send_response(200)
            self.send_header('Content-type', 'multipart/x-mixed-replace;boundary=ipcamera')
            self.end_headers()

            buf = bytearray(BUFSZ)

            con = http.client.HTTPConnection("{0}:{1}".format(HOST,PORT))
            con.request("GET",url_reqvs.format(self.id_num))
            resp = con.getresponse()

            while not resp.closed:
                buf = resp.read(BUFSZ)
                self.wfile.write(buf)

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""

if __name__ == '__main__':
    server = ThreadedHTTPServer(('localhost', 8080), Handler)
    print ('Starting server, use <Ctrl-C> to stop')
    server.serve_forever()

ホントは中継ついでに保存もしたい。そのためには環状バッファを実装する必要がある気がする。

Screenshot from 2015-12-28 21:58:48.png

追記

Pythonを使わず、wgetとオリジナルのC言語製 MJPEG スプリッターを使うと、VLCでリアルタイムで見ながら保存もできるようになります。以下参照。
cc -O3 separate.c でコンパイルして、 bash syma.sh を実行。
デバッグ不足で一度目は映らなかったりするので閉じて再度トライのこと。
https://gist.github.com/keiya/cb9e2901ccc1e813c634

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_FRAME_SIZE 256*1024 // KB
#define CONTENT_LENGTH "Content-Length: "
#define PAYLOAD "\r\n"

int main()
{
    char buf[MAX_FRAME_SIZE];
    //size_t rs = fread(buf, MAX_FRAME_SIZE, 1, stdin);
    // parse content-length
    int length;
    int seq = 0;
    while (1) {
        while( fgets(buf, MAX_FRAME_SIZE, stdin) != NULL )
        {
            char *length_start = strstr(buf,CONTENT_LENGTH);
            if (length_start == NULL) continue;
            char *length_end = strstr(length_start,"\r\n");
            int tmp = *length_end;
            *length_end = 0;
            length_start += strlen(CONTENT_LENGTH);
            *length_end = tmp;
            length = atoi(length_start);
            break;
        }

        while( fgets(buf, MAX_FRAME_SIZE, stdin) != NULL )
        {
            // parse body
            char *payload = strstr(buf,PAYLOAD);
            if (payload != buf) continue; // if not start with "\r\n"
            break;
        }
        if (fread(buf,length,1,stdin) == 0) break;
        fwrite(buf,length,1,stdout);

        char fname[16];
        snprintf(fname,15,"%05d.jpg",seq++);
        FILE *out = fopen(fname,"w");
        fwrite(buf,length,1,out);
        fclose(out);
    }
}
PARSER="$HOME/hgfs/Dropbox/symafpv/a.out"
HOST="http://192.168.1.1:80"
DATE=`date +%F_%T`
mkdir -p $DATE
cd $DATE
ID=`wget -q -O - "$HOST/request_av.cgi?User=admin&pwd=" | grep "var id=" | grep -o -P "[0-9]+"`
wget -q -O - "$HOST/Videostream.cgi?User=admin&pwd=&id=$ID" | $PARSER | vlc /dev/stdin
avconv -framerate 15 -i %05d.jpg -codec copy encoded15.mov
rm *.jpg

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3