Node.jsで無線制御するロボットカー:リアルタイムIoTプロジェクト
部品と材料
| Arduino UNO | ×1 | |
| SparkFun デュアルHブリッジ モータードライバ L298 | ×1 | |
| HC-05 Bluetoothモジュール | ×1 | |
| ジャンパーワイヤー(汎用) | ×1 | |
| 9V電池 | ×2 | |
| DCモーター 12V | ×2 |
このプロジェクトについて
プロジェクトのアイデア
Node.jsはリアルタイムアプリケーションに最適な選択肢の一つです。以前Socketを使ったリアルタイムアプリで経験があり、同じ概念でNode.jsサーバーを用いたIoTプロジェクトを自習目的で作成しました。
このローバーはBluetoothでNode.jsサーバーと通信し、フロントエンドではSocketを使ってサーバーにコマンドを送信します。
プロジェクトの目的
Nodeサーバーとハードウェア(ローバー)間の無線通信を学習・実装し、Nodeサーバーが提供するモバイルWebページからSocket経由でローバーをリモート制御すること。
前提知識
Node、Socketプログラミング、L298モータードライバの基本知識が必要です。
必要なもの
- Arduino Uno ×1
- L298 モータードライバ ×1
- HC-05 Bluetoothモジュール ×1
- ジャンパーワイヤー
- 9V電池 ×2
- ギアードモーター(6-9V) ×2
- 互換ホイール ×2
- シャーシ
- Node.jsインストール済みのコンピューター(サーバー用)
ステップ1:ローバーの組み立て

組み立ては複雑ではありません。「2輪シャーシキット」をオンラインで購入すれば、組み立てに必要な部品がすべて揃っています。
Arduino UnoとL298モータードライバをローバーの上面に搭載し、それぞれ別の9V電池で駆動します。Arduino UnoがHC-05 Bluetoothモジュールに電源を供給し、サーバーと通信します。
回路図

上図の通り、L298モータードライバは9V電池で駆動し、2つのモーター制御出力をモーターAとBに接続。モーターに極性はないためどちらの端子に繋いでも構いませんが、両モーターが同じ方向に回転するようにしてください。5Vレギュレータージャンパーは外さないでください。
注意: L298に12V以上を供給すると、オンボードの5Vレギュレーターが破損します。
Arduino Unoも9V電池で駆動(プラスをVinピン、マイナスを共通GND)。ArduinoがBluetoothモジュールに電源を供給するため、HC-05のVccをArduinoの5V、GNDをGNDに接続。
HC-05とArduinoのシリアル通信用に、HC-05のTXDをArduinoのRX、HC-05のRXDをArduinoのTXに接続。
L298制御用に、EN1とEN2をArduinoの任意のPWMピンに、Inputピン1〜4を任意のデジタルピンに接続。
データ伝送の流れ

1. ユーザーがNodeサーバーの提供するWebページにアクセス(URL例:192.XXX.XXX.129:8080)
2. Webページでボタンをクリックすると、Socket経由でサーバーに必要な関数実行を要求
3. HC-05とBluetooth接続しているNodeサーバーが、必要なデータをHC-05に送信
4. HC-05がシリアル通信でArduino UNOにデータを転送
5. Arduino UNOがL298モジュールを制御
ステップ2:サーバーのセットアップ
Node.jsをインストール(安定版ならどれでも。私はv11.15を使用)。以下のパッケージをインストール:
- node-gyp
- express
- node-bluetooth
- socket.io
- ejs
※ node-gyp のインストールは少し癖があり、最新版Nodeではサポートされていない場合があるため、Node v11.15の使用を推奨。
Webページでの操作イベントを受け取り、Socketでサーバーに通知、サーバーが対応する関数(Bluetoothへのデータ送信)を実行する仕組みです。
express と EJS でサーバーとWebページを作成し、望むコントロールを配置、Socket接続を設定します。ドキュメントを参照してください。
Bluetooth設定はこちらのドキュメントを参照。コントロールボタンがクリックされるたびにHC-05モジュールへメッセージが送られます。
私のシンプルなWebページ:

ステップ3:Arduinoコード
BluetoothとArduino Unoはシリアル通信でやり取りするため、「文字列」コマンドと、終了を示す追加文字を送信します。
例:前進コマンドは forwardT 。Arduino側では文字 T を検出したらシリアル通信完了とみなします。
受信した文字列コマンドに基づき、L298ドライバを制御して前進、後退、左折、右折、速度変更などを行います。
Arduinoコードは添付ファイルを参照。
ステップ4:最終結果
拡張と今後の展望
今後は音声コマンドでの制御、障害物回避機能を追加予定。また、走行距離、最高速度、平均速度などの統計をデータベースに記録したり、温度・光・湿度センサーを複数追加して定期的に記録・DB保存することも計画中。
次期バージョン
次のプロジェクト「モバイルで音声制御ローバー」をご覧ください。
コード
Node Rover Arduinoコード Arduino
const int en1 = 9;
const int en2 = 3;
const int inp1 = 2;
const int inp2 = 4;
const int inp3 = 7;
const int inp4 = 8;
char charRead;
String inputString = "";
void setup() {
Serial.begin(9600);
pinMode(en1, OUTPUT);
pinMode(en2, OUTPUT);
pinMode(inp1, OUTPUT);
pinMode(inp2, OUTPUT);
pinMode(inp3, OUTPUT);
pinMode(inp4, OUTPUT);
}
void loop() {
if (Serial.available()) {
charRead = Serial.read();
if (charRead != 'T') {
inputString += charRead;
} else {
if (inputString == "forward") {
digitalWrite(inp1, HIGH);
digitalWrite(inp2, LOW);
digitalWrite(inp3, HIGH);
digitalWrite(inp4, LOW);
} else if (inputString == "backward") {
digitalWrite(inp1, LOW);
digitalWrite(inp2, HIGH);
digitalWrite(inp3, LOW);
digitalWrite(inp4, HIGH);
} else if (inputString == "fleft") {
digitalWrite(inp1, HIGH);
digitalWrite(inp2, LOW);
digitalWrite(inp3, LOW);
digitalWrite(inp4, LOW);
} else if (inputString == "fright") {
digitalWrite(inp1, LOW);
digitalWrite(inp2, LOW);
digitalWrite(inp3, HIGH);
digitalWrite(inp4, LOW);
} else if (inputString == "bleft") {
digitalWrite(inp1, LOW);
digitalWrite(inp2, LOW);
digitalWrite(inp3, LOW);
digitalWrite(inp4, HIGH);
} else if (inputString == "bright") {
digitalWrite(inp1, LOW);
digitalWrite(inp2, HIGH);
digitalWrite(inp3, LOW);
digitalWrite(inp4, LOW);
} else if (inputString == "break") {
analogWrite(en1, 50);
analogWrite(en2, 50);
delay(550);
digitalWrite(inp1, LOW);
digitalWrite(inp2, LOW);
digitalWrite(inp3, LOW);
digitalWrite(inp4, LOW);
analogWrite(en1, 150);
analogWrite(en2, 150);
} else if (inputString == "maxspeed") {
analogWrite(en1, 250);
analogWrite(en2, 250);
} else if (inputString == "medspeed") {
analogWrite(en1, 180);
analogWrite(en2, 180);
} else if (inputString == "lowspeed") {
analogWrite(en1, 90);
analogWrite(en2, 90);
} else {
digitalWrite(inp1, LOW);
digitalWrite(inp2, LOW);
digitalWrite(inp3, LOW);
digitalWrite(inp4, LOW);
}
inputString = "";
}
}
}
回路図
製造プロセス
- Raspberry Pi 4でWeb経由リアルタイム温湿度モニタリング
- 温度制御ファンサーキット:メディア家具冷却用DIYリレーシステム
- 4ドルのソーラーライトをスマートワイヤレスセンサーノードに変身: MSP430 + nRF24L01+で庭園監視
- Raspberry Pi 4 を Web サーバーに変えて自分のサイトを構築する方法
- ラジコンカーをBluetooth操作ロボットに改造する方法
- 古いラジコンカーをXboxコントローラーで操作可能に - ArduinoとUSBホストシールドで実現
- Qi対応Wi-Fiラジコンカー:ワイヤレス充電機能付きRCカーキットの製作
- Arduinoベースのヌンチャク操作6自由度ロボットアームキット
- ワイヤレス赤外線センサー駆動ロボット車両の構築
- リソース制約マイクロコントローラー向け効率的Webサーバーソリューション
- 3ドルのESP8266でTLS対応Webサーバーを30分以内に導入