小型ドローンとPythonを用いたプログラミング教育（対象：高校生以上）

# イントロダクション
## 経緯
理系と文系の両方の大学でプログラミングなどの情報教育に関わり、これまで Java や Excel VBA、R、Pythonなどを担当して15年ほどになります。小型ドローン（無人航空機）を用いたプログラミング演習は、2020年度から開始して約250人の学生を対象に実習を行ってきました。

人工知能のブームや、小中高でのプログラミング教育など必修化などの背景もあり、プログラミング教育の需要が増加しました。需要が増加する一方で、プログラミングに苦手意識を持つ学生も増えているにもかかわらず、プログラミング教育のノウハウは、一部しか伝わってないように感じています。

## 目的
本記事の目的は以下の二つです。
- 高校生や大学生を受け持つ教員に向けて小型ドローンを用いたプログラミング教育のノウハウの共有
- プログラミング初心者にプログラムを動かせた実感を持ってもらいながら、プログラミングが楽しいと思えるようなノウハウの共有

## 内容
- Pythonによるプログラミングを通して小型ドローンを比較的短いプログラムで飛行させます。
- 本記事は、本記事の対象者が講義の題材として利用できるように掲載しています。

## 対象者
- 高校生以上を担当する教員
- プログラミングの学習を続けたけどプログラムを動かしている実感が湧かないプログラミング初心者

本記事のプログラミング初心者は、プログラムの動作の順番や変数を学んだことをある生徒や学生を指します。

# 道具
## スマートフォン
教員側の事前準備として iPhone or iPad, Android が必要です。
スマートフォン用のTelloを操縦するアプリケーション（[Tello App](https://www.dji.com/jp/downloads/djiapp/tello)）をインストールしてください。

## パソコン
BYOD（Bring Your Own Device）という個人所有の端末を持ち込んで学習に使用することを前提としています。そのため、学生所有のPythonの実行が可能な Windows または Mac が必要です。加えてWi-Fi接続が可能な端末が必要です。

## RYZEのTELLO（テロ）とバッテリー
下記リンクのTELLOという小型ドローン（トイドローン）を利用します。
https://www.ryzerobotics.com/jp/tello

著者はバッテリーと充電器が付属している[TELLO ブーストコンボ](https://amzn.asia/d/iWfSqa5)を充電管理の手間が省けるため購入しています。

必要な台数は1グループ（3名前後）にTELLOを1機です。1グループには2個または3個のバッテリーがあれば、プログラム作成の時間などがあるため、100分の授業でも十分に足ります。

注意：TELLOには追加でプロペラガードの購入ができます。しかし、TELLO本体に付属している以上の大きなプロペラガードは重量が増える上に、空気抵抗も増すため、Pythonの命令が想定通りに動作しないことがあります。


# 法令について
ドローンを利用する際に悩む要因が[航空法](https://www.mlit.go.jp/koku/koku_tk10_000003.html)です。結論から先に述べると、TELLOは航空法に抵触しません。つまり、航空法に関する登録等の手続は不要になります。これはTELLOが100g未満の機体のためです。もし本記事で紹介していない100g以上の機体を利用する場合は各種申請が必要です。

ただし、建物の管理者がドローンを飛ばすことに対して申請を求めている場合は、その建物の管理者に申請する必要があります。例えば大学の場合には施設課に申請します。

# 講義例
講義は講義の事前準備、安全講習会、プログラムの解説、演習のパートに分けて準備・実施します。

## 講義の事前準備
PythonでTELLOを操縦するには、スマートフォン上のアプリで一度飛行させる必要があります。新品のTELLOの場合は、最初からPythonでの操縦を試みると、パソコンとTELLOの接続ができません。

[Tello App](https://www.dji.com/jp/downloads/djiapp/tello) を用いて、次の手順でTelloの離陸と着陸をさせてください。
- TELLOのバッテリー挿入部分に記載されてるWiFiのIDである「TELLO-XXXXXX」をメモします。
- TELLOの電源を入れます。
- スマートフォンのWiFiを「TELLO-XXXXXX」に切り替えます。
- スマートフォンからTELLOアプリを起動します。
- TELLOのアプリ画面の右下に「Telloに接続」ボタンをタップして、TELLOとスマートフォンを接続します。
- 安全な場所で、アプリ画面の左上の![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154819/49cece9f-31a4-a34e-7f10-7dc24ded2fb6.png) をタップして離陸し、ホバリング後、アプリ画面の左上の![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154819/57df02c4-5466-ed94-4006-9d1a8aa46e70.png)をタップして着陸を行います。

Tello App の 画面説明や操縦方法は、[マニュアル](https://dl-cdn.ryzerobotics.com/downloads/Tello/201806mul/Tello%20User%20Manual%20V1.0_JP.pdf)の16ページから19ページを参考にしてください。


注意：授業時間に余裕がある場合には、履修者に上記の作業をさせることも考えられます。しかし、ラジコンのように操作することができるため事故に注意が必要です。

## 安全講習会
小型ドローンでも安全講習会が重要です。ここでしっかりと安全の重要性を説明しないとドローンを故意に人へ衝突させるような行為をする学生が現れ、不要な事故が発生します。

少し大袈裟に聞こえるかもしれませんが、事故を発生させないために下記の内容を十分に理解してもらう必要があります。安全講習をサボると、遊び半分でふざけた行動を起こす学生が発生して大変危険です。
- DJIの[無償付帯賠償責任保険](https://drone.aeroentry.jp/insurance/free)を参考に賠償補償金額を伝える
    - 保険プランとして「対人賠償の1事故つにき1億円」が存在すること
    - 事故を起こす場合は自動車事故並、またはそれ以上に大変であること
- 大怪我の恐れを伝える
    - 回転中のプロペラが目に入れば失明の可能性があること
    - 指の切断や骨折の事故の報道があったこと

その後に、**どこでも、いつもで飛ばせるという状況**を回避すること念頭に、PythonでTELLOを飛ばす際の注意事項を説明します。

- 飛行用のプログラムは複数人でチェックすること
- 飛行用のプログラムの完成後、担当教委員からのチェックを受けた後に飛行させること
- 担当教委員の目が届く、指定された場所でのみ飛行させること
- 飛行させる場合は人が周囲にいないことを確認すること
- 飛行前にはプロペラが曲がっていたり傷がないことを確認すること

注意しても人が密集しているところで飛行させるなどの危険な行為をする場合は、そのグループに対してTELLOを用いた実習を中止して、別の課題を実施させることもありえることを事前にアナウンスしておきましょう。

## 準備
安全講習後、下記を実施してください。
- 1グループ3人程度のグループ分け
- グループごとにTELLOを1機とバッテリーを2個配布

## 機体の説明
実物の機体に触れながら、履修者にも手を動かしてもらいながら、次の点を説明します。詳細は[マニュアル](https://dl-cdn.ryzerobotics.com/downloads/Tello/201806mul/Tello%20User%20Manual%20V1.0_JP.pdf)の指定されたページ番号を参考にしてください。


- TELLOのバッテリー挿入部分に記載されてるWi-FiのIDである「TELLO-XXXXXX」をさせます。
- 電源ボタンの位置（[マニュアル](https://dl-cdn.ryzerobotics.com/downloads/Tello/201806mul/Tello%20User%20Manual%20V1.0_JP.pdf)のp4の画像引用）
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154819/458d88b0-654d-3e7b-328c-34d1222eb82e.png)
- 上記の画像の「1. プロペラ」、「3. 機体ステータスインジケーター」、「4. カメラ」、「8. フライトバッテリー」を実物の機体を見せながら説明します。 
- バッテリーの挿入方法（[マニュアル](https://dl-cdn.ryzerobotics.com/downloads/Tello/201806mul/Tello%20User%20Manual%20V1.0_JP.pdf)のp14の画像引用）を説明します。この際にはバッテリーの上下に注意を払うようにアナウンスします。
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154819/f09f5e27-810b-cac2-4e77-64795ff06723.png)
- 電源ボタンを押すことによる起動
- 起動によるLEDライト（3番の機体ステータスインジケータ）の色の種類を説明します。特に起動した際に赤、緑、黄色を交互に点滅することや、緑色と赤色の違いを説明します。
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154819/96ba99aa-1376-b000-10eb-69761cf07e90.png)
- 電源ボタンを再度押させ、電源をOFFにさせます。
- バッテリーの抜きかたを説明し、バッテリーを外します。

講義の時間に余裕があれば、プロペラの回転数の違いにより飛行すること（[参照](https://www.tead.co.jp/blog/%E3%83%89%E3%83%AD%E3%83%BC%E3%83%B3%E3%81%AF%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E4%BB%95%E7%B5%84%E3%81%BF%E3%81%A7%E9%A3%9B%E3%82%93%E3%81%A7%E3%81%84%E3%82%8B%E3%81%AE%E3%81%8B%E3%80%81/)）、それをPythonの予め定められた命令で簡単に操作できることを説明すると、履修者が何をしているのか理解が深まります。

履修者に説明する必要はありませんが、担当教員は[マニュアル](https://dl-cdn.ryzerobotics.com/downloads/Tello/201806mul/Tello%20User%20Manual%20V1.0_JP.pdf)のp7のビジョンポジショニングシステムを把握してください。特にp7の下部の注釈に記載れている機体を慎重に操作する場面を把握してください。思わぬ動作による事故を避けることができます。


## プログラムの配布と解説
下記の離陸と着陸に最低限必要なプログラムを配布してください。プログラムを配布後、プログラム内容をコメントに従って説明してください。
「import socket」に関連する命令は、本記事の中での目的から外れるため、Telloと履修者自身のパソコンを接続するための「オマジナイ」として説明しても問題ありません。可能であれば、ソケット通信を簡単に絵で説明できると履修者の理解度が深まりますが必須ではありません。

```py:離陸と起動
import socket # Pythonでソケット通信を行うためのライブラリ
import time # 処理の流れを一時的に止めるために時間関連のライブラリをインポート

##### TELLOと履修者のパソコンを接続するためのオマジナイ
ip = '192.168.10.1' # TELLOの工場出荷時のデフォルトのIPアドレス
port = 8889 # TELLOの工場出荷時のデフォルトのポート番号
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # パソコンとTelloの接続する。パソコン（クライアント）とTello (サーバー) を結ぶ仮想的な接続部分をソケットとして作成　
tello_address = (ip, port)
##### オマジナイ終了


##### TELLOへの命令
# コマンドモード（'command'）でTELLOを起動する
# コマンドモードでTELLOを起動すれば、直感的な用語（例えば'takeoff'）を命令として扱えるようになる。
socket.sendto('command'.encode('utf-8'), tello_address)
# 上記は直感的に説明すると「TELLOに対して、'command'というメッセージを送り、ドローンを操作できる状態にするためのコード」です。
## socket.sendto は「データを送る」という指示を出す部分です。ネットワークを使って、データ（メッセージや命令など）を送ります。
## 'command'.encode('utf-8') は、送るメッセージ「command」をデータとして準備する部分です。
## tello_address は、データを送りたい「送り先」の情報です。

##### 待機命令
# ドローンに「command」モード（操作を受け付ける状態）に入るよう命令を送った後、ドローンが準備を整えるための待機時間が必要です。すぐに次の命令を送っても、ドローンが「command」モードに入っていない場合、命令を受け取れないことがあるため、少し待つ必要があります。
# 下記の命令で停止させないと、パソコンは、プログラムをほぼ一瞬でTelloに送る。そのため、Tello側で命令受け取りの準備が終わるまで、パソコン側で待機する
time.sleep(5) # このプログラムの位置でプログラムに書かれている処理の進行を5秒間停止
##### 待機命令終了

##### 離陸命令
# TELLOに「takeoff」という離陸命令を送り、ドローンを空中に浮かび上がらせます。
socket.sendto('takeoff'.encode('utf-8'),tello_address) #離陸のため'takeoff'コマンドを送る
##### 離陸命令終了


#### ホバリングまでの待機命令
# 離陸後のドローンを安定させ、次の動作をスムーズにするための時間を確保します。
# TELLOが安全に離陸して安定するまでの待機時間を設けるためです。TELLOが「takeoff」命令を受け取った後、実際に空中で安定するまでに少し時間がかかります。10秒の待機時間を設けることで、ドローンが適切な高度まで上昇し、ホバリング（静止状態）しながら次の命令を受け付ける準備が完了するまでの余裕ができます。
time.sleep(10) # 10秒間停止
#### ホバリングまでの待機命令終了


##### 離着陸以外の飛行に関する命令を記述
# ここの間（'takeoff' と 'land' ）に、前進命令などの具体的な命令を記述します。
# socket.sendtoで指示した処理が終わる時間も考えて、socket.sendtoとtime.sleepをセットで記述してください。特にtime.sleepを忘れることが多いため注意します。
#####

#### 着陸命令
# ドローンに「land」という命令を送って着陸させます。
socket.sendto('land'.encode('utf-8'),tello_address)
#### 着陸命令終了


time.sleep(5) # 着陸を待つために5秒間待機
socket.close() # 通信終了
```


## 飛行実習
履修者に離陸と着陸のプログラムを実行させて、TELLOを離着陸させます。自由気ままに飛ばさせないために、担当教員または授業補佐によるプログラムをチェックする過程を入れてください。

プログラムをチェックする過程では、履修者のプログラムが正しく書かれていることを確認します。特に、「離着陸の命令が書かれていること」や「time.sleepの入れ忘れ」に注意してくします。このタイミングでTELLOとパソコンの接続方法と飛行方法を下記のように教えます。このステップを踏まないと所構わず飛ばす学生増えて事故の原因になりますので注意してください。

- TELLOの電源をONにする
- パソコンのWi-Fi接続から、メモしたTELLOのWi-FI IDである「TELLO-XXXXXX」を選択して接続する
- 机や椅子など飛行の邪魔になるものがない開けたエリアにTELLOを置く
- 周囲に人がいないことを確認しながら、作成したPythonの離陸と起動のプログラムを実行する。
- TELLOが離着陸したことを確認し、TELLOの電源をOFFにする。



## 四角形を描くように飛行
次に下記のような細かいステップを踏みながら、四角形の経路を飛行するプログラムを作成させます。ここでいきなり四角形の経路を書かせると、どの方向に動くか分からないままのプログラムを

- 離陸後、前方に 20 cm 進み、着陸するプログラム
離陸と着陸のプログラムを改変してください。特に離陸と着陸の間の「##### 離着陸以外の飛行に関する命令を記述」の下にTELLOを前進させる命令を記入してください。20cmでは実感が湧かない履修者もいます。その際には、'forward 20'を'forward 50'に変更して前進して50cm進むという命令に変更を促します。

```py:前進20cm
##### 離着陸以外の飛行に関する命令を記述
# ドローンに「前進して20cm進む」という命令を送る
socket.sendto('forward 20'.encode('utf-8'),tello_address)
# "forward 20"という文字列が前進して20cm進むに該当する
time.sleep(10)
#####
```

TELLOのコマンドの一覧は[Tello SDK 2.0 User Guide](https://dl-cdn.ryzerobotics.com/downloads/Tello/Tello%20SDK%202.0%20User%20Guide.pdf)を参考にしてください。履修者らに、socket.sendto('TELLOに与えるコマンドの名前'.encode('utf-8'),tello_address)という構文を説明した後に、Tello SDK 2.0 User Guide の 前進命令の'forward' や、時計回りにその場で方向転換する'cw'などの見方と組み込みかたを教えます。

- 離陸後、前方に 20 cm 進み、その場で90度方向転換し、着陸するプログラム
Tello SDK 2.0 User Guideのおける'forward'と'cw'のPythonのプログラムとして書く方法を教えて、下記のプログラムを実行させます。

```py:前進20cmと方向転換
##### 離着陸以外の飛行に関する命令を記述
socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)

# ドローンに「90度右回転（時計回り）」するよう指示
socket.sendto('cw 90'.encode('utf-8'),tello_address)
time.sleep(10)
#####
```

- 離陸後、前方に 20 cm 進み、その場で90度方向転換し、前方に20cm進み、着陸するプログラム
同様にプログラムを作成させ飛行させます。
```py:前進20cmと方向転換、前進20cm
##### 離着陸以外の飛行に関する命令を記述
socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('cw 90'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)
#####
```

- 四角形の飛行ルート作成
段階を踏んだのちに四角形を描くように飛行させます。
```py:四角形
##### 離着陸以外の飛行に関する命令を記述
socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('cw 90'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('cw 90'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('cw 90'.encode('utf-8'),tello_address)
time.sleep(10)

socket.sendto('forward 20'.encode('utf-8'),tello_address)
time.sleep(10)
#####
```
最後にsocket.sendto('cw 90'.encode('utf-8'),tello_address)を4回記述する学生がいる場合には、本当に必要かどうかを考えさせてください。

# 最後に

本記事を用いた講義は、100分授業を4回から5回分実施することを想定しています。
- 1コマ目：四角形を描くように飛行させる
- 2コマ目：socket.sendto('curve 60 60 0 120 0 0 20'.encode('utf-8'),tello_address) を用いて円形の動作をさせて、どういう命令なのかを考えさせる
- 3コマ目 ~ 5コマ目：自由に飛行ルートを設計させ、それを実現するプログラムを作成させる。

上記のように設計すると、大学の講義であればプログラミングの導入や変数、条件分岐、繰り返し文、配列などを一通り終えた後の実習として機能します。