PCからシリアル通信したメッセージを中継するNefryBTからTelloを操作するメモ

PCからシリアル通信したメッセージを中継するNefryBTからTelloを操作するメモです。
やりたいこと
こちらの記事で、Node-REDとトイドローンTelloを連携するナレッジを書いたんですが、悩ましいところがあります。
というのも、TelloをWi-Fiで接続してUDPで操作する場合、命令をするIoT機器がWi-Fiで縛られてしまいます。さらに、そのIoT機器が外部操作を受け入れられない限り、ネットワークから孤立しまうところが悩ましいところなんです。
Raspberry Piは幸いにも、有線でのLANと無線LANでの両方のネットワークを受け入れられるので、その制約を超えることが出来ますが、もう少し他の方法も模索したいという話。
今回は、PCからシリアル通信したメッセージを中継するNefryBTを作り、Telloを操作するようにします。
NefryBTソースコード
NefryBTソースコードはこちらです。
#include <Nefry.h>
#include <NefryDisplay.h>
#include <WiFiUDP.h>
// Nefryメッセージ用Buffer変数
char NefryTextBuffer[50];
// TELLO設定
const char* TELLO_IP = "192.168.10.1";
const int PORT = 8889;
// 離陸着flag
int takeoff_flag = 1;
WiFiUDP Udp;
char packetBuffer[255];
String message = "";
void setup() {
Serial.begin(115200);
// ボタンの有効化
Nefry.enableSW();
// UDP
Udp.begin(PORT);
Serial.println("start");
}
void loop() {
if (Serial.available() > 0){
// 改行で区切る
String str = Serial.readStringUntil('\n');
// Stringから char*の変換
char* sendstr = strdup(str.c_str());
telloMessage(sendstr);
} else {
if (Nefry.readSW()) {
if(takeoff_flag == 1){
// チェック用、1度ボタンを押すと離陸
telloMessage("command");
telloMessage("takeoff");
takeoff_flag = 0;
} else {
// チェック用、もう一度ボタンを押すと着陸
telloMessage("command");
telloMessage("land");
takeoff_flag = 1;
}
Nefry.ndelay(1000);
}
}
}
// Telloからのレスポンスを確認する関数
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;
}
// UDPでTelloに命令を送る関数
void sendMessage(char* ReplyBuffer) {
Udp.beginPacket(TELLO_IP, PORT);
Udp.printf(ReplyBuffer);
Udp.endPacket();
}
// Telloにデータを送受信する関数
void telloMessage( char* command ) {
sendMessage(command);
message = listenMessage();
char* messtr = strdup(message.c_str());
displayMessage(command,messtr);
}
// 表示
void displayMessage( char* command , char* message ) {
sprintf(NefryTextBuffer,"command: %s",command);
NefryDisplay.print(NefryTextBuffer);
Serial.println(NefryTextBuffer);
sprintf(NefryTextBuffer,"message: %s",message);
NefryDisplay.print(NefryTextBuffer);
Serial.println(NefryTextBuffer);
}
[/html]</div>
こちらをNefryBTに書き込みます。
### 苦労した点:シリアルで文字列受信させること
いままで、Serial.readで1文字ずつ読んでいたのですが、かなり大変だったところを、以下の記事で救われました。
<a href="http://ch.nicovideo.jp/yugata/blomaga/ar1177727" target="_blank">【prog】Arduino・シリアルで文字列受信するには:ゆうがたの「特にコレと言って」 - ブロマガ</a>
> 引っ張るのも嫌なので、先に結論を書きます。
Serial.read()でもSerial.readString()でもなく、
Serial.readStringUntil(char)を使え!
とのことで、readStringUntilで取得しやすく!
### 苦労した点:Stringから char*の変換
しかし、readStringUntilを返すのがStringでして、Stringから char*の変換に手間取りました。
<a href="https://stackoverflow.com/questions/25549562/how-to-convert-const-char-to-char-in-c" target="_blank">pointers - How to convert const char* to char* in C? - Stack Overflow</a>
<div>[html]
// Stringから char*の変換
char* sendstr = strdup(str.c_str());
sendMessage(sendstr);
message = listenMessage();
なんとか、こちらのナレッジを参考に突破。
その他参考文献
今回の開発にあたっては文字列周りで以下の記事も参考になりました。ありがとうございました。
- 【prog】Arduino・シリアルで文字列受信するには:ゆうがたの「特にコレと言って」 - ブロマガ
- string型の話
- string型をcharに変換/コピーする
- c_strの使い方
- strdupの使い方
動かしてみる
早速、ノートPCにNefryを差し込み操作してみます。
このように差し込まれたCOMポートに命令を送ります。UDPで送られる文字がシリアル通信で送れるという仕組み。
通信はこのような設定にしています。文字列の区切りは \n にしていてボーレートはNefryに合わせて115200にしてます。
離陸させたときにはこのようなメッセージ。
着陸させたときにはこのようなメッセージ。
今回は up 50 、down 50 を繰り返してみます。
https://www.youtube.com/watch?v=ykyCgQxPbZ0
無事動きました!
まとめ
ということで、PCからシリアル通信したメッセージを中継するNefryBTからTelloを操作することができました。
これができると、USBシリアルの数さえ許せばNefryBTの数だけTelloが動かすことが可能になり、操作する機材のWi-FiはTelloに縛られずに、外部ネットワークからの操作を受け付けることが出来ます。
近日、複数台のTelloでも試してみようと思います。
それでは、よき Tello & NefryBT Lifeを!