質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

5896閲覧

[Python]telloEduで編隊飛行を行った際のカメラ映像の取得方法を教えてください。

tiffany

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/09/03 08:24

編集2020/09/07 04:04

前提・実現したいこと

[Python]telloEduで編隊飛行を行った際のカメラ映像の取得方法を教えてください。

この質問は以下のサイトでマルチポストしています。
分かったこと、補足説明や解決方法はどちらのサイトにも更新します。
http://qiita.com/tiffany1098/questions/70c0cbfba80ec8ffa1f1

UDPやIPアドレスについてあまり詳しくないため、間違っていましたらご指摘お願いします。

発生している問題

tellopyなどは使わず、TelloSDK2.0のコマンド送信によるプログラムを書いています。
TelloEdu1台での飛行時のカメラ映像は「command」の次に「streamon」とコマンドを送信したのち、OpecCVで
cap = cv2.VideoCapture('udp://0.0.0.0:11111')
ret,frame = cap.read()
cv2.imshow('',frame)
と書きtelloの映像を取得していました。1台の時はこの方法でPC画面に映像を表示させることに成功しました。
しかし、telloEDU3台の編隊飛行の際はこの方法では成功しません。実行画面ではstreamon OK まで進み、その後何も起こりません。3台使うことによりカメラのUDPが変わるなど、何か原因があると思うのですがそれが分かりません。

telloEDUの編隊飛行(前進、後退などの単純な動き)自体はうまくいっています。

#補足説明
tello 1台のときはtello自体がwifiアクセスポイントとなります。
telloのIPアドレス、ポート番号は公式通りに
('192.168.10.1',8889)
を使用しています。
映像受信時のUDPも公式通りに
('udp://0.0.0.0:11111')
を使用しています。

tello3台のときは
wifiルーターにtello3台とパソコンをつなげているため、IPアドレスが変わるため
ドローン1:('192.168.100.112',8889)
ドローン2:('192.168.100.113',8889)
ドローン3:('192.168.100.114',8889)
を使用しています。このIPアドレスはwifiにつなげた状態でパソコンでIPアドレススキャナーのアプリでスキャンして得ました。
映像受信時のUDPは1台の時と変わらず
('udp://0.0.0.0:11111')
を使用していますが、映像を取得できませんでした。「streamon」はきちんと送れているようなので、telloのIPアドレスは正しく、映像受信時のUDPが間違っているのではないかと考えています。

IPアドレスを変更するとUDPも変わるのでしょうか。変わるとしても、変更後の値が分かりません。そもそも編隊飛行ではカメラを使えないのでしょうか。

ご回答宜しくお願い致します。

#試したこと


https://joho-ka.mints.ne.jp/multi-camras-with-opencv?doing_wp_cron=1599214242.8721311092376708984375
こちらのサイトのcapture = cv2.VideoCapture(i)のiの値を変えていく方法はうまくいきませんでした。この方法はパソコンに直接つなぐタイプのカメラにしか使えないようで、通信で映像を取得するtelloには使うことができませんでした。


wi-fiルーターにパソコンとドローン3台ではなく、1台のみ接続し試しました。
ドローン1:('192.168.100.112',8889)
('udp://0.0.0.0:11111')
で試しましたが、「streamon OK」で止まり、映像の取得はできませんでした。
つまり、混信以前のUDPなどが間違っていることになるのでしょうか。

Python

1#試したこと② 2import socket 3import threading 4import time 5import cv2 6 7event = threading.Event() 8 9sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 10sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) 11sock.bind(('',9000)) 12 13tello1_address = ('192.168.100.112',8889) 14 15def send_command1(msg): 16 print(msg) 17 msg = msg.encode(encoding="utf-8") 18 sock.sendto(msg,tello1_address) 19 event.wait() 20 event.clear() 21 22def send_command2(msg): 23 print(msg) 24 msg = msg.encode(encoding="utf-8") 25 sock.sendto(msg,tello2_address) 26 event.wait() 27 event.clear() 28 29def send_command3(msg): 30 print(msg) 31 msg = msg.encode(encoding="utf-8") 32 sock.sendto(msg,tello3_address) 33 event.wait() 34 event.clear() 35 36def send_command(msg): 37 print(msg,msg,msg, sep='\n', end='\n') 38 msg = msg.encode(encoding="utf-8") 39 sock.sendto(msg,tello1_address) 40 sock.sendto(msg,tello2_address) 41 sock.sendto(msg,tello3_address) 42 event.wait() 43 event.clear() 44 45def send_command12(msg1,msg2): 46 print(msg1,msg2, sep='\n', end='\n') 47 msg1 = msg1.encode(encoding="utf-8") 48 msg2 = msg2.encode(encoding="utf-8") 49 sock.sendto(msg1,tello1_address) 50 sock.sendto(msg2,tello2_address) 51 event.wait() 52 event.clear() 53 54def send_command23(msg2,msg3): 55 print(msg2,msg3, sep='\n', end='\n') 56 msg2 = msg2.encode(encoding="utf-8") 57 msg3 = msg3.encode(encoding="utf-8") 58 sock.sendto(msg2,tello2_address) 59 sock.sendto(msg3,tello3_address) 60 event.wait() 61 event.clear() 62 63def send_command13(msg1,msg3): 64 print(msg1,msg3, sep='\n', end='\n') 65 msg1 = msg1.encode(encoding="utf-8") 66 msg3 = msg3.encode(encoding="utf-8") 67 sock.sendto(msg1,tello1_address) 68 sock.sendto(msg3,tello3_address) 69 event.wait() 70 event.clear() 71 72def send_command123(msg1,msg2,msg3): 73 print(msg1,msg2,msg3, sep='\n', end='\n') 74 msg1 = msg1.encode(encoding="utf-8") 75 msg2 = msg2.encode(encoding="utf-8") 76 msg3 = msg3.encode(encoding="utf-8") 77 sock.sendto(msg1,tello1_address) 78 sock.sendto(msg2,tello2_address) 79 sock.sendto(msg3,tello3_address) 80 event.wait() 81 event.clear() 82 83def recv(): 84 while True: 85 try: 86 data,server = sock.recvfrom(1518) 87 print(data.decode(encoding="utf-8")) 88 event.set() 89 except Exception: 90 break 91recvThread = threading.Thread(target=recv) 92recvThread.start() 93 94 95def main(): 96 try: 97 send_command1('command') 98 send_command1('streamon') 99 100 cap1 = cv2.VideoCapture('udp://0.0.0.0:11111') 101 102 while True: 103 ret,frame1 = cap1.read() 104 cv2.imshow('TelloEDU1',frame1) 105 106 key = cv2.waitKey(1) 107 if key == 27: 108 break 109 110 111 except Exception as ex: 112 print(ex) 113 finally: 114 cap1.release() 115 cv2.destroyAllWindows() 116 send_command1('streamoff') 117 sock.close() 118 print('--- END ---') 119 120if __name__ == '__main__': 121 main()


('192.168.10.1',8889)と('udp://0.0.0.0:11111')がセットになっている(対になっている)可能性があるか調べました。wi-fiルーターにパソコンとドローンを1台接続し、ドローンは192.168.10.1に割り振られるようにルーター側で設定しました。
この方法もうまくいかず、「streamon OK」で止まりました。


ドローン自体をwi-fiアクセスポイントとしたとき(パソコンとドローンを1対1で接続)、
('192.168.10.1',8889)('udp://0.0.0.0:11111')
('192.168.10.1',8889)('udp://127.0.0.1:11111')
('192.168.10.1',8889)('udp://192.168.10.2:11111')
のように映像受信時のIPアドレスを変えても、映像を受信できました。


wi-fiルーターではなく、ドローンをwi-fiのアクセスポイントとしたとき、このアクセスポイントに他のドローンも接続できるか試しましたができませんでした。

該当のソースコード

Python

1import socket 2import threading 3import time 4import cv2 5''' 6from formationflight.multi_1.tello1 import Tello1 7from formationflight.multi_1.tello2 import Tello2 8from formationflight.multi_1.tello3 import Tello3 9 10tello1 = Tello1() 11tello2 = Tello2() 12tello3 = Tello3() 13''' 14 15event = threading.Event() 16 17sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 18sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True) 19sock.bind(('',9000)) 20 21tello1_address = ('192.168.100.112',8889) 22tello2_address = ('192.168.100.113',8889) 23tello3_address = ('192.168.100.114',8889) 24 25def send_command1(msg): 26 print(msg) 27 msg = msg.encode(encoding="utf-8") 28 sock.sendto(msg,tello1_address) 29 event.wait() 30 event.clear() 31 32def send_command2(msg): 33 print(msg) 34 msg = msg.encode(encoding="utf-8") 35 sock.sendto(msg,tello2_address) 36 event.wait() 37 event.clear() 38 39def send_command3(msg): 40 print(msg) 41 msg = msg.encode(encoding="utf-8") 42 sock.sendto(msg,tello3_address) 43 event.wait() 44 event.clear() 45 46def send_command(msg): 47 print(msg,msg,msg, sep='\n', end='\n') 48 msg = msg.encode(encoding="utf-8") 49 sock.sendto(msg,tello1_address) 50 sock.sendto(msg,tello2_address) 51 sock.sendto(msg,tello3_address) 52 event.wait() 53 event.clear() 54 55def send_command12(msg1,msg2): 56 print(msg1,msg2, sep='\n', end='\n') 57 msg1 = msg1.encode(encoding="utf-8") 58 msg2 = msg2.encode(encoding="utf-8") 59 sock.sendto(msg1,tello1_address) 60 sock.sendto(msg2,tello2_address) 61 event.wait() 62 event.clear() 63 64def send_command23(msg2,msg3): 65 print(msg2,msg3, sep='\n', end='\n') 66 msg2 = msg2.encode(encoding="utf-8") 67 msg3 = msg3.encode(encoding="utf-8") 68 sock.sendto(msg2,tello2_address) 69 sock.sendto(msg3,tello3_address) 70 event.wait() 71 event.clear() 72 73def send_command13(msg1,msg3): 74 print(msg1,msg3, sep='\n', end='\n') 75 msg1 = msg1.encode(encoding="utf-8") 76 msg3 = msg3.encode(encoding="utf-8") 77 sock.sendto(msg1,tello1_address) 78 sock.sendto(msg3,tello3_address) 79 event.wait() 80 event.clear() 81 82def send_command123(msg1,msg2,msg3): 83 print(msg1,msg2,msg3, sep='\n', end='\n') 84 msg1 = msg1.encode(encoding="utf-8") 85 msg2 = msg2.encode(encoding="utf-8") 86 msg3 = msg3.encode(encoding="utf-8") 87 sock.sendto(msg1,tello1_address) 88 sock.sendto(msg2,tello2_address) 89 sock.sendto(msg3,tello3_address) 90 event.wait() 91 event.clear() 92 93def recv(): 94 while True: 95 try: 96 data,server = sock.recvfrom(1518) 97 print(data.decode(encoding="utf-8")) 98 event.set() 99 except Exception: 100 break 101recvThread = threading.Thread(target=recv) 102recvThread.start() 103 104 105def main(): 106 try: 107 send_command('command') 108 send_command1('streamon') 109 110 cap1 = cv2.VideoCapture('udp://0.0.0.0:11111') 111 #cap2 = cv2.VideoCapture('udp://0.0.0.0:11111') 112 #cap3 = cv2.VideoCapture('udp://0.0.0.0:11111') 113 114 while True: 115 ret,frame1 = cap1.read() 116 cv2.imshow('TelloEDU',frame1) 117 118 key = cv2.waitKey(1) 119 if key == 27: 120 break 121 122 123 except Exception as ex: 124 print(ex) 125 finally: 126 cap.release() 127 cv2.destroyAllWindows() 128 send_command('streamoff') 129 sock.close() 130 print('--- END ---') 131 132if __name__ == '__main__': 133 main()

補足情報(FW/ツールのバージョンなど)

python 3.7.6

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

問題点

telloのIPアドレスは正しく、カメラのUDPが間違っているのではないかと考えています。

この認識は間違いです。telloとカメラは1つの装置として認識されています。

TELLO SDK 2.0 User GuideのReceive Tello Video Streamを見ると

  • TelloはUDPのクライアントとしてPort 11111にブロードキャストで(サブネット上の全てのマシンに)映像を送信する
  • PCはUDPのサーバとしてPort 11111として待ち受ける

となっています。PC側をUDPのサーバとして動作させているのは

python

1cap1 = cv2.VideoCapture('udp://0.0.0.0:11111')

の部分です。3台全てのTelloがPC側の同じUDPのアドレスに同時に映像を(ブロードキャストで)投げ込んでいるため、サーバであるPC側ではそれらが混在して正しく映像として結合できないことが問題です。

解決方法

Tello側に指定したポートに映像送り込めるコマンドがあれば良いのですが、残念ながらそのようなコマンドはありませんでした。したがってPC側で受けた映像をIPアドレスに応じて別のポートに投げ込む、いわゆるプロキシサーバを使う必要があります。Pythonで書くと以下のようになります。

python

1# udp_proxy.py 2import socket 3 4BUF_SIZE = 8192 5 6listen_addr = ("0.0.0.0", 11111) 7s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 8s.bind(listen_addr) 9 10addrs = { 11 "192.168.100.112": ("127.0.0.1", 12000), 12 "192.168.100.113": ("127.0.0.1", 12001), 13 "192.168.100.114": ("127.0.0.1", 12002), 14} 15 16c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 17while True: 18 data, (ip, port) = s.recvfrom(BUF_SIZE) 19 if ip in addrs: 20 c.sendto(data, addrs[ip])

これをpython udp_proxy.pyとして起動しておくと、受けたIPアドレスに応じて、ローカルのUDP Port 12000/12001/12002にデータを転送します。

OpenCV側では

python

1cap1 = cv2.VideoCapture('udp://0.0.0.0:12000') 2cap2 = cv2.VideoCapture('udp://0.0.0.0:12001') 3cap3 = cv2.VideoCapture('udp://0.0.0.0:12002')

とすれば、それぞれ別のパケットとして受け取ることが可能になります。

参考URL

投稿2020/09/04 12:56

編集2020/09/04 17:53
yymmt

総合スコア1615

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiffany

2020/09/05 08:49

ご回答ありがとうございます。 早速この方法を試してみたのですが、質問があります。 私が書いたプログラム(OpenCV側)をtello.pyとすると、 yymmt様の回答内容の 「これをpython udp_proxy.pyとして起動しておくと」はどのようにしたらいいでしょうか。 1)python udp_proxy.py tello.py と実行 2)python udp_proxy.py実行→python tello.py実行(python udp_proxy.py実行の時点で固まる) 3)tello.pyの中でimport udp_proxy する 4)python udp_proxy.py tello.txt と実行 これらを試してみたのですが、うまくいきませんでした。どの方法も実行後に実家う画面では何も起こらず、固まってしまいます。 tello.pyは cap1 = cv2.VideoCapture('udp://0.0.0.0:12000') cap2 = cv2.VideoCapture('udp://0.0.0.0:12001') cap3 = cv2.VideoCapture('udp://0.0.0.0:12002') のように修正しました。 知識不足で申し訳ありませんが、ご教授お願い致します。
yymmt

2020/09/05 13:03

importするのではなく別のプログラムとして起動してください。 python udp_proxy.py と実行してください。
tiffany

2020/09/07 03:34 編集

返信ありがとうございます。 この方法を試してみましたが、「streamon OK」で止まり映像取得できませんでした。 ここで、wi-fiルーターにパソコンとドローン1台だけ接続し試してみましたが、その時も映像取得できませんでした。 この場合、データが3個分混在する問題以前に、映像受信時のudpが間違っていることのなるのでしょうか。その他に原因があるのでしょうか。 「試したこと」を追記しましたので読んでいただけると幸いです。
yymmt

2020/09/07 04:11

wifi1台でも動かないということですので、Wireshark等を使ってPC側にパケットが流れているかどうかを確認するのはどうでしょうか?「udpが間違っている」というのは「'udp://0.0.0.0:ポート番号'が間違っている」のことだと思いますが、0.0.0.0は全てのネットワークインターフェイスからデータを受け付けることができるようになるので現時点でこの部分を変更する必要はないと思います。
tiffany

2020/09/07 13:14

ありがとうございます。 Wiresharkを使ってwi-fiルーターに接続した状態の時のパケットを調べてみました。するとPC側に8889のポートのパケットは届いていますが、11111のポートのパケットが届いていないことが分かりました。 'udp://0.0.0.0:ポート番号'が間違っているわけでは無いとのことですので、公式SDKに問い合わせてみたところ 「telloEduは編隊飛行の時(ステーションモードの時)映像の取得はできない。」と返信がありました。 編隊飛行の映像取得はできませんでしたが、プロキシサーバなどとても勉強になりました。ありがとうございました。
yymmt

2020/09/08 03:52

動作モードによって映像の取得ができない場合があるというのは盲点でした。編隊飛行で映像が取れるようになるとSLAMで面白いことができそうですが、そういう利用は想定していないのかも知れませんね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問