Telloプログラミング:data, server = sock.recvfrom(1518)のdataの中身を覗いてみた


Telloプログラミングの中で、TelloとMacbookとの通信経路を確立する部分の定番コードは、次のようなものです。

data, server = sock.recvfrom(1518)

ここで、返り値を受け止めるdata変数に、どのような値が入るのか、興味を持ちました。
この変数の中身を、Terminalに出力して確認してみました。

前回の記事を改良してみました。ソースコードの全体は、この記事の最後に掲載してあります。

コード改編部分

以下を追加(2021/7/28)
dataはバイト列(例:b'\x 16指数表記データ')だから、str型に変換するにはdecodeが必要
received_data = data.decode('utf-8')
print("Telloからの返り値: " + received_data)

コード該当箇所1
def recv():
    count = 0
    while True: 
        try:
            data, server = sock.recvfrom(1518)
            #以下を追加(2021/7/28)
            #dataはバイト列(例:b'\x 16指数表記データ')だから、str型に変換するにはdecodeが必要
            received_data = data.decode('utf-8')
            print("Telloからの返り値: " + received_data)
        except Exception:
            print ('\nExit . . .\n')
            break

#recvThread create
recvThread = threading.Thread(target=recv)
recvThread.start()

以下の2つが入り乱れてTerminalに表示されないように、time.sleep(1)を間にはさむ。

  • 操作コマンドの入力待ち受けプロンプト(の表示)
  • 前の指令コマンドの返り値(の表示)

前に入力したコマンドに対するTelloからの返り値をprint出力するrecv()メソッドの処理が終わるまで、2秒待機する
time.sleep(2)

コード該当箇所2
while True: 
    # 最初に入力が必要な"command"命令は、ユーザが打ち込まなくて良いようにスクリプト側でTelloに送出する
    msg = str("command").encode(encoding="utf-8") 
    sent = sock.sendto(msg, tello_address)
    # "takeoff"以降の命令をユーザ入力から受け取る
    try:
    # 前に入力したコマンドに対するTelloからの返り値をprint出力するrecv()メソッドの処理が終わるまで、2秒待機する
        time.sleep(2)
        msg = input("Telloに送る指示コマンドを入力してください。:  ")
        if not msg:
            break  

検証画面と、その結果分かったこと

送出した操作コマンドと対応する返り値

  • Tello SDKで定義されている正しい操作コマンド:「OK」という返り値が戻される
  • 未定義の操作コマンド (引数のみが未定義の場合を含む): 「unknown command」という返り値が戻される
  • (同上) :「out of range」という返り値が戻される

その他

  • 「error No valid imu」という返り値が戻される
Terminal
electron@diynoMacBook-Pro Tello % python3 tello_python_rev2.py
Telloからの返り値: ok
Telloに送る指示コマンドを入力してください。:  takeoff
Telloからの返り値: ok
kefTelloに送る指示コマンドを入力してください。:  t 50
Telloからの返り値: unknown command: keft
Telloからの返り値: ok
Telloに送る指示コマンドを入力してください。:  Telloからの返り値: ok
right 50
Telloからの返り値: ok
Telloからの返り値: ok
Telloに送る指示コマンドを入力してください。:  up 100
Telloからの返り値: ok
Telloからの返り値: error No valid imu
Telloに送る指示コマンドを入力してください。:  up x
Telloからの返り値: out of range
Telloからの返り値: ok
Telloに送る指示コマンドを入力してください。:  upp
Telloからの返り値: unknown command: upp
Telloからの返り値: ok
Telloに送る指示コマンドを入力してください。:  upppppp
Telloからの返り値: unknown command: upppppp
Telloからの返り値: ok
Telloに送る指示コマンドを入力してください。:  ^C  
Exit . . .

electron@diynoMacBook-Pro Tello % 

ソースコード全文

tello_python_rev2.py
import threading 
import socket
import sys
import time

host = ''
port = 9000
locaddr = (host, port) 

# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
tello_address = ('192.168.10.1', 8889)

sock.bind(locaddr)

def recv():
    count = 0
    while True: 
        try:
            data, server = sock.recvfrom(1518)
            #以下を追加(2021/7/28)
            #dataはバイト列(例:b'\x 16指数表記データ')だから、str型に変換するにはdecodeが必要
            received_data = data.decode('utf-8')
            print("Telloからの返り値: " + received_data)
        except Exception:
            print ('\nExit . . .\n')
            break

#recvThread create
recvThread = threading.Thread(target=recv)
recvThread.start()

while True: 
    # 最初に入力が必要な"command"命令は、ユーザが打ち込まなくて良いようにスクリプト側でTelloに送出する
    msg = str("command").encode(encoding="utf-8") 
    sent = sock.sendto(msg, tello_address)
    # "takeoff"以降の命令をユーザ入力から受け取る
    try:
    # 前に入力したコマンドに対するTelloからの返り値をprint出力するrecv()メソッドの処理が終わるまで、2秒待機する
        time.sleep(2)
        msg = input("Telloに送る指示コマンドを入力してください。:  ")
        if not msg:
            break  

        # Send data
        # Tello SDK v2.0 https://dl-cdn.ryzerobotics.com/downloads/Tello/Tello%20SDK%202.0%20User%20Guide.pdf
        if msg == "land":
            order_command = "battery?"
            battery_volume = sock.sendto(order_command.encode(encoding="utf-8") , tello_address)
            order_command = "time?"
            flight_time = sock.sendto(order_command.encode(encoding="utf-8") , tello_address)            
            print("着陸します。")
            message = "累積飛行時間: {0} \nバッテリ残量(%): {1}".format(str(flight_time), str(battery_volume))
            print(message)
            sock.close()  
            break
        elif msg == "battery?":
            msg = msg.encode(encoding="utf-8") 
            sent = sock.sendto(msg, tello_address)
            print("バッテリ残量(%): " + str(sent))
        elif msg == "speed?":
            msg = msg.encode(encoding="utf-8") 
            sent = sock.sendto(msg, tello_address)
            print("現在の速度: " + str(sent))
        elif msg == "time?":
            msg = msg.encode(encoding="utf-8") 
            sent = sock.sendto(msg, tello_address)
            print("累積飛行時間: " + str(sent))
        elif msg == "sdk?":
            msg = msg.encode(encoding="utf-8") 
            sent = sock.sendto(msg, tello_address)
            print("この機体のSDK Ver.: " + str(sent))
        elif msg == "sn?":
            msg = msg.encode(encoding="utf-8") 
            sent = sock.sendto(msg, tello_address)
            print("この機体のシリアル番号: " + str(sent))
        else:
            msg = msg.encode(encoding="utf-8") 
            sent = sock.sendto(msg, tello_address)

    except KeyboardInterrupt:
        sock.close()  
        break