#はじめに
Telloを買ったらプログラムで操作したくなることに異論の余地はないと思います。
この記事ではC#でTelloを操作する方法について書きます。
Telloを操作する方法といっても、TelloにUDP通信でコマンドをbyte配列で送るなんてことをゴリゴリ書くのはチョットムズカシイため、あくまでそういったところをマルっとやってくれるライブラリを使って、ということになります。
#TelloLib
強い人がTelloをそうさするためのC#のライブラリをGitHubで公開してくれています。
それがTelloLib
です。
これを使うととても簡単にC#でTelloを操作することができます。
#入手方法
こちらにTelloLibとサンプルを含むVisual Studioのソリューションが公開されているので、git clone
するかzipファイルをダウンロードしてください。
簡単なコンソールアプリやAndroidアプリのサンプルプロジェクトがあるので、それを動かしたりしてもよいですが、今回用があるのはこの中のTelloLib
プロジェクトです。
#TelloLibをコンパイル
まずはTelloLibをコンパイルして、後で自分のプロジェクトから参照できるようにdllを生成しましょう。
Visual StudioでaTello.sln
ファイルを開きます。
ソリューションエクスプローラーのTelloLib
プロジェクト上で右クリックして、メニューからビルド
を実行してください。
dllファイルの出力先は、以下のようなソリューション構成であれば、以下のフォルダ内にTelloLib.dll
という名前であります。
...\TelloLib\bin\Debug
このTelloLib.dll
をこれから作る自分のプロジェクトで参照することで、このライブラリを利用できるようになります。
#プロジェクトを作る
これからTelloを操作するアプリケーションを作っていきます。
今回はシンプルなコンソールアプリケーションから離陸と着陸だけを行うプログラムを作成します。
Visual Studioを起動し、コンソールアプリ(.NET Core) Visual C#
プロジェクトを作成します。
プロジェクト名はここではMyTelloConsole
とします。
もちろん何でもよいです。
#参照を追加する
プロジェクトに先ほど生成したTelloLib.dll
ファイルへの参照を追加します。
ソリューションエクスプローラーの依存関係
を右クリックして参照の追加
を選択します。
参照するファイルの選択
ダイアログが開くので、先ほど生成したTelloLib.dll
ファイルを選択して追加
ボタンを押します。
これでライブラリを利用する準備が整いました。
#プログラムを書いていく
Main
メソッドに直接書いていくことにします。
今回のプログラムの流れは以下のとおりです。
- イベントハンドラを設定
- Telloとの通信初期化
- ループ内でコマンド入力→送信
##イベントハンドラを設定
Telloを操作するために使用するクラスはTello
クラスです。
このクラスには以下の3つのイベントがあります。
- onConnection
- onUpdate
- onVideoData
このうち今回必要なのはonConnection
イベントだけですが、これら3つのイベントはTelloLib
内ではイベントハンドラが設定されていない場合(つまりnullだった場合)の対処がされていないので、イベントハンドラを設定せずに実行すると、これらのイベントが発火されたときにnull参照で例外が発生することになります。
それらの例外はcatchされてコンソールにエラーメッセージが表示されてアプリケーション自体は動き続けるのですが、エラーメッセージが延々と出力され続けるのは困ります。
これを解決するにはライブラリ利用側で各イベントにイベントハンドラを設定するか、TelloLib側を修正して、それぞれのイベントが発火される箇所でnull条件演算子?.
を使ってnull参照を回避する、という方法が考えられます。こんな感じで。
onUpdate(100) → onUpdate?.Invoke(100)
今回はすべてのイベントにイベントハンドラを設定することにします。
するとこんな感じになります。
using System;
using TelloLib;
namespace MyTelloConsole
{
class Program
{
static void Main(string[] args)
{
Tello.onConnection += Tello_onConnection;
Tello.onUpdate += Tello_onUpdate;
Tello.onVideoData += Tello_onVideoData;
}
private static void Tello_onConnection(TelloLib.Tello.ConnectionState newState)
{
}
private static void Tello_onVideoData(byte[] data)
{
}
private static void Tello_onUpdate(int cmdId)
{
}
}
}
この中で今回必要なのはonConnectionイベントのイベントハンドラ(ここではTello_onConnection
)だけです。
このイベントハンドラはTelloとの通信のステータスが変化したときに実行されます。
このイベントの重要な役割は、Telloとの通信が開始されたらTelloの初期設定を行うことです。
このイベントハンドラは変化後のステータスが引数(newState
)として渡されて実行されるので、このnewState
がConnected
になったらTelloの初期設定が行われるようにします。
private static void Tello_onConnection(TelloLib.Tello.ConnectionState newState)
{
if (newState == Tello.ConnectionState.Connected)
{
Tello.queryAttAngle();//???
Tello.setMaxHeight(1);//最大高度?メートル?
}
}
このコードについてはサンプルプログラムのTelloConsole
内のMain
メソッドを参照してください。
setMaxHeight
メソッドはわかります。可能最大高度を指定するのでしょう。メートル単位で。
しかしqueryAttAngle
メソッドがわかりません。わかりませんがきっと必要と思われるので、ここではおまじないとしておきます。
#Telloとの通信を開始
Telloとの通信は以下の1行で開始されます。
シンプルでよろしいですね。
これをMain
メソッド内に追加します。
Tello.startConnecting();//接続開始
詳しいことはおいといて、この接続処理によって前述の通信ステータスがConnected
になったときにonConnection
イベントが発火されて、設定したイベントハンドラによってTelloの初期設定が行われることになります。
この時点でMain
メソッドは以下のとおりです。
static void Main(string[] args)
{
Tello.onConnection += Tello_onConnection;
Tello.onUpdate += Tello_onUpdate;
Tello.onVideoData += Tello_onVideoData;
Tello.startConnecting();//接続開始
}
#コマンド送信
whileループでユーザーからのコマンド入力を受け付け、それに応じてTelloを操作するようにします。
基本的な形は以下のとおりです。
var inputStr = "";
while (inputStr != "exit")
{
inputStr = Console.ReadLine().ToLower();
//inputStrの内容に応じた処理を書く
}
今回は以下の3つのコマンドを受け付けるようにします
- takeoff 離陸
- land 着陸
- exit アプリケーションの終了(ループから抜ける)
離陸と着陸についてはTelloLib
にそれぞれtakeOff
メソッドとland
メソッドが用意されていて、これらを呼び出すだけでよくなっています。
ユーザーからの入力に加えて、Telloとの通信ステータス、そして飛行中か否かのステータスを条件としてそれぞれのメソッドを実行するようにします。
加えて、exit
と入力されたときにループから抜けてアプリケーションが終了するようにします。
var inputStr = "";
while (inputStr != "exit")
{
inputStr = Console.ReadLine().ToLower();
//離陸
//Telloと接続中、かつ、飛行していない
if (inputStr == "takeoff" && Tello.connected && !Tello.state.flying)
{
Tello.takeOff();
}
//着陸
//Telloと接続中、かつ、飛行中
if (inputStr == "land" && Tello.connected && Tello.state.flying)
{
Tello.land();
}
}
//とりあえず着陸命令だしておく
Tello.land();
以上で、離陸と着陸だけするプログラムが完成しました。
完成したMain
メソッドは以下のようになります。
static void Main(string[] args)
{
Tello.onConnection += Tello_onConnection;
Tello.onUpdate += Tello_onUpdate;
//Tello.onVideoData += Tello_onVideoData;
Tello.startConnecting();//接続開始
var inputStr = "";
while (inputStr != "exit")
{
inputStr = Console.ReadLine().ToLower();
//離陸
//Telloと接続中、かつ、飛行していない
if (inputStr == "takeoff" && Tello.connected && !Tello.state.flying)
{
Tello.takeOff();
}
//着陸
//Telloと接続中、かつ、飛行中
if (inputStr == "land" && Tello.connected && Tello.state.flying)
{
Tello.land();
}
}
//とりあえず着陸命令だしておく
Tello.land();
//これだと、命令が送られる前にアプリケーションが終了してしまうので、
//ちょっと待つ
Thread.Sleep(1000);
}
では実際にTelloを操作してみましょう。
#やってみよう
##TelloとPCを接続
ここでいう接続とはTelloとPCをWifi接続するということです。
まず、Telloの電源を入れます。
しばらく待つと、LEDが黄色く速く点滅を繰り返すようになります。
Telloが起動しましたが、端末との接続がない状態です。
次にPC側です。
PCが拾っているWifiのアクセスポイントのリストに「TELLO-****」という名前のアクセスポイントが現れるので、それを選択して接続します。
「接続済み」となればOKです。
この時点ではTelloは相変わらずLEDが黄色く速く点滅していて何の変化もみられませんが大丈夫です。
##コンソールアプリケーションから操作
いよいよコンソールからTelloを操作してみましょう。
といっても離着陸だけですが。
実行してみてください。
コンソールが表示され、Connected!
と表示されたら、takeoff
と入力してエンターキーを勢いよく押しましょう。
離陸しましたか?
結構、おおー、って思っちゃいますよね。
続けてland
と入力してこれまた勢いよくエンターキーを押しましょう。スターン!
着陸しましたか。
#おわりに
今回は離着陸のみの簡単なものでしたが、これじゃなんだか物足りませんよね。
次は前進、後退、左回転、右回転について書きたいと思います。