トイドローン Tello をM5Stack+EAO 鍵スイッチで緊急着陸させるメモ
トイドローン Tello をM5Stack+EAO 鍵スイッチで緊急着陸させるメモです。
今回の仕組み

今回の仕組みとしては、他でTello操縦している状況をまず作ります。左右に揺れている感じです。

そのときに、M5Stack+EAO 鍵スイッチでUDPの着陸指示を出して強制着陸させます。
M5Stackソースコード
NefryBT(ESP32)でTelloを制御。1回だけ離陸して着陸する - Qiita
小型ドローンTelloの編隊飛行をESP32でやってみた : DJI Tello drone formation flight - Qiita
こちらを参考にして、以下のソースコードをM5Stackに書き込みます。
TELLO_SSID は自分のTelloのWi-Fi SSIDを入力します。
#include <WiFiUDP.h>
#include <M5Stack.h>
// TELLOのSSID
const char* TELLO_SSID = "TELLO-XXXXXX"; // 自分のTelloのWi-Fi SSIDを入力
// TELLOのIP
const char* TELLO_IP = "192.168.10.1";
// TELLO_PORT
const int PORT = 8889;
// ピン ON/OFF管理
int pinStateCurrent = LOW;
int pinState = LOW;
int connectPin = 2;
// UDPまわり
WiFiUDP Udp;
char packetBuffer[255];
String message = "";
void setup() {
Serial.begin(115200);
// Initialize the M5Stack object
M5.begin();
// EAO KEY INPUT_PULLUP
pinMode(connectPin, INPUT_PULLUP);
// START
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(10, 10);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(3);
M5.Lcd.printf("TELLO START");
// Start WiFi
Serial.println("Connecting to ");
Serial.print(TELLO_SSID);
WiFi.begin(TELLO_SSID, "");
// INFO
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(10, 100);
M5.Lcd.printf("TELLO_SSID: ");
M5.Lcd.println(TELLO_SSID);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// WiFi Connected
Serial.println("");
Serial.println("WiFi Connected.");
M5.Lcd.setCursor(20, 130);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(2);
M5.Lcd.println("> WiFi Connected.");
// UDP
Udp.begin(PORT);
sendMessage("command");
message = listenMessage();
Serial.println(":command");
Serial.println(message);
M5.Lcd.setCursor(20, 150);
M5.Lcd.println("> Tello Commanded.");
}
void loop() {
// buttonPin判定
int pinStateCurrent = digitalRead(connectPin);
if( pinStateCurrent != pinState){
pinState = pinStateCurrent;
if (pinState == HIGH) {
Serial.println("ON");
// テキスト反映
M5.Lcd.fillScreen(RED);
M5.Lcd.setCursor(10, 120);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setTextSize(4);
M5.Lcd.println("EAO KEY");
M5.Lcd.println(" > force land");
// 緊急着陸
sendMessage("land");
Serial.println(":land");
message = listenMessage();
Serial.println(message);
} else {
Serial.println("OFF");
// テキスト反映
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(10, 120);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.println("EAO KEY");
M5.Lcd.println(" > ----");
}
delay(1000);
}
if(M5.BtnA.wasPressed()) {
M5.Lcd.fillScreen(GREEN);
Serial.printf("wasPressed A \r\n");
M5.Lcd.setCursor(10, 120);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.setTextSize(4);
M5.Lcd.println("Button A");
M5.Lcd.println(" > takeoff");
// 離陸
sendMessage("takeoff");
Serial.println(":takeoff");
message = listenMessage();
Serial.println(message);
delay(1000);
}
if(M5.BtnB.wasPressed()) {
M5.Lcd.fillScreen(BLUE);
Serial.printf("wasPressed B \r\n");
M5.Lcd.setCursor(10, 120);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.println("Button B");
M5.Lcd.println(" > land");
// 着陸
sendMessage("land");
Serial.println(":land");
message = listenMessage();
Serial.println(message);
delay(1000);
}
if(M5.BtnC.wasPressed()) {
// M5.Lcd.printf("wasPressed C \r\n");
M5.Lcd.fillScreen(BLACK);
Serial.printf("wasPressed C \r\n");
M5.Lcd.setCursor(10, 120);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.println("Button C");
M5.Lcd.println(" > command");
// command
sendMessage("command");
message = listenMessage();
Serial.println(":command");
Serial.println(message);
delay(1000);
}
M5.update();
}
// Tello <- UDP
String listenMessage() {
int packetSize = Udp.parsePacket();
if (packetSize) {
Serial.print("Received packet of size ");
Serial.println(packetSize);
Serial.print("From ");
IPAddress remoteIp = Udp.remoteIP();
Serial.print(remoteIp);
Serial.print(", port ");
Serial.println(Udp.remotePort());
// read the packet into packetBufffer
int len = Udp.read(packetBuffer, 255);
if (len > 0) {
packetBuffer[len] = 0;
}
Serial.println("Contents:");
Serial.println(packetBuffer);
}
// this only works as tello's API doesn't return responses greater than 255 char
return (char*) packetBuffer;
}
// Tello -> UDP
void sendMessage(char* ReplyBuffer) {
Udp.beginPacket(TELLO_IP, PORT);
Udp.printf(ReplyBuffer);
Udp.endPacket();
}
M5StackをEAO 鍵スイッチにつなげる

GPIO 2番とGNDにつなげます。

起動すると自分のTelloのWi-Fi につながります。

起動時はおそらくOFFの状態です。

キーを回すとこのような表示でTelloに着陸の動作を命令します。
実際に動かしてみる
ということで実際に強制的に割り込めるかやってみましょう!

まず別ルートでNode-REDで飛翔させてプログラム制御しておきます。左右に飛行しております。
EAO 鍵スイッチを動作させてみると、無事に着陸できました!
ふりかえる
ということで、トイドローン Tello をM5Stack+EAO 鍵スイッチで緊急着陸させることができました。
なぜ、これをやってみたかったかというと、まずTelloの操作が command 司令を出したあとにさらに割り込みができるのかを試したかったことがスタートです。
そして、EAO 鍵スイッチをIoT化してみて感じた一番の有用性というのは、実は「鍵を持った人だけ特別な動作ができる」ということなので、これをドローン上で簡易的だとしても試してみたかったというところも試したかったところもあります。
実際にやってみて狙い通りアナログの鍵ならではの、鍵を持った人のみが緊急着陸させるというセキュアな状況をつくれました。
これはいろいろと応用がききそうですね。
それでは、よき、 M5Stack & Tello & EAO Lifeを!