動機
- Obniz Cloudからtelloを動かせた。
- ということはenebularからnode-redでtelloを制御できるのでは?と考えた。
用意するのもの
物品(サービス) | 説明 | 備考 |
---|---|---|
tello | UDP経由で制御することもできる小型ドローン | https://store.dji.com/jp/product/tello?vid=38421 |
enebular cloud | 無料でクラウドからnode-redを触れる環境 | https://www.enebular.com/ja/ |
Obniz Board 1Y | Obniz Cloudを介してIoTできるESP32ボード | https://obniz.com/ja/ |
M5Atom lite | M5Stack社が出している小型の筐体付きESP32ボード | https://shop.m5stack.com/products/atom-lite-esp32-development-kit |
ジャンパー x4本 | オス-オスのジャンパ | 秋月とかで入手 |
あと、モバイルバッテリーなどObniz Boardに給電できるものがあればOK
構成
事前にM5Atom liteに対してtello-UART-porterを書き込んでおく。その後、
Obniz Board 1YとM5Atom liteをUART通信するために結線すればハードウェアの準備は完了。
tello-UART-Porterについて
要はUARTから送られたコマンドを解釈してtelloへ制御指定を送ってくれるやつです。
インストール方法などはREADMEを参照する。
enebular側の構成について。
マイコンのネット接続はObniz OSならびにObniz Cloudにおまかせする。
また、ネット上の処理はenebular Cloud上で済ます。
enebularってなに?っていう方はこちら。
Node−RED上からObnizを使う際にはこちらを使う。enebularのメニューから「パレットの管理」に入り、ノードの追加で下記ノードを追加する。執筆当時のバージョンは0.6.2。
フローについて
Obniz nodeにてUARTを使用する。また、UARTからtello-UART-Porterで使えるコマンドを流せば基本的に操作できる。
injectノードから文字列を投げて、changeノードでは改行コードをいれているだけ。それをobnizからUART経由でtello-UART-porterに流して終わり。
obnizのコードはこちら。
obniz.uart0.start({ tx: 11, rx: 10, baud: 115200 });
obniz.uart0.onreceive = function (data, text) {
obniz.display.clear();
obniz.display.print(text);
msg.payload = data;
// 非同期だからreturnで出力できないよ!
node.send(msg);
}
flow.jsonはこちら
[
{
"id": "11f4d8766d32a0bc",
"type": "change",
"z": "26a1f1b0b488b867",
"name": "CRLFをつけるところ",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "$join([msg.payload,\"\\r\\n\"],\"\" )\t",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 380,
"y": 140,
"wires": [
[
"8308cb75c0993286"
]
]
},
{
"id": "709c86aac72e0336",
"type": "inject",
"z": "26a1f1b0b488b867",
"name": "takeoff",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "takeoff",
"payloadType": "str",
"x": 110,
"y": 40,
"wires": [
[
"11f4d8766d32a0bc"
]
]
},
{
"id": "d0a49b9015af0cc2",
"type": "debug",
"z": "26a1f1b0b488b867",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 810,
"y": 140,
"wires": []
},
{
"id": "b9c2ef92620a21a0",
"type": "inject",
"z": "26a1f1b0b488b867",
"name": "land",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "land",
"payloadType": "str",
"x": 110,
"y": 100,
"wires": [
[
"11f4d8766d32a0bc"
]
]
},
{
"id": "b14dbd55baeb8013",
"type": "inject",
"z": "26a1f1b0b488b867",
"name": "rotateclockwise 300",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "rotateclockwise 300",
"payloadType": "str",
"x": 150,
"y": 180,
"wires": [
[
"11f4d8766d32a0bc"
]
]
},
{
"id": "0c55611bde4e9d7c",
"type": "debug",
"z": "26a1f1b0b488b867",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 610,
"y": 300,
"wires": []
},
{
"id": "be7bbf59799caa20",
"type": "inject",
"z": "26a1f1b0b488b867",
"name": "init",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 90,
"y": 300,
"wires": [
[
"7f4fce927cd14e7f"
]
]
},
{
"id": "7f4fce927cd14e7f",
"type": "obniz-function",
"z": "26a1f1b0b488b867",
"obniz": "e95927ee07d37b17",
"name": "",
"code": "obniz.uart0.start({ tx: 11, rx: 10, baud: 115200 });\n\nobniz.uart0.onreceive = function (data, text) {\n obniz.display.clear();\n obniz.display.print(text);\n msg.payload = data;\n\n // 非同期だからreturnで出力できないよ!\n node.send(msg);\n}\n",
"x": 360,
"y": 300,
"wires": [
[
"0c55611bde4e9d7c"
]
]
},
{
"id": "8308cb75c0993286",
"type": "obniz-function",
"z": "26a1f1b0b488b867",
"obniz": "e95927ee07d37b17",
"name": "",
"code": "obniz.uart0.send(msg.payload);\n",
"x": 600,
"y": 140,
"wires": [
[
"d0a49b9015af0cc2"
]
]
},
{
"id": "77fed006dc46d48b",
"type": "comment",
"z": "26a1f1b0b488b867",
"name": "実際にコマンドを送るところ",
"info": "",
"x": 340,
"y": 40,
"wires": []
},
{
"id": "5f0cca9ffd9047e5",
"type": "comment",
"z": "26a1f1b0b488b867",
"name": "UART初期化するところ",
"info": "",
"x": 120,
"y": 240,
"wires": []
},
{
"id": "e95927ee07d37b17",
"type": "obniz",
"obnizId": "xxxx-xxxx",
"deviceType": "obnizboard1y",
"name": "",
"accessToken": "",
"code": ""
}
]
ね、簡単でしょ?...と言いたいところだけど、実を言うと改行コードで丸一日ハマっていました。tello-UART-porterで使っているSerialCommandでは改行コードがCRLF(Windowsとかでよくあるやつ)になっていて、enebularで"\n"を送ってもLFしかできないので動作しないのです。なので、文字列の末尾にはCRを表す"\r"も合わせて付与しています。
とはいえ、命令が抽象化されているって便利。
動かしてみた
おわりに
- クラウド環境からドローン動くのいいよね。
- 一応別のストリームで動画も取得できるっぽい。データ量とかを考えるとラズパイあたりを使って制御したほうがいいんかなぁ。
- 改行コードには気をつけよう!