DJI公式SDK「Tello-Python」を試そう

(2023年6/28追記)

DJI公式SDKのTello-Pyhtonを今から学ぶのは、正直オススメしません。
Telloを動かすプログラムをPythonで書く場合について、ここに紹介しておきます。

# TelloのPythonプログラミング

TelloをPythonで動かす方法は色々ありますが、筆者の把握している方法について以下に(独断と偏見ありで)解説します。
<dl>
  <dt>UDPのソケットプログラムを自力で書く</dt>
  <dd>　TelloのSDKは、バイナリーのパケットではなくテキスト平文なので、UDPのソケットプログラムさえできれば動かすことができます。たとえば、以下のたった4行のプログラムでも動かせます。

```python:Telloの最低動作プログラム
import socket
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )   # UDPソケットの作成
msg = input('command? = ')   # 送信するコマンドをキーボード入力 commandとかtakeoffとか
sock.sendto( msg.encode('utf-8'), ('192.168.10.1', 8889) )   # Telloへ送信
```
とはいえ、カメラ映像の受信やデコードの処理を自力で書くのはとても大変です。
Pythonプログラミングの入門などで少し動かすのには良さそうです。<br><br></dd>
  <dt>Ryze Tech.公式の　<a href="https://terra-1-g.djicdn.com/2d4dce68897a46b19fc717f3576b7c6a/Tello%20%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/Both/Tello3(1).py">Tello3.py</a>　というサンプルを使う</dt>
  <dd>　この公式なSDKのサンプルプログラムはPython3用で書かれています。しかし、UDPのソケットプログラムを書くだけで、Telloに特化したクラス化などはしていません。また映像の受信やデコードには対応していないので画像処理はできません。やれることはスマホアプリやScratchと同程度の離着陸・移動だけです。プログラムが古いファームウェア用に書かれており、ステータスのポート番号が9000になっているので、現在は動きません<br><br></dd>
  <dt>DJI公式の　<a href="https://github.com/dji-sdk/Tello-Python">Tello-Python</a>　を使う</dt>
  <dd>　Ryze Tech.に技術供与しているDJIが出したTello SDKのサンプルプログラム集です。DJIなので安心してしまいそうですが、色々問題点があります。まずはPython2用プログラムであることです。Python2は2020年でサポートが終了してしまいました。最新のLinuxではそもそもPython2がインストールされていないこともあります。Bullseye版のRaspberry Pi OSもPython2は入っていません。２つ目は、Githubの更新が止まっている点です．3年ほど前からメンテナンスされていないので、最新のSDK3.0にも対応していません。そして最大の問題点はTelloのカメラ映像のH.264圧縮をデコードするライブラリをセルフビルドする必要がある点です。cmakeやboostを使ってソースから自分でビルドするという方法はデコード速度が最も速いので魅力的なのですが、入門者には難易度が高く、Tello_Videoが動かせず挫折してしまう人が多いです。筆者もこのページで記事を書いていますが、癖の強いサンプルだと感じています。<br><br></dd>
  <dt>pipでインストールできるpythonライブラリ　<a href="https://github.com/hanyazou/TelloPy">TelloPy</a>　を使う</dt>
  <dd>　バイナリモードでTelloを取り扱えるようにしてくれたPython用のライブラリがTelloPyです。pipで簡単にインストールできるので便利です。Python3にも対応しています。バイナリなので通信が速いのが特徴です。video_effect.pyというOpenCVでの画像処理サンプルもあり、すぐ試すことができるようになっています。H.264のデコードはFFMpegのライブラリPyAVを使っているのでセルフビルドの必要がありません。しかし、SDKモードのライブラリではないので、SDK2.0のインフラストラクチャ接続やミッションパッドの機能には対応していません。SDK3.0のモータON/OFFやポート変更の機能もまだありません。Windowsではインストールにてこずることが多く「動かなかった」という声も多く聞きます。Raspberry Piでは特に問題なくインストールできます。<br><br></dd>
  <dt>ROS1の　<a href="http://wiki.ros.org/tello_driver">tello_driver</a>　を使う</dt>
  <dd>　上述したTelloPyを使ったROS1用のパッケージがtello_driverです。ROSを使って、SLAMなどの高度に知能的なことをする場合には、TelloPyとtello_driverを組み合わせることになります。まあROSが使える人はもはや入門者じゃないですね。公式のtello_driverはPython2用なので、Python3で使いたい場合にはフォークしたものを使うと良いでしょう。<br><br></dd>
  <dt>ROS2の　<a href="https://github.com/tentone/tello-ros2">tello-ros2</a>　を使う</dt>
  <dd>　ROS1用のパッケージはバイナリのTelloPyを使っていますが、ROS2用のパッケージでは後述するDJITelloPyを使っています。<br><br></dd>
  <dt>pipでインストールできるpythonライブラリ　<a href="https://github.com/damiafuentes/DJITelloPy">DJITelloPy</a>　を使う</dt>
  <dd>　名前はTelloPyに似ていますが、バイナリではなくSDKを使うライブラリです。Python3に対応しており、SDK3.0への対応も行われています。H.264のデコードはTelloPyと同じPyAVを使っているのでセルフビルドの必要がありません。また、有志の掲示板に上がっているような隠しコマンドにも対応しているので、下向きカメラへの切り替え機能もあります。pipでインストールする際には、依存関係にあるOpenCVのインストールも自動で行われます。<br></dd>
</dl>
以上のことから、

- Python3対応
- SDK3.0対応
- H.264のデコードライブラリで苦労しない
- 環境構築が比較的簡単

の点から、当分の間は　DJITelloPy　が良さそうです。

DJITelloPyのリファレンスマニュアルは　[このページ](https://djitellopy.readthedocs.io/en/latest/)　にあります。


(2022年4/27追記)
本Qiita記事をSDK3.0とPython3とDJITelloPyを利用する形式にリファインして，
CQ出版のInterface 2022年4月号の特集記事「第2部　自律飛行1…Telloで撮ってラズパイで画像処理」
を書かせていただきました．
紹介が遅くなりましてすみません．パクリ記事疑惑が浮上したので，両方私ですよ～と(^^

https://interface.cqpub.co.jp/magazine/202204/

ページ数の都合で，ARやQRの記事が書けなかったのが残念ですが(T_T)

公式Tello-PythonはPython2なのでDJITelloPyを使ったのですが，H.264のデコードに使ってるPyAVが頻繁に停まるのが残念です．．．

今，公式Tello-Pythonのtello.pyを，セルフビルドデコーダやPyAVを使わず，OpenCVのデコーダを利用する形に改変し，SDK3.0にも対応させていますので，今後はそちらの記事を書こうと思います．


(2020年6/23追記)
DJITelloPyの記述を追加しました．
インストールして試してみましたが，TelloPyとTello-Pythonをミックスした様なライブラリでした（pigame使うとことか，TelloPyっぽい）
画像フレームの更新がちょっと遅いのが気になりました．

# はじめに

Ryze Tech.のTelloのプログラミング方法の１つに、DJIの公式SDK「Tello-Python」があります。

https://github.com/dji-sdk/Tello-Python

本ページでは、このTello-Pythonの導入とサンプルプログラムの動作、応用プログラムの作り方を解説したいと思います。

# 概要

https://www.ryzerobotics.com/jp/
Ryze Technology社の200g未満のミニドローン「Tello」シリーズは、飛ばして遊ぶだけの他のトイドローンとは異なり、ScratchやPythonのプログラムで動かすことができるのが魅力です。

完成品でプログラマブルなドローンはParrot社の独壇場でしたが、ANAFI以外の製造終了に伴ってTelloへのシフトが予想されます。ANAFIは高価なので、プログラムして遊ぼうという気になれませんね．暴走して壊れたら(T_T)

TelloのPythonプログラミングには、

1. 有志によって解析されたバイナリデータを用いる方法
2. pipでインストールできるpythonライブラリ　[TelloPy](https://github.com/hanyazou/TelloPy)　を使う
3. Ryze Tech.が公開している　[Tello3.pyというサンプル](https://terra-1-g.djicdn.com/2d4dce68897a46b19fc717f3576b7c6a/Tello%20%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/Both/Tello3(1).py)　(ただしポート番号がちょっと違う)
4. gitでダウンロードしてインストールする　[DJITelloPy](https://github.com/damiafuentes/DJITelloPy)　を使う
4. DJIのTello-Python (https://github.com/dji-sdk/Tello-Python)

がありますが、3.と4.と5.はRyze Tech.が公開している<font color="blue">**Tello SDK**</font>に基づいて作られています。
Tello SDKは、`takeoff`,`land`などの文字列を送信するだけでTelloを動かせるので簡単です。

# Telloの種類

2019年9月現在、Telloには以下の３種類があります。

- [Tello](https://www.ryzerobotics.com/jp/tello)　（Tello SDK 1.3）
- [Tello アイアンマン エディション](https://www.ryzerobotics.com/jp/ironman)　（Tello SDK 1.3）
- [Tello EDU](https://www.ryzerobotics.com/jp/tello-edu)　（Tello SDK 2.0）

Tello EDUのみがミッションパッドやインフラストラクチャ接続をサポートするSDK2.0です。
無印Telloとアイアンマンは同じものでSDK1.0系になります。

使い方は多くのトイドローンと同様に、電源を投入すると**Tello自体がWiFiアクセスポイント(WiFi親機)**となり、スマートフォンやＰＣで接続しに行く形態です。

なお、Tello EDUはWiFi子機となってアクセスポイントに接続することができるため、複数台での同時管理、すなわち編隊飛行が可能になります。
したがって「将来的に編隊飛行までやりたい」と考えている人はEDUを購入したほうが良いでしょう。少しお値段が高くなりますが。
無印のfirmwareを書き換えてEDU化する，などのhackは見つかっていませんので(笑

# 準備するもの

- Linux環境　＋　無線ＬＡＮ

　　動作確認済みＯＳ：
　　　・インテル系PC　Ubuntu-MATE 16.04(x64)および18.04(x64)
　　　・Raspberry Pi　Raspbian stretch

Telloに接続するためには無線ＬＡＮの環境が必要です。
ノートＰＣであれば問題ありませんが、デスクトップ機ではUSB無線LANドングルを利用してください。なお、Telloは2.4GHzなので，Linuxでドライバの導入が大変になる事が多い5GHz製品を買う必要はありません。

普通のＰＣとラズパイとでは、環境設定の手順が異なります。
また、Windowsでの環境設定はBATファイルの書き換え等の追加作業が必要なため、今後の予定としておきます。

# Telloのプログラミング？

**<font color="red">Tello本体そのものにはプログラムをする機能も，プログラムを書き込むメモリ領域もありません．</font>**

勘違いしている人が多いので，しっかりと明記しておきます．
「TelloでSTEM教育」も流行ってきているため，嘘を教えないで欲しいからです．

一般的に「Telloのプログラミング」と呼ばれている行為は，以下の図の様な流れになっています．

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/5593597a-902b-abd9-4ee3-e8a3efe888db.png" width=60%>

1. Telloのカメラ映像やセンサーデータをＰＣ(通称：母艦）で受け取る
2. 母艦ＰＣで画像処理やデータ処理をして，Telloの動き方を計算する
3. Tello SDKに基づいて，Telloへコマンドを送信する
4. Telloが動く
5. 1へ戻って繰り返す

Telloはいわば「知能を持たない移動端末」で，知能的な計算をしているのは母艦ＰＣです．

この様な外部計算方式のシステムは，以下の様に呼称されています．

・東大JSKだと「リモート・ブレイン」
　　頭脳である大型コンピュータは，小型ロボット本体内に収められないため，遠隔頭脳として提言された．

・「外部知能」
　　文字通り，知能部分は外部にあるので．

・「他律制御」
　　自己を律する「自律制御」に対して，他者が律するという意味で．

・タチコマ(攻殻機動隊SAC2)だと「脳なし？」
　　タチコマのAI部分のニューロチップは米帝の衛星に搭載されており，体は入出力端末に過ぎないため．

・AVR-0(機動警察パトレイバー)だと「HOS-SADの管制車」
　　AVR-0は実験段階だったため，衛星の支援情報などを処理する機器をレイバー本体に搭載することができず，随伴する管制車に置いてあった．


いずれも，外部のコンピュータで計算処理を行い，移動ロボットには命令を送るだけ，ロボット本体には知能がない，ということを意味しています．

繰り返しますが，**「Telloにプログラムを書き込む」という表現を使うのは間違いです．**


# 前提条件

本記事では、
　**「通常のスマートフォンでのTelloの飛行手順は理解している」**
ことを前提とします。
すなわち、

・Telloの電源ON/OFF
・WiFi親機となったTelloへ接続する
・離着陸や移動，宙返りなどの操作

などの基本操作の説明は致しません。

# Tello-Pythonのダウンロード

本記事では、Tello-Pythonをホームディレクトリに置くとして話を進めます。

まずは、`git`がインストールされていなかったらインストールします。

```bash:gitがなかったらインストール
$ sudo apt install git
```
次に，Tello-Pythonをgitでダウンロードします。

```bash:Tello-Pythonの導入
$ cd ~
$ git clone https://github.com/dji-sdk/Tello-Python.git
```
するとホームディレクトリには`Tello-Python`というディレクトリができます。
Tello-Pythonのディレクトリ内には、４つのサンプルプログラムがあります。
以下の図で赤・橙で囲まれたフォルダおよびファイルです。
![tello_python_folder.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/5ee141ee-cfdf-3e09-7e62-f15de0bfd88f.png)

赤で囲まれたサンプルは、python環境さえあれば実行可能な簡単なサンプルです。
しかし、橙のサンプルでは各ディレクトリ内にあるシェルファイル(.sh)でOpenCVのインストールやH.264デコーダライブラリのビルドなどの作業が必要です．
<font color="red">**しかし，Ubuntu16.04やRaspbianでは望み通りの環境設定ができないため、少々工夫が必要になります．**</font>

（追記）Windowsの場合は，[これ](https://github.com/dji-sdk/Tello-Python/archive/master.zip)をダウンロードして，解凍してください．
解凍する場所はホームフォルダ(c:￥Users￥(ユーザー名)￥)が良いです．
すなわち'c:￥Users￥(ユーザー名)￥Tello-Python-master￥'となります．

# Tello-Pythonのサンプルプログラム

0. [「tello_state.py」を動かす](https://qiita.com/hsgucci/items/7067e356eda5ba2d8e73)
1. [「Single_Tello_Test」を動かす](https://qiita.com/hsgucci/items/a199e021bb55572bb43d)
2. [「Tello_Video」を動かす](https://qiita.com/hsgucci/items/c9082690c6d0695b722f)
3. [「Tello_Video_With_Pose_Recognition」を動かす](https://qiita.com/hsgucci/items/c28df7fffe52811060f5)
4. [「Tello_Video」の改造](https://qiita.com/hsgucci/items/06411566b8a05575d71c)
5. 　[(補足)Python3で「Tello_Video」を動かす](https://qiita.com/hsgucci/items/cbcb8da6941a9981c11e)

# OpenCVを使った応用

1. [「Tello_Video」のTelloクラスを使おう](https://qiita.com/hsgucci/items/d1df1122853ee6dd4bf7)
2. [キー入力操縦プログラム](https://qiita.com/hsgucci/items/bcdcdf162d5842a79b11)
3. [ジョイスティック操縦プログラム](https://qiita.com/hsgucci/items/a5926dd396b319e6ccaf)
1. [OpenCVを使うスケルトンプログラム](https://qiita.com/hsgucci/items/4bf1ef324837665f6b60)
1. [ARマーカ認識プログラム](https://qiita.com/hsgucci/items/37becbb8bfe04330ce14)
1. [顔検出プログラム](https://qiita.com/hsgucci/items/5d4e4de933a14820795b)
1. [色検出プログラム](https://qiita.com/hsgucci/items/e9a65d4fa3d279e4219e)
1. [QRコード認識プログラム](https://qiita.com/hsgucci/items/9fc6d079119bdc391349)
2. [ライントレースプログラム](https://qiita.com/hsgucci/items/4a5aa35aa9fd036621a7)
3. カラーコーントレースプログラム
3. 輪くぐりプログラム
4. DonkeyCarプログラムとの融合(要Python3化)

# Tello EDUを使った編隊飛行

1. Tello EDUの設定
2. Tello_VideoのTelloクラスをEDU用にダウングレードする
3. キー入力で複数台を操縦
4. ジョイスティックで複数台を操縦

# WiFi接続時の注意点

複数のTelloがある場合、下図の様にWiFiアクセスポイントとしてTelloも複数見えます．
![tello_double.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/95b13679-95a4-2df2-29d9-25a3f4228055.png)

どちらが自分のTelloかな？と迷う時はバッテリーを外してみると分かります。
![tello_ssid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/479ad8ae-983d-7d63-23d5-a47d8322ece7.png)

混乱を避けるために、スマートフォンのTelloアプリでSSIDをオリジナルの名前に変えてしまうという方法もあります。
例えばアイアンマンエディションなら「TELLO_Mk42」とか？（笑
![tello_change_name.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/c53fbded-32a2-0197-6eb4-9ea094d2a37d.png)

# プログラミング中は熱に注意

プログラミングの際には，Telloの電源を入れたまま地上で待機させ続ける事が多いです．
書き終わって「さあ試すぞ！」と実行してみるとエラー．．．
．．．あれ？なんで？．．．
**<font color="red">よく見るとTelloの電源が落ちています．</font>**


TelloはIntel Movidiusチップを使ったビジョンポジショニング機能があるため，機体下面が非常に発熱します．更にサーマルシャットダウンの機能があり，温度が高すぎると勝手に電源を落としてしまいます．
　参考：[システムオーバーヒートに関しまして](https://info.system5.jp/dronefaq/archives/4015)

スマートフォンで飛行をしている際には風が当たるので問題ないのですが，
地上待機時は熱が逃げないので，すぐにシャットダウンしてしまいます．

筆者は以下の工夫をしています．
「USB扇風機で風を当てる」
![tello_fan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/38c4a3ab-267c-65f9-5fac-982b7480f80e.png)

「放熱フィンに被さっているプラをニッパで切り取る」
![tello_cut.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/00b9ee61-23dc-c8f5-6b08-dff0d8320894.png)

「カバーなんていらない」
![tello_no_cover.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/74c8adc1-b62d-550c-fe7b-e2700517fda1.png)