【 DJI TelloPyサンプルコード】Tello移動中の単眼カメラ画像を、遅延なしにMacbookのウィンドウに表示成功


###環境

```bash:Terminal
electron@diynoMacBook-Pro examples % python3 --version
Python 3.9.6
electron@diynoMacBook-Pro examples %
```

###Tello離陸中のリアルタイム画像のウィンドウ出力に成功

__DJITelloPyの*manual-control-opencv.py*__を、MacbookのPython3環境で動かしました。

- 離陸中の画像フレームが、Macbook側のウィンドウに遅延なく出力された。
- 移動動作が終わった後のホバリング中だけでなく、移動中の画像もウィンドウに出力表示に成功した。
- ホバリング中のTelloの正面に立って、手をかざして動かしたところ、遅延なくMacbookのウィンドウに手の所作が表示された。

__キーボード入力には反応しなかった。今後、*key = cv2.waitKey(1) & 0xff*ではなく、*msg = input("")*で、キーボード入力を受け付けるように、コードを書き換えてみたい。__

```bash:Terminal
electron@diynoMacBook-Pro examples % python3 manual-control-opencv.py
[INFO] tello.py - 107 - Tello instance was initialized. Host: '192.168.10.1'. Port: '8889'.
[INFO] tello.py - 422 - Send command: 'command'
[ERROR] tello.py - 442 - 'utf-8' codec can't decode byte 0xcc in position 0: invalid continuation byte
[INFO] tello.py - 422 - Send command: 'command'
[INFO] tello.py - 446 - Response command: 'ok'
[INFO] tello.py - 422 - Send command: 'streamon'
[INFO] tello.py - 446 - Response streamon: 'ok'
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] non-existing PPS 0 referenced
[h264 @ 0x7fb9bb0d2800] decode_slice_header error
[h264 @ 0x7fb9bb0d2800] no frame!
[INFO] tello.py - 422 - Send command: 'takeoff'
[INFO] tello.py - 446 - Response takeoff: 'ok'
[h264 @ 0x7fb9ba08cc00] left block unavailable for requested intra mode
[h264 @ 0x7fb9ba08cc00] error while decoding MB 0 9, bytestream 9067
[h264 @ 0x7fb9b9860200] left block unavailable for requested intra mode
[h264 @ 0x7fb9b9860200] error while decoding MB 0 5, bytestream 10250
[h264 @ 0x7fb9ba08cc00] left block unavailable for requested intra mode
[h264 @ 0x7fb9ba08cc00] error while decoding MB 0 27, bytestream 3395
[h264 @ 0x7fb9b9860200] left block unavailable for requested intra mode
[h264 @ 0x7fb9b9860200] error while decoding MB 0 38, bytestream 980
[h264 @ 0x7fb9b905d000] error while decoding MB 19 41, bytestream -6
[h264 @ 0x7fb9b9879800] error while decoding MB 26 44, bytestream -6
[h264 @ 0x7fb9b905d000] error while decoding MB 15 44, bytestream -6
[h264 @ 0x7fb9ba07d800] error while decoding MB 40 41, bytestream -14
[h264 @ 0x7fb9ba07de00] error while decoding MB 45 36, bytestream -5
[h264 @ 0x7fb9b9860200] error while decoding MB 7 40, bytestream -8
[h264 @ 0x7fb9b905d000] error while decoding MB 18 44, bytestream -8
[h264 @ 0x7fb9ba08cc00] error while decoding MB 54 44, bytestream -8
[INFO] tello.py - 422 - Send command: 'land'
^C
electron@diynoMacBook-Pro examples % 
```

###動かしたスクリプトのソースコード

```Python3:manual-control-opencv.py
# simple example demonstrating how to control a Tello using your keyboard.
# For a more fully featured example see manual-control-pygame.py
# 
# Use W, A, S, D for moving, E, Q for rotating and R, F for going up and down.
# When starting the script the Tello will takeoff, pressing ESC makes it land
#  and the script exit.

from djitellopy import Tello
import cv2, math, time

tello = Tello()
tello.connect()

tello.streamon()
frame_read = tello.get_frame_read()

tello.takeoff()

while True:
    # In reality you want to display frames in a seperate thread. Otherwise
    #  they will freeze while the drone moves.
    img = frame_read.frame
    cv2.imshow("drone", img)

    key = cv2.waitKey(1) & 0xff
    if key == 27: # ESC
        break
    elif key == ord('w'):
        tello.move_forward(30)
    elif key == ord('s'):
        tello.move_back(30)
    elif key == ord('a'):
        tello.move_left(30)
    elif key == ord('d'):
        tello.move_right(30)
    elif key == ord('e'):
        tello.rotate_clockwise(30)
    elif key == ord('q'):
        tello.rotate_counter_clockwise(30)
    elif key == ord('r'):
        tello.move_up(30)
    elif key == ord('f'):
        tello.move_down(30)

tello.land()

```

###環境構築

- pip3 install djitellopyは、__[前の記事](https://qiita.com/electronics_diy721/items/990736c1ba6425fe3df9)__で済ませています。

DJI TelloPyのサンプル用のスクリプトファイルを取得するため、以下の公式リポジトリを*git clone*

- [damiafuentes / DJITelloPy](https://github.com/damiafuentes/DJITelloPy)

```bash:Terminal
electron@diynoMacBook-Pro Desktop % git clone https://github.com/damiafuentes/DJITelloPy.git
Cloning into 'DJITelloPy'...
remote: Enumerating objects: 478, done.
remote: Counting objects: 100% (151/151), done.
remote: Compressing objects: 100% (94/94), done.
remote: Total 478 (delta 94), reused 108 (delta 56), pack-reused 327
Receiving objects: 100% (478/478), 153.58 KiB | 1.15 MiB/s, done.
Resolving deltas: 100% (275/275), done.
electron@diynoMacBook-Pro Desktop % 
```

__manual-control-opencv.py__が格納されているディレクトリに移動

```bash:Terminal
electron@diynoMacBook-Pro Desktop % cd DJITelloPy 
electron@diynoMacBook-Pro DJITelloPy % ls
LICENSE.txt		djitellopy		docs			mkdocs.yml		setup.cfg
README.md		doc-requirements.txt	examples		requirements.txt	setup.py
electron@diynoMacBook-Pro DJITelloPy % 
electron@diynoMacBook-Pro DJITelloPy % cd examples 
electron@diynoMacBook-Pro examples % ls
manual-control-opencv.py	mission-pads.py			simple-swarm.py			take-picture.py
manual-control-pygame.py	record-video.py			simple.py
electron@diynoMacBook-Pro examples % 
```