目的
Node.js (JavaScript) でドローン(Parrot のミニドローン)を飛ばします。
既に Mac による例と Raspberry Pi による例を拝見していたので、Windows でもやってみました。Windows では他の環境に比べて少しトリッキーでしたので、自分のメモの意味も含め、まとめておきます。
環境・機材
ハードウェア
- Windows の パソコン(Lenovo ThinkPad E440; Windows 10 Home, Ver.1703)
-
Parrot MAMBO(Amazon で
14,453 円で入手) -
iBUFFALO Bluetooth アダプタ BSBT4D09BK(Amazon で 936 円で入手)
- 上記 PC 内蔵の BT では動作確認できませんでした
- このアダプタ(BSBT4D09BK)は「CSR8510 A10」というチップが使われており、下記 node-rolling-spider が依存している node-bluetooth-hci-socket モジュールに適合しています
ソフトウェア
環境構築
Node.js のインストール
- 通常どおりインストーラでインストール
- 私は C:\nodejs にインストールしました
windows-build-tools のインストール
-
各種の Node モジュールを Windows ネイティブでコンパイルするための環境一式で、以下を一括でインストール・各種設定できます(こちらをご参考)。なお、既に VisualStudio 、C++ Build Tools、Python がインストールされている環境でも「conflict-free」だそうです。
- Visual C++ Build Tools 2015
- Python 2.7.11
- C:\Users\(ユーザ名)\.windows-build-tools\python27 にインストールされる
-
コマンドプロンプト(cmd.exe)を「管理者として実行」して、以下のコマンドを実行
npm install --global windows-build-tools
- インストールが終わるまで気長に待ちます
node-rolling-spider のインストール
- Parrot のミニドローンと Bluetooth でやりとりできるモジュールです
- これからアプリケーションを作るフォルダを適当に作成
- 例 C:\Users\(ユーザ名)\drone
- コマンドプロンプトでそのフォルダに移動
- 以下のコマンドを実行
npm install rolling-spider
- 黄色い文字で「WARN」がいくつか出てくると思いますが、たいてい大丈夫です
- 赤い文字で「ERROR」の場合はネイティブコンパイル等に失敗しているので、windows-build-tools をインストールし直したり、エラーメッセージをもとに試行錯誤してください
Bluetooth アダプタの設定
- Bluetooth アダプタをパソコンの USB ポートにさします
- Windows 10 の場合、普通に使う場合はドライバ不要(自動インストール)だそうです(させば、デバイスマネージャーで Bluetooth デバイスとして認識されます)が…
- 上記 node-rolling-spider が依存している node-bluetooth-hci-socket というモジュールを通じて使う場合は、「WinUSB」というドライバに書き換える必要があります(こちらに記載)。
- Zadig というドライバ書き換えツールをこちらからダウンロードします
- zadig-2.3.exe をダブルクリックで実行します
- Options メニュー -> List All Devices を選択するとデバイスの一覧が出ます
- デバイスの一覧から Bluetooth アダプタ(今回の場合は「CSR8510 A10」)を選ぶと、左側に現在のドライバが出ます(私の場合は以前に東芝のスタックを入れていたので tosrfusb と表示されています)
- これを「WinUSB」に書き換えるため、「Replace Driver」をクリックします
- 「The driver was installed successfully.」と出れば成功です。
- するとこれまで「デバイスマネージャー」で「Bluetooth」として認識されていたアダプタが、「ユニバーサル シリアル バス デバイス」として認識されるようになります。こうなれば OK です。
※ Bluetooth アダプタのドライバを元に戻す方法は後述します
ようやく飛ばします
既に標準のスマホ/タブレットアプリを使って当該ドローンの操作はひととおり理解していることを前提とします。
以下のコードは rolling-spider モジュール内の eg フォルダにある「keyboard.js」をベースにして、モジュールのサイトを参考に書き換えつつ、コメントを加えています。間違いがあればコメントいただけましたら幸いです。
コーディング
以下のコードをテキストエディタで入力し、さきほど rolling-spider をインストールしたフォルダ(例 C:\(ユーザ名)\drone)内に「app.js」として保存します。
'use strict'; // 厳格モードにする
// モジュールの読み込み
const Drone = require('rolling-spider'); // rolling-spider モジュールを使う
const keypress = require('keypress'); // キーボード操作を取得する keypress モジュールを使う(rolling-spider と同時にインストールされる)
// 変数の設定
let ACTIVE = true; // ドローンがアクティブ状態か否か
const STEPS = 2; // 一度のキー操作で命令を出す回数(動かすステップ数、0-100)
// rolling-spider のインスタンスを作る
const d = new Drone();
// ドローンの初期設定
d.connect( () => { // BLE でドローンに接続し、接続できたらコールバック
d.setup( () => { // ドローンを初期設定してサービスや特徴を取得、その後コールバック
d.flatTrim(); // トリムをリセット
d.startPing(); // 不明
d.flatTrim(); // なぜ二回呼ぶのかは不明
ACTIVE = true; // ドローンを ACTIVE 状態とする
console.log(d.name, 'is ready!'); // 準備OKなことをコンソール出力
});
});
// キー操作でイベントを発生させる
keypress(process.stdin); // 標準入力に keypress イベントを発生させる
process.stdin.setRawMode(true); // raw mode(修飾を伴わない)で標準入力を受け付ける
process.stdin.resume(); // keypress イベントをリッスン
// キー操作後に少しのあいだ入力を受け付けないようにする関数
function cooldown() {
ACTIVE = false; // いったん ACTIVE 状態でなくしておいて
setTimeout( () => { // 一定時間後に
ACTIVE = true; // ACTIVE に戻す
}, STEPS * 12); // この例では 24 ms
}
// キーボードからの入力による操作
process.stdin.on('keypress', (ch, key) => { // keypress イベントが発生したら
if (ACTIVE && key) { // ドローンが ACTIVE で key があれば
// 緊急停止
if (key.name === 'm') { // m キー
d.emergency(); // 緊急停止(モーターを即時停止)
setTimeout( () => { // 3秒後にプログラム終了
process.exit();
}, 3000);
// 離陸(t; take-off)
} else if (key.name === 't') { // t キー
console.log('takeoff'); // コンソール出力
d.takeOff(); // 離陸
// w/s/a/d キー(前後左右の移動)
} else if (key.name === 'w') { // w キー
d.forward({ steps: STEPS }); // 前進(前ピッチ)
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 's') { // s キー
d.backward({ steps: STEPS }); // 後退(後ピッチ)
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'a') { // a キー
d.tiltLeft({ steps: STEPS }); // 左水平移動(左ロール)
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'd') { // d キー
d.tiltRight({ steps: STEPS }); // 右水平移動(右ロール)
cooldown(); // 少しの間キー操作を受け付けない
// カーソルキー(上下と左右スピン)
} else if (key.name === 'left') { // 左カーソルキー
d.turnLeft({ steps: STEPS }); // 左旋回(左スピン(ヨー))
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'right') { // 右カーソルキー
d.turnRight({ steps: STEPS }); // 右旋回(右スピン(ヨー))
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'up') { // 上カーソルキー
d.up({ steps: STEPS * 2.5 }); // 上昇
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'down') { // 下カーソルキー
d.down({ steps: STEPS * 2.5 }); // 下降
cooldown(); // 少しの間キー操作を受け付けない
// i/j/k/l キー(アクロバット)
} else if (key.name === 'i') { // i キー
d.frontFlip({ steps: STEPS }); // 前に宙返り
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'k') { // k キー
d.backFlip({ steps: STEPS }); // 後ろに宙返り
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'j') { // j キー
d.leftFlip({ steps: STEPS }); // 左に宙返り
cooldown(); // 少しの間キー操作を受け付けない
} else if (key.name === 'l') { // l キー
d.rightFlip({ steps: STEPS }); // 右に宙返り
cooldown(); // 少しの間キー操作を受け付けない
// 着陸(q; quit)
} else if (key.name === 'q') { // q キー
console.log('landing...'); // コンソール出力
d.land(); // 着陸
}
}
// プログラム終了(ctrl + c)
if (key && key.ctrl && key.name === 'c') { // ctrl + c なら
process.stdin.pause(); // 標準入力を一時停止
process.exit(); // プログラム終了
}
});
動作確認
- ミニドローンにバッテリーを装着し、電源を ON にします
- Parrot MAMBO の目が緑色に点滅します(ペアリングモード?)
- コマンドプロンプトで、上記の app.js があるディレクトリ(例 C:\(ユーザ名)\drone)に移動し、以下を実行します
node app.js
コンソールに以下のように表示され、MAMBO の目が緑色の「点灯」になったら準備OKです(xxxxxxは個体の番号)。
Mambo_xxxxxx is ready!
操縦方法(キーアサイン)
キー | 動作 | メソッド |
---|---|---|
m | 緊急停止(即座にプロペラ停止) | emergency() |
t | 離陸 | takeOff() |
w | 前進(前ピッチ) | forward() |
s | 後退(後ピッチ) | backward() |
a | 左水平移動(左ロール) | tiltLeft() |
d | 右水平移動(右ロール) | tiltRight() |
↑ カーソル | 上昇 | up() |
↓ カーソル | 下降 | down() |
← カーソル | 左旋回(左スピン(ヨー)) | turnLeft() |
→ カーソル | 右旋回(右スピン(ヨー)) | turnRight() |
i | 前方宙返り | frontFlip() |
k | 後方宙返り | backFlip() |
j | 左に宙返り | leftFlip() |
l | 右に宙返り | rightFlip() |
q | 着陸 | land() |
ctrl + c | プログラム終了 | - |
まとめ
node-rolling-spider モジュールを使って Windows でミニドローンを飛ばすポイントは以下です。
- windows-build-tools でモジュールをネイティブ・コンパイルできる環境を整えておく
- node-bluetooth-hci-socket モジュールに対応した Bluetooth アダプタを使う
- Bluetooth アダプタのドライバを WinUSB に書き換える(Zadig というツールを使う)
これらのうち1点目は今回の内容に限ったことではありませんが、これまで手動では設定しており、他のモジュールはうまくビルドされていたのに、今回つまずきました。windows-build-tools を再インストールしたらうまくいきました。手動設定で、なにか足りていなかったようです。
2点目と3点目については、node-rolling-spider の依存モジュールの readme までちゃんと読まずに試していて、つまずきました。また、一般的な Bluetooth アダプタのように「スタック」を使わずに(スタックをバイパスして)通信するというのが当初は理解できず、手間取りました。
このあたり、事前に Raspberry Pi で試した時は何も考えなくてもすんなり動いて、Windows でぜんっぜん動かなくて、心が折れかけでした。業務の都合上(?)、Windows マシンだけで済むと楽なので、少し手間取りはしましたが、動いてよかったです。
付録
Bluetooth アダプタのドライバの戻し方
- デバイスマネージャーで WinUSB ドライバで書き換えていた Bluetooth アダプタを右クリックし、「ドライバーの更新」を選択
- 「コンピューターを参照してドライバーソフトウェアを検索」を選択
- 「コンピューター上の利用可能なドライバーの一覧から選択します」を選択
- 「Generic Bluetooth Radio」(当初に認識されていたデバイス名)を選択し、「次へ」でドライバをインストール
- デバイスマネージャーで当該のアダプタが「Bluetooth」として認識されていれば OK です
- 念のため zadig-2.3.exe を実行し、「List All Device」して、当該アダプタを選択して、もとのドライバになっていることを確認します