LoginSignup
1

posted at

updated at

enebular cloudからtello(EDUじゃない)を動かしてみる

動機

  • 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通信するために結線すればハードウェアの準備は完了。

UARTでObniz BoardとM5Atomを結線

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 function
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はこちら
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"も合わせて付与しています。

CRLF

とはいえ、命令が抽象化されているって便利。

動かしてみた

おわりに

  • クラウド環境からドローン動くのいいよね。
  • 一応別のストリームで動画も取得できるっぽい。データ量とかを考えるとラズパイあたりを使って制御したほうがいいんかなぁ。
  • 改行コードには気をつけよう!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1