M1 Rover:荒れた地形を走行する屋外自律ロボット
部品と材料
| 部品 | 数量 | 備考 |
|---|---|---|
| SparkFun デュアル Hブリッジ モータードライバー L298 | 1 | |
| DCモーター(汎用) | 4 | |
| Arduino UNO | 1 | |
| LED(汎用) | 8 | |
| 抵抗 221Ω | 8 | |
| サーボモーター(Tower Pro MG996R) | 1 | |
| 超音波センサー HC-SR04 | 1 |
使用アプリとオンラインサービス
- Arduino IDE
- Microsoft Visual Studio 2015
- Microsoft Windows 10 IoT Core
プロジェクト概要
これまでいくつかの屋内ロボットを製作してきた後、荒れた地形を走行できる屋外ロボットの製作を決意しました。これを「M1-Robot」と名付けました。
M1-Robotのモーター駆動部は、Arduinoで4つのDCモーターを簡単に制御できるため、より強力なロボットの中核として最適だと考え、ゼロからオフロード仕様の4輪駆動M1を設計しました。
これは単なるラジコンカーではありません。一連の命令に従って自律走行させたり、リモートコンピューターから制御したり、ゲームコントローラーやカスタムジョイスティックでラジコンカーのように操作したりすることも可能です。
ステップ1:設計
自分の製品や試作品を設計するのは楽しい作業ですが、実物大で製作しようとすると一気に複雑になります。そこで、強力かつ使いやすい設計ツールとしてGoogle SketchUp 2017を採用しました。これにより、モデルの図面をレーザーカッターや3Dプリンター用にエクスポートできます。
最初の3週間は、ロボットの船体(シャーシ)の設計と構築に費やしました。材料として3mm厚の木製ボードが支給されました。
時間の制約により、配線は船体内に全て押し込む形になり、あまり綺麗ではありません。
今後M2、M3とバージョンアップしていく予定なので、「M1Rover」と名付けました。キット形式で設計されており、ネジで組み立てるだけで完成します。
ステップ2:構成部品と特徴
- 最大3時間の稼働時間!
- Arduino Uno、Mega、Nanoに対応
- 動作電圧:5V〜9V DC
- 3mm厚の木製シャーシ
- 直径68mmホイール、L298N デュアルHブリッジ モーター/ステッパードライバー
- DCモーター駆動用9V電池
- Arduino駆動用9V電池
- LEDライト7個(フロント4、リア2)
- HC-06 Bluetoothモジュール
- Arduinoセンサーシールド v5.0
- 超音波トランスデューサー HC-SR04
ステップ3:モーターコントローラー
Hブリッジは通常、モーターの速度と方向制御に使用されますが、高出力LEDアレイの輝度制御など、他のプロジェクトにも応用可能です。
- Arduino、電源、モーターコントローラーのグランド(GND)を必ず共通に接続してください。
- PWMピンは、PWM機能を使用しない場合は接続不要です。
ステップ4:シャーシの組み立て
シャーシはレーザーカッターで複数のパーツに切り出されています。前述の通りキット形式で設計されているため、説明書に従って組み立てるだけです。
デザイン性も考慮し、ラジコンカーらしくフロントとリアにライトを配置しました。フロントには220Ω抵抗を直列にした白色LED4個、リアには同じく220Ω抵抗付き赤色LED2個を搭載。これらのLEDも同一アプリケーションから制御可能です。
ステップ5:回路
多数の電子部品を同時に制御するため、各部品の接続順序に注意が必要で、やや複雑な回路となりました。
主な接続構成:
- Arduinoセンサーシールド 5.0
- Arduino Uno R3 + L298N デュアルHブリッジ モーター/ステッパードライバー
- DCモーター駆動用9V電池
- LEDライト7個(リア2、フロント4)
- HC-06 Bluetoothモジュール
- 超音波トランスデューサー HC-SR04
- サーボモーター 9g
- アクティブブザー
- ホイール付きDCモーター4個
ステップ6:ソフトウェア
M1-Robotのコードを書くにあたり、さまざまな要素を考慮しました。GUIソフトウェアを使用すれば、ロボットの状態に関するより多くの情報を取得できます。
スターターキット用の基本コード。Bluetooth経由でモバイル端末やノートPCから制御可能:
int frontled = 3; // フロントLED
int rearled = 4; // リアLED
int outPin1 = 5; // モーター1
int outPin2 = 6; // モーター1
int outPin4 = 11; // モーター2
int outPin3 = 12; // モーター2
char bt = 0; // Bluetooth受信データ
int buzzerPin = 2;
const int pingPin = 9; // 超音波センサー Trigピン
const int echoPin = 8; // 超音波センサー Echoピン
void setup() {
Serial.begin(9600);
pinMode(outPin1, OUTPUT);
pinMode(outPin2, OUTPUT);
pinMode(outPin3, OUTPUT);
pinMode(outPin4, OUTPUT);
pinMode(frontled, OUTPUT);
pinMode(buzzerPin, OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
bt = Serial.read();
digitalWrite(frontled, HIGH);
long duration, inches, cm;
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(10);
digitalWrite(pingPin, LOW);
pinMode(echoPin, INPUT);
duration = pulseIn(echoPin, HIGH);
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
if (cm > 10) { // 障害物まで10cm以上なら動作
if (bt == 'F') { // 前進
digitalWrite(outPin1, HIGH); digitalWrite(outPin2, LOW);
digitalWrite(outPin3, HIGH); digitalWrite(outPin4, LOW);
} else if (bt == 'B') { // 後退
digitalWrite(outPin1, LOW); digitalWrite(outPin2, HIGH);
digitalWrite(outPin3, LOW); digitalWrite(outPin4, HIGH);
} else if (bt == 'S') { // 停止
digitalWrite(outPin1, LOW); digitalWrite(outPin2, LOW);
digitalWrite(outPin3, LOW); digitalWrite(outPin4, LOW);
} else if (bt == 'R') { // 右旋回
digitalWrite(outPin1, HIGH); digitalWrite(outPin2, LOW);
digitalWrite(outPin3, LOW); digitalWrite(outPin4, LOW);
} else if (bt == 'L') { // 左旋回
digitalWrite(outPin1, LOW); digitalWrite(outPin2, LOW);
digitalWrite(outPin3, HIGH); digitalWrite(outPin4, LOW);
} else if (bt == 'I') { // 右前
digitalWrite(outPin1, HIGH); digitalWrite(outPin2, LOW);
digitalWrite(outPin3, LOW); digitalWrite(outPin4, HIGH);
} else if (bt == 'G') { // 左前
digitalWrite(outPin1, LOW); digitalWrite(outPin2, HIGH);
digitalWrite(outPin3, HIGH); digitalWrite(outPin4, LOW);
}
} else { // 障害物検知時:ブザーで警告
digitalWrite(buzzerPin, HIGH); delay(500);
digitalWrite(buzzerPin, LOW); delay(500);
}
}
}
long microsecondsToInches(long microseconds) { return microseconds / 74 / 2; }
long microsecondsToCentimeters(long microseconds) { return microseconds / 29 / 2; }
このArduinoコードは、全ての電子部品がシリアルポート経由のコマンドで動作するため、Bluetoothモジュール、PC、スマートフォンなど、あらゆる種類のコントローラーと互換性があります。
- C# Windowsアプリケーション(スクリーンショット添付)
ステップ7:パッケージ構成
スターターパッケージ
基本コンポーネントを含み、トッププレートに任意のセンシング、マニピュレーション、コンピュータハードウェアを簡単に搭載可能。オンボードのRover電源にセンサーを接続するだけで開始できます。
エクスプローラーパッケージ
基本的な屋内・屋外自律機能を実現。IPカメラの代わりに、IPアドレス経由でインターネット接続したスマートフォンのカメラを使用。
マッピングパッケージ
屋外走行時の基本的なGPSトラッキングを実現。リアルタイムで座標パスを確認できるのは非常に面白い機能です。
マニピュレーションパッケージ
ロボットアームと2フィンガー50mmグリッパーによる世界とのインタラクション。
重要なヒント:
全てのサーボが180度フル回転するわけではありません。多くは機械的な可動範囲が狭いです。テストコードを書いて機械的な限界を確認してください。servo.writeではなくservo.writeMicrosecondsを使うことを推奨します。1000〜2000を基本範囲として扱え、多くのサーボは600〜2400まで対応しています。
様々な値を試し、ブザー音(リミット到達音)が鳴るポイントを見つけてください。その範囲内でのみ制御するようにコードを書きます。servo.attach(pin, min, max)で制限を設定することも可能です。
補足:servo.attachでmin/maxマイクロ秒を設定すれば、そのままservo.write(0-180度をマイクロ秒にマッピング)が使えます。
エンドストップで保持し続けると大電流が流れ、急速に発熱してサーボを「焼き切る」原因になります。真の可動範囲を見つけ、コード側でエンドストップを超えないよう制限してください。Arduinoのconstrain()関数が便利です:
servo.write(constrain(angle, 10, 160)); // 角度を10〜160度に制限
カスタムパーツとエンクロージャ
m1rover_dxf_hackaday_4o7WTGHUGE.dxf
回路図

製造プロセス
- Raspoulette:太陽光発電自律コープドアシステムのプロトタイプ
- Windows IoT Core搭載RoverをRaspberry Pi 2で構築 - 初心者から上級者まで
- シンプルPiロボット - Raspberry Piで2WD自律ローバーを構築
- Arduino UNOとMAX7219で作るUFOアタックゲーム – レトロなドットマトリクスシューティング
- 3D RGB アルドゥクロック:Bluetooth対応LED時計(RTC内蔵)
- Arduino用バイポーラステッピングモーターライブラリ – 産業グレードの制御機能
- 川の健康を見守る:Arduinoベース水質監視システム「MyRiver」
- DIYギター高速ピック&ストンプペダル - 3Dプリントモーター駆動ピックの自作
- リニアモーター理解:電気エネルギーから精密直線運動へ
- サーボモーターの仕組みと重要性
- 可変リラクタンスモーター:種類、動作原理、応用