Arduinoでロボットカーを作る方法:Bluetooth操作をステップごとに
Arduinoのロボットカーをステップごとに作ります。部品と費用、L298NとHC-05の配線、18650電池、走行コード、スマートフォンでの操作、まっすぐ走らない・リセットするときの対処法を解説します。
Arduinoで車を作ることは、電子工作とプログラミングを1つのプロジェクトで学べる、とても楽しい方法の1つです。ギア付きのDCモーター2個、L298Nモータードライバ、18650電池2本、HC-05 Bluetoothモジュール、Arduino Unoがあれば、スマートフォンで操作するロボットカーを週末だけで作れます。その過程で、モーターをArduinoに直接つなげない理由、電池選びがとても大切な理由、数行のコードで本物の車が動くしくみを自分の目で確かめられます。
このガイドでは、2WD(モーター2個)のロボットカーを最初から最後まで一緒に作ります。部品リストと費用の内訳、シャーシの組み立て、配線表、前進・後退・旋回のコード、スマートフォンからのBluetooth操作です。初心者が最も苦労する2つの問題、車がまっすぐ走らないこととモーターが動き出すとArduinoがリセットすることには、それぞれ専用の章を設け、実測にもとづく実践的な対処法を紹介します。最後の章では、同じ車をESP32やRaspberry Pi Picoで動かす方法と、障害物を避けるロボットやライントレースロボットに発展させる方法を紹介します。




Arduinoのロボットカーのしくみ
ロボットカーは4つの部分に分けられます。Arduinoは頭脳で、スマートフォンからの命令を読み、どのモーターをどの向きにどの速さで回すかを決めます。L298Nモータードライバは筋肉で、Arduinoの弱い5 Vの信号を、モーターに必要な大きな電流に変えます。ギア付きモーターが車輪を回し、電池パックがすべてに電源を供給します。この車にはハンドルがなく、2つの車輪を違う速さや違う向きに回して曲がります。これを差動駆動と呼びます。左の車輪を前に、右の車輪を後ろに回すと、車はその場で右に回転します。前か後ろにある自由に向きが変わる小さなキャスターが、車体のバランスを保ちます。

| 項目 | 黄色のTTモーター(1:48) |
|---|---|
| 動作電圧 | 3〜6 V |
| ギア比 | 1:48(プラスチックのギア) |
| 無負荷回転数 | 3 Vで約90〜120 RPM、6 Vで200〜250 RPM |
| 無負荷電流 | 約150〜160 mA |
| 停動電流(ストール電流) | 約1.1〜1.5 A |
| 車輪の直径(キット) | 65 mm |
| 6 Vでの車の速さ | 約0.7 m/s(π × 0.065 m × 200 / 60) |
表で最も大切なのは停動電流の行です。車輪が障害物を押したときや車が走り出すとき、各モーターは一瞬1アンペア以上を流します。Arduinoのピンが出せるのは最大20〜40 mAなので、モーターは必ずドライバを通してつなぎます。この仕事をする間、L298Nは約1.5〜2.5 Vを失います。7.4 Vの電池パックならモーターには5〜6 Vが残り、これはTTモーターにちょうど理想的な範囲です。ドライバの内部とHブリッジの考え方は、L298NでDCモーターを制御するで詳しく解説しています。
部品リスト
| 部品 | 数量 | メモ |
|---|---|---|
| 2WDのアクリル製ロボットカーシャーシキット | 1 | ふつうTTモーター2個、車輪2個、キャスター、スイッチ、モーターの取り付け金具、ねじが入っている |
| Arduino Uno R3(互換品で可)+USBケーブル | 1 | Nanoでも可。ピン番号は同じ |
| L298Nモータードライバモジュール | 1 | 1チャンネルあたり2 A。2つのモーターを別々に駆動 |
| HC-05またはHC-06 Bluetoothモジュール | 1 | Androidのスマートフォンとの通信用 |
| 18650リチウムイオン電池 | 2 | 5 A以上を出せるメーカー品 |
| 18650用2本電池ボックス(直列) | 1 | 2本を直列にして7.4 Vにする |
| 18650用充電器 | 1 | 1本ずつ別々に充電できる充電器 |
| ジャンパーワイヤー(オス-メス、メス-メス) | 20+ | Arduino、L298N、HC-05の間 |
| 1 kΩと2 kΩの抵抗 | 1 + 1 | HC-05のRXD入力用の分圧回路 |
| 100 nFのセラミックコンデンサ | 2〜4 | ノイズを抑えるためモーターの端子の間に |
| 470〜1000 µFの電解コンデンサ(16 V以上) | 1 | 推奨。L298Nの電源入力に |
| 結束バンド、両面テープ、M3のスペーサー | 数個 | 基板と配線の固定用 |
ほとんどのシャーシキットには単3電池4本用の電池ボックスも入っていますが、このあと説明するように、L298Nと組み合わせるには弱すぎるので、リストに18650電池を入れました。HC-06はスレーブとしてしか動かないHC-05のシンプルな兄弟分で、スマートフォンから車を操作するにはまったく問題ありません。キットに入っているスリット付きのプラスチックの円盤は、あとで車を完全にまっすぐ走らせるために使う速度センサー用のエンコーダー円盤です。捨てずに、今はとっておきましょう。
費用:予算はどこにかかる?
価格は販売店や為替によっていつも変わるので、金額は書きません。その代わり、どの品目が予算を占め、どこで節約できるかを紹介します。一般的なルールとして、電子モジュール(L298N、HC-05、抵抗)は安く、予算のほとんどはボード、シャーシキット、そして何より電池と充電器にかかります。電池は最後まで節約すべきでない部分です。よい18650電池は何百回も充電でき、これから作るどのロボットのプロジェクトでも使い回せます。
| 品目 | 価格の目安 | 節約のコツ |
|---|---|---|
| シャーシキット(モーターと車輪を含む) | 中 | モーター、車輪、キャスターを別々に買うより、キットのほうがたいてい安い |
| Arduino Uno | 中(互換品)〜高(純正品) | 学ぶには互換品で十分。手持ちのUnoやNanoを使い回してもよい |
| L298Nモータードライバ | 低 | 1つのモジュールで2つのモーターを駆動。4WDでも1つで足りる |
| HC-05 / HC-06 | 低〜中 | スマートフォンで操作するだけならHC-06で十分 |
| 18650電池2本+充電器 | 最大の品目 | 「9900 mAh」と書かれたとても安い電池はたいてい偽物。ここは節約しない |
| 線、抵抗、コンデンサ、ねじ | 低 | ほとんどはスターターキットに入っている |
2WDか4WDか?
| 項目 | 2WD(モーター2個+キャスター) | 4WD(モーター4個) |
|---|---|---|
| 旋回 | その場で鋭く簡単に回転する | 車輪を横に滑らせて曲がる(スキッドステア)。カーペットでは苦戦する |
| 消費電流 | 走行中に約0.3〜0.6 A | 約2倍 |
| 電池のもち | 長い | 短い |
| でこぼこの地面 | キャスターが段差に引っかかることがある | グリップがよい |
| 直進性 | キャスターの向きが変わると車がそれることがある | より安定 |
| L298Nへの接続 | 各モーターを専用のチャンネルに | 各側の2つのモーターを並列にして1チャンネルに |
| 向いている用途 | 最初の車、ライントレースロボット | 屋外、重い荷物 |
最初の車には2WDをおすすめします。安く、消費電流が少なく、その場で簡単に回転でき、ライントレースロボットなどの次のプロジェクトにも向いています。4WDの車を作る場合は、各側の2つのモーターを並列にして同じOUT端子につなぎ、両方が同じ向きに回ることを確かめましょう。このときL298Nの1チャンネルにはモーター2個分の電流が流れます。ふつうの走行では問題ありませんが、車輪が引っかかると1チャンネル2 Aの上限を超え、ドライバの過熱保護がモーターを止めることがあります。
電源:なぜ18650電池2本なのか?
ロボットカーの問題のほとんどは、電池の選び間違いから生まれます。正しい電源は2つの条件を同時に満たす必要があります。L298Nでの損失のあとでもモーターに十分な電圧を残せること、そして起動時にモーターが数アンペアを流しても電圧が崩れないことです。18650リチウムイオン電池2本の直列(2S)は、満充電で8.4 V、平均7.4 Vで、数アンペアを楽に出せます。Arduino UnoのVIN入力の推奨は7〜12 Vなので、同じパックでモーターとArduinoの両方に給電できます。2500 mAhの電池で、走行中に平均0.8 A(モーターと基板の合計)を流す2WDの車なら、理論上は約3時間走ります。パックを完全に使い切ることはないので、2〜2.5時間のほうが現実的な数字です。自分の値で計算するには電池寿命ツールを使いましょう。

| 電源 | 電圧 | 電流の供給能力 | ロボットカーには |
|---|---|---|---|
| 9 Vの角形電池(PP3) | 9 V | とても低い | 不向き。リセットの最も多い原因 |
| 単3アルカリ電池4本 | 6 V(負荷ですぐ下がる) | 中 | 弱い。L298Nを通るとモーターには約4 Vしか届かない |
| 単3ニッケル水素電池4本(充電式) | 4.8 V | 良い | L298Nでは電圧が足りない |
| 18650リチウムイオン電池2本(2S) | 7.4 V(満充電8.4 V) | 高い(数アンペア) | 最良の選択 |
| 18650リチウムイオン電池3本(3S) | 11.1 V(満充電12.6 V) | 高い | TTモーターには高すぎる。5Vジャンパーの上限12 Vを超える |
| USBのモバイルバッテリー | 5 V | 良い | Arduinoに別に給電する場合のみ |
残量を推測する代わりに、測ることもできます。電池のプラス(スイッチのあと)を、10 kΩの抵抗2本で作った分圧回路を通してA0につなぎます。8.4 VのパックはA0では4.2 Vになり、Arduinoが読める上限の5 Vを下回ります。分圧回路が流す電流は約0.4 mAだけなので、電池のもちには影響しません。
1// Pil + (anahtardan sonra) → 10 kΩ → A0 → 10 kΩ → GND / battery + (after the switch) → 10 kΩ → A0 → 10 kΩ → GND
2const float DIVIDER = 2.0; // iki eşit direnç gerilimi yarıya böler / two equal resistors halve the voltage
3
4void setup() {
5 Serial.begin(9600);
6}
7
8void loop() {
9 float v = analogRead(A0) * 5.0 / 1023.0 * DIVIDER;
10 Serial.print(F("Pil / Battery: "));
11 Serial.print(v, 2);
12 Serial.println(F(" V"));
13 if (v < 6.6) Serial.println(F("Sarj et / Charge now")); // hücre başına 3,3 V / 3.3 V per cell
14 delay(1000);
15}ステップごとの組み立て
- アクリル部品の保護紙をはがします。モーターに線が付いていなければ、各モーターに2本の線をはんだ付けし、はんだの部分をホットボンドで補強します。振動でモーターの線が取れるのが最も多い故障です。
- キットのT字型のアクリル金具と長いM3のねじで、モーターをシャーシの裏側に固定します。2つのモーターの軸がまっすぐ並び、モーターの線の端子が内側を向くようにします。
- エンコーダー円盤を使うつもりなら、今のうちにモーター軸の内側に取り付けます。車輪を付けたあとでは難しくなります。
- シャーシの反対側の中央に、スペーサーを使ってキャスターを取り付けます。シャーシが床と平行になる高さのスペーサーを選びます。
- D字型の軸に合わせて、車輪を奥まで押し込みます。車輪がゆるいと、車はずっとそれ続けます。
- 電池ボックスを両面テープかマジックテープで、重さが車輪の軸の近くにかかる位置に置きます。重さのほとんどがキャスターにかかると、駆動輪が空回りします。
- プラスチックのスペーサーで、ArduinoとL298Nを上段に取り付けます。ArduinoのUSBポートに楽に手が届き、L298Nのヒートシンクが外気に触れるようにします。金属のねじが基板の裏のはんだに触れないよう注意しましょう。
- 電池のプラスの線にスイッチを直列に入れ、電池を外さなくても車をオン・オフできるようにします。
- 各モーターの2本の線をより合わせてL298Nまで引き、すべての線を短くして結束バンドでまとめます。電池を入れる前に、テスターで電池の端子の間がショートしていないことを確かめましょう。
配線図
配線は2つの部分に分けて考えましょう。電源側(電池、スイッチ、L298N、モーター)と信号側(ArduinoからL298NとHC-05への細い線)です。L298NのENAとENBのピンにある小さなジャンパーを外します。速度をコードで設定するため、これらのピンをArduinoのPWM出力につなぎます。L298Nの5Vジャンパーはそのままにします。パックは12 V未満なので、ボード自体のレギュレーターがドライバのロジックに給電します。

| L298Nの端子 | 接続 |
|---|---|
| OUT1、OUT2 | 左のモーター(4WDでは左の2つのモーターを並列に) |
| OUT3、OUT4 | 右のモーター(4WDでは右の2つのモーターを並列に) |
| 12V | スイッチを通して電池のプラス |
| GND | 電池のマイナスとArduinoのGNDピン(共通GND) |
| 5V | Arduino Unoでは何もつながない。ESP32とPicoではボードに給電する |
| 5Vジャンパー | 付けたまま(電池は12 V未満) |
| ENAとENBのジャンパー | 外す。ピンはArduinoのPWM出力へ |
| 接続 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| L298NのENA(左のモーターの速度) | D5(PWM) | GPIO 25 | GP15 |
| L298NのIN1 | D7 | GPIO 27 | GP14 |
| L298NのIN2 | D8 | GPIO 33 | GP13 |
| L298NのENB(右のモーターの速度) | D6(PWM) | GPIO 26 | GP10 |
| L298NのIN3 | D9 | GPIO 32 | GP12 |
| L298NのIN4 | D4 | GPIO 4 | GP11 |
| HC-05のTXD | D10(SoftwareSerialのRX) | 不要(Bluetooth内蔵) | GP1(UART0 RX) |
| HC-05のRXD | D11、1 kΩ / 2 kΩの分圧回路を通して | 不要 | GP0(UART0 TX)、直接 |
| HC-05のVCC | 5V | 不要 | L298Nの5V出力 |
| ボードの電源 | VIN ← スイッチのあとの電池のプラス | 5V(VIN) ← L298Nの5V出力 | VSYS ← L298Nの5V出力 |
| GND | L298NのGNDと電池のマイナスと共通 | 共通 | 共通 |
速度用のピンにD5とD6を選んだのには理由があります。Unoでは、Servoライブラリが9番と10番のPWMを無効にし、tone()関数が3番と11番のPWMを無効にします。ENAとENBを5番と6番にしておけば、あとでサーボやブザーを追加してもモーターの速度制御は動き続けます。D2とD3は割り込みに対応しているので、エンコーダー用に空けてあります。ボードのピン配置はピン配置ツールで確認できます。
最初のスケッチ:前進、後退、左、右
Bluetoothに進む前に、モーターと配線だけをテストしましょう。コードの中心はdrive(left, right)関数です。各モーターの速度を-255〜255で別々に受け取り、プラスの値が前進、マイナスの値が後退、ゼロが停止です。速度の値が電圧に変わるしくみはPWMとは?で解説しています。書き込む前に、車輪が自由に回るよう車を箱の上に載せましょう。setup()の3秒の待ち時間はそのためのものです。
1// Sol motor / left motor: ENA=5, IN1=7, IN2=8 — Sağ motor / right motor: ENB=6, IN3=9, IN4=4
2const int ENA = 5, IN1 = 7, IN2 = 8;
3const int ENB = 6, IN3 = 9, IN4 = 4;
4
5const int SPEED = 180; // temel hız 0-255 / base speed 0-255
6const int TRIM = 0; // % düzeltme: + sol, - sağ motoru yavaşlatır / % trim: + slows left, - slows right
7
8void drive(int left, int right) { // her biri -255 … 255 / each -255 … 255
9 if (TRIM > 0) left = left * (100 - TRIM) / 100;
10 if (TRIM < 0) right = right * (100 + TRIM) / 100;
11 digitalWrite(IN1, left > 0); digitalWrite(IN2, left < 0);
12 digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
13 analogWrite(ENA, abs(left));
14 analogWrite(ENB, abs(right));
15}
16
17void forward() { drive(SPEED, SPEED); }
18void backward() { drive(-SPEED, -SPEED); }
19void turnLeft() { drive(-SPEED, SPEED); } // yerinde sola / spin left in place
20void turnRight() { drive(SPEED, -SPEED); } // yerinde sağa / spin right in place
21void stopCar() { drive(0, 0); }
22
23void setup() {
24 int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
25 for (int p : pins) pinMode(p, OUTPUT);
26 stopCar();
27 delay(3000); // tekerlekleri kaldırmak için zaman / time to lift the wheels
28}
29
30void loop() {
31 forward(); delay(1500);
32 stopCar(); delay(500);
33 backward(); delay(1500);
34 stopCar(); delay(500);
35 turnLeft(); delay(600);
36 stopCar(); delay(500);
37 turnRight(); delay(600);
38 stopCar(); delay(2000);
39}| 動き | 左のモーター | 右のモーター | コード |
|---|---|---|---|
| 前進 | 前 | 前 | drive(180, 180) |
| 後退 | 後ろ | 後ろ | drive(-180, -180) |
| その場で左に回転 | 後ろ | 前 | drive(-180, 180) |
| その場で右に回転 | 前 | 後ろ | drive(180, -180) |
| 大きく左に曲がる | ゆっくり前 | 前 | drive(90, 180) |
| 停止 | 止まる | 止まる | drive(0, 0) |
車輪を浮かせた状態で、車は前進、後退、左、右を順番に行うはずです。片方の車輪が逆に回るなら、コードは変えずに、L298NのOUT端子でそのモーターの2本の線を入れ替えます。両方の車輪が逆に回るなら、両方のモーターの線を入れ替えます。モーターがうなるだけで回らないなら、SPEEDの値が低すぎます。ほとんどのTTモーターは、動き出すのにPWMの値が少なくとも80〜120くらい必要で、このしきい値は電池が減るにつれて上がります。
スマートフォンからBluetoothで操作する(HC-05)
HC-05は、スマートフォンとArduinoの間の無線のシリアルケーブルのように働きます。スマートフォンのアプリが文字を送り、Arduinoがそれを読んで対応する動きをします。Playストアで「Bluetooth RC Car」や「Bluetooth RC Controller」と検索して見つかる操作アプリのほとんどは、前進にF、後退にB、左にL、右にRを送り、ボタンを離すと停止のSを送ります。斜めにG、I、H、Jを、速度に0〜9とqを使うものもあります。モジュールのピン、LEDの点滅パターン、ATコマンドはHC-05 Bluetoothモジュールで解説しています。

- 下のスケッチを書き込む間、車のスイッチはオフのままでかまいません。ArduinoとHC-05はUSBから給電されます。HC-05のLEDが速く点滅していれば、モジュールは接続を待っています。
- AndroidスマートフォンのBluetooth設定でHC-05を見つけ、PIN 1234(だめなら0000)でペアリングします。
- 操作アプリを開き、Bluetoothと付近のデバイスの権限を許可して、デバイスの一覧からHC-05を選びます。接続されると、モジュールのLEDは2秒ごとに2回短く点滅します。
- ArduinoをUSBでつないだまま、シリアルモニタを9600ボーで開き、アプリのボタンを押します。各ボタンが送る文字が画面に表示されます。アプリが違う文字を送るなら、コードのcaseの行をそれに合わせて変えましょう。
- USBケーブルを抜き、スイッチを入れ、車を床に置いて走らせます。
1#include <SoftwareSerial.h>
2
3SoftwareSerial bt(10, 11); // RX, TX → HC-05 TXD, RXD (RXD bölücüyle / RXD via divider)
4
5const int ENA = 5, IN1 = 7, IN2 = 8; // sol motor / left motor
6const int ENB = 6, IN3 = 9, IN4 = 4; // sağ motor / right motor
7const int TRIM = 0; // % düzeltme / % trim
8const unsigned long TIMEOUT = 600; // ms; 0 = kapalı / 0 = disabled
9
10int speed = 200; // 0-255
11unsigned long lastCmd = 0;
12
13void drive(int left, int right) {
14 if (TRIM > 0) left = left * (100 - TRIM) / 100;
15 if (TRIM < 0) right = right * (100 + TRIM) / 100;
16 digitalWrite(IN1, left > 0); digitalWrite(IN2, left < 0);
17 digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
18 analogWrite(ENA, abs(left));
19 analogWrite(ENB, abs(right));
20}
21
22void setup() {
23 int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
24 for (int p : pins) pinMode(p, OUTPUT);
25 drive(0, 0);
26 Serial.begin(9600); // gelen harfleri görmek için / to see incoming letters
27 bt.begin(9600); // HC-05 veri modu hızı / HC-05 data mode baud rate
28}
29
30void loop() {
31 if (bt.available()) {
32 char c = bt.read();
33 Serial.println(c);
34 lastCmd = millis();
35 int half = speed / 2;
36 switch (c) {
37 case 'F': drive(speed, speed); break; // ileri / forward
38 case 'B': drive(-speed, -speed); break; // geri / backward
39 case 'L': drive(-speed, speed); break; // yerinde sola / spin left
40 case 'R': drive(speed, -speed); break; // yerinde sağa / spin right
41 case 'G': drive(half, speed); break; // ileri-sol / forward-left
42 case 'I': drive(speed, half); break; // ileri-sağ / forward-right
43 case 'H': drive(-half, -speed); break; // geri-sol / back-left
44 case 'J': drive(-speed, -half); break; // geri-sağ / back-right
45 case 'S': drive(0, 0); break; // dur / stop
46 case 'q': speed = 255; break; // tam hız / full speed
47 default:
48 if (c >= '0' && c <= '9') speed = map(c - '0', 0, 9, 100, 240); // hız kademesi / speed level
49 }
50 }
51 if (TIMEOUT > 0 && millis() - lastCmd > TIMEOUT) drive(0, 0); // komut yoksa dur / no command: stop
52}| 文字 | 動き | 左 / 右のモーター |
|---|---|---|
| F | 前進 | +速度 / +速度 |
| B | 後退 | −速度 / −速度 |
| L | 左に回転 | −速度 / +速度 |
| R | 右に回転 | +速度 / −速度 |
| G, I | 左前、右前 | 片側を半分の速度に |
| H, J | 左後ろ、右後ろ | 片側を半分の速度に |
| S | 停止 | 0 / 0 |
| 0–9, q | 速度の段階 | 0 → 100, 9 → 240, q → 255 |
コードのTIMEOUTは安全のための機能です。これらのアプリはボタンを押している間ずっと同じ文字を送り続けるので、600 ms文字が来なければ、コードは接続が切れたとみなして車を止めます。こうすれば、スマートフォンが範囲外に出たりアプリが閉じたりしても、車が壁に向かって走り続けることはありません。ボタンを1回押すごとに文字を1回だけ送るアプリだと、車は600 ms後に止まってしまうので、その場合はTIMEOUTを0にしてこの機能をオフにします。また、loop()のどこにもdelay()を使っていません。長い待ち時間があると命令が遅れます。その理由はmillis()とdelay()でわかります。
車がまっすぐ走らない:原因と対処法
両方のモーターに「前進」で同じPWMの値を与えても車が少しずつ片側にそれていくなら、心配はいりません。これはロボットカーで最も多い問題です。安いギア付きモーターは、同じ電圧でも回る速さが違います。ギアの摩擦、ブラシ、磁石の違いで、どのモーターも少しずつ違うのです。そこにゆるい車輪、向きが変わり続けるキャスター、片側に寄った重さが加われば、2メートルで20〜30 cmそれるのはまったく普通のことです。まず機械的な原因を直し、それから残った差をソフトウェアで補正しましょう。
| 症状 | 考えられる原因 | 対処法 |
|---|---|---|
| いつも同じ側にそれる | モーターの速さが違う | TRIMでソフトウェア補正、またはエンコーダー |
| 走り出しでふらつき、そのあとまっすぐになる | 片方のモーターの起動が遅い、またはキャスターの向きが変わる | ソフトスタート。首振りキャスターの代わりにボールキャスター |
| それ方が毎回違う | 車輪がゆるい、タイヤが滑る、モーターの金具が曲がっている | 車輪を軸の奥まで差し込み、ねじを締める |
| 前進せずその場で回転する | 片方のモーターの線が逆 | OUT端子でそのモーターの線を入れ替える |
| 電池が減るにつれてそれが大きくなる | 低い電圧ではモーター間の差が大きくなる | 電池を充電する。TRIMは満充電で設定する |
| 速くなると片側に引っぱられる | 重さが片側に寄っている | 電池と基板を中央の、車輪の軸の近くに移す |
機械的な問題を直したら、ソフトウェアで微調整します。コードのTRIM定数は、速いほうのモーターを割合で遅くします。プラスの値で左のモーターを、マイナスの値で右のモーターを遅くします。次のようにキャリブレーションしましょう。
- 電池を満充電にします。満充電でキャリブレーションすると、結果が安定します。
- 床に2メートルのまっすぐなテープを貼り、テープに沿って車を始点に置きます。
- 最初のスケッチのloop()にforward()と3秒の待ち時間だけを残し、車を走らせます。
- 車が右にそれるなら左のモーターが速いので、TRIMを3増やします。左にそれるならTRIMを3減らします。
- 2メートルでのそれが数センチになるまで繰り返し、同じTRIMの値をBluetoothのスケッチにコピーします。
- 最もよく使う速度でキャリブレーションしましょう。モーター間の差は速度によって少し変わります。
完全にまっすぐ走らせたり距離を測ったりするための次のレベルがエンコーダーです。キットの20スリットの円盤をモーターの軸に取り付け、LM393を使ったスリット式の速度センサーでスリットを1つずつ数えます。センサーの出力を割り込みに対応したD2とD3のピンにつなぎ、2つの車輪のパルス数を比べます。左側が先に進んでいたら、左のモーターを少し遅くします。このシンプルな比例(P)制御で、電池の残量や床に関係なく車はまっすぐ走ります。65 mmの車輪は1回転で約20.4 cm進むので、1パルスはおよそ1 cmの移動にあたります。割り込みのしくみはArduinoの割り込みで解説しています。
モーターが動き出すとArduinoがリセットする
車が走り出したり、向きを変えたり、障害物にぶつかったりしたときに、Arduinoが再起動したり、HC-05の接続が切れたり(LEDがまた速く点滅し始める)するなら、問題はほぼ確実に電源側にあります。起動時、2つのモーターは合わせて2〜3 Aを流すことがあり、弱い電池はそれを出せず、電圧が一瞬崩れます。Unoのプロセッサは、電源が2.7 Vを下回ると安全のために自分でリセットします(ブラウンアウト)。そこにモーターのブラシからの電気的なノイズと、細い線での電圧降下が加わります。効果の大きい順に対処法を紹介します。
- 電池を替える:9 Vの電池や弱った単3電池の代わりに、充電した18650電池2本を使いましょう。ほとんどの問題はこれで終わります。
- 正しい電源の経路を使う:ArduinoにはVINを通して電池から給電し、L298Nの5V出力をVINにつながないでください。
- モーターのコンデンサ:各モーターの2つの端子の間に100 nFのセラミックコンデンサをはんだ付けすると、ブラシのノイズを発生源で抑えられます。
- リザーバーコンデンサ:L298Nの12VとGNDの端子に470〜1000 µFの電解コンデンサをつなぎます(プラスの足を12Vへ)。起動時の一瞬の電流の要求をまかないます。
- ソフトスタート:いきなり255にするのではなく、下のように速度を少しずつ上げます。電流の急増が小さくなります。
- 反転の前に止める:前進から後退にすぐ切り替えると、モーターの電流が最大になります。向きを変える前に100〜200 ms止まりましょう。
- 太く短い電源線:電池とL298Nの間にジャンパーワイヤーやブレッドボードを使わず、0.5 mm²以上の線とねじ端子を使いましょう。
- 電源を分ける:それでも問題が続くなら、Arduinoはモバイルバッテリーから、モーターは電池から給電し、2つのGNDをつなぎます。
1// Yumuşak kalkış: ilk koddaki drive() ile kullan / soft start: use with drive() from the first sketch
2void rampTo(int target) {
3 for (int s = 60; s < target; s += 20) {
4 drive(s, s);
5 delay(15); // yaklaşık 10 adımda tam hız / full speed in about 10 steps
6 }
7 drive(target, target);
8}
9
10// Kullanım: forward() yerine rampTo(SPEED) / usage: rampTo(SPEED) instead of forward()ESP32とRaspberry Pi Picoで作るロボットカー
ESP32はクラシックBluetoothを内蔵しているので、HC-05は不要です。BluetoothSerialライブラリでスマートフォンと同じシリアル接続ができ、上の操作アプリもそのまま使えます。L298Nの入力は約2.3 Vを超えるとHIGHとみなすので、ESP32の3.3 Vの信号で十分です。ESP32ボードは、L298Nの5V出力からボードの5V(VIN)ピンに給電します。電池をそのピンに直接つながないでください。このコードはESP32-S3とESP32-C3ではコンパイルできません。これらはBLEしか持っていないからです。
1#include "BluetoothSerial.h"
2
3BluetoothSerial bt;
4
5const int ENA = 25, IN1 = 27, IN2 = 33; // sol motor / left motor
6const int ENB = 26, IN3 = 32, IN4 = 4; // sağ motor / right motor
7
8int speed = 200; // 0-255
9unsigned long lastCmd = 0;
10
11void drive(int left, int right) {
12 digitalWrite(IN1, left > 0); digitalWrite(IN2, left < 0);
13 digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
14 analogWrite(ENA, abs(left));
15 analogWrite(ENB, abs(right));
16}
17
18void setup() {
19 int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
20 for (int p : pins) pinMode(p, OUTPUT);
21 drive(0, 0);
22 bt.begin("BlueGrays-Car"); // telefonda görünecek ad / name shown on the phone
23}
24
25void loop() {
26 if (bt.available()) {
27 char c = bt.read();
28 lastCmd = millis();
29 switch (c) {
30 case 'F': drive(speed, speed); break; // ileri / forward
31 case 'B': drive(-speed, -speed); break; // geri / backward
32 case 'L': drive(-speed, speed); break; // yerinde sola / spin left
33 case 'R': drive(speed, -speed); break; // yerinde sağa / spin right
34 case 'S': drive(0, 0); break; // dur / stop
35 case 'q': speed = 255; break; // tam hız / full speed
36 default:
37 if (c >= '0' && c <= '9') speed = map(c - '0', 0, 9, 100, 240);
38 }
39 }
40 if (millis() - lastCmd > 600) drive(0, 0); // komut yoksa dur / no command: stop
41}標準のRaspberry Pi PicoにはBluetoothがないので、HC-05をUART0のピンにつなぎます。Picoは3.3 Vで動くので、今回は分圧回路は不要です。PicoはVSYSピンから、HC-05はL298Nの5V出力から直接給電します。USBなしで電池だけで動かすときは、VBUSピンには電圧が来ません。Picoのコードでは、速度を-100〜100のパーセントで指定します。
1from machine import Pin, PWM, UART
2import time
3
4bt = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1)) # GP0 → HC-05 RXD, GP1 ← HC-05 TXD
5
6ena = PWM(Pin(15)); ena.freq(1000) # sol motor hızı / left motor speed
7enb = PWM(Pin(10)); enb.freq(1000) # sağ motor hızı / right motor speed
8in1, in2 = Pin(14, Pin.OUT), Pin(13, Pin.OUT)
9in3, in4 = Pin(12, Pin.OUT), Pin(11, Pin.OUT)
10
11def drive(left, right): # -100 … 100 (%)
12 in1.value(left > 0); in2.value(left < 0)
13 in3.value(right > 0); in4.value(right < 0)
14 ena.duty_u16(int(abs(left) * 655))
15 enb.duty_u16(int(abs(right) * 655))
16
17speed = 80
18last = time.ticks_ms()
19drive(0, 0)
20
21while True:
22 if bt.any():
23 c = bt.read(1)
24 last = time.ticks_ms()
25 if c == b'F': drive(speed, speed) # ileri / forward
26 elif c == b'B': drive(-speed, -speed) # geri / backward
27 elif c == b'L': drive(-speed, speed) # yerinde sola / spin left
28 elif c == b'R': drive(speed, -speed) # yerinde sağa / spin right
29 elif c == b'S': drive(0, 0) # dur / stop
30 elif c == b'q': speed = 100 # tam hız / full speed
31 elif c and 48 <= c[0] <= 57: # '0'…'9' hız kademesi / speed level
32 speed = 40 + (c[0] - 48) * 6
33 if time.ticks_diff(time.ticks_ms(), last) > 600:
34 drive(0, 0) # komut yoksa dur / no command: stop次のステップ:車をアップグレードしよう
- 障害物を避けるロボット:前にHC-SR04距離センサーと、それを左右に向けるサーボモーターを追加します。詳しくは障害物を避けるロボットのガイドをご覧ください。
- ライントレースロボット:前の下側に2〜3個のTCRT5000赤外線センサーを取り付け、床の黒い線をたどります。ライントレースロボットをご覧ください。
- ジョイスティックのリモコン:2台目のArduino、ジョイスティックモジュール、nRF24L01で、スマートフォンのいらない本物のリモコンを作ります。
- 赤外線リモコン:テレビのリモコンのボタンで走らせます。赤外線受信モジュールとリモコンのコードを走行の命令に割り当てます。
- Wi-Fiで走らせる:ESP32で、スマートフォンのブラウザで開く操作ページを配信します。基本はESP32のウェブサーバーとWebSocketのガイドで紹介しています。
- エンコーダーと距離:速度センサーを使って、ちょうど1メートル走り、ちょうど90度曲がらせます。これは迷路を解くロボットの基本です。
- ロボットアーム:車の上にサーボで動く小さなロボットアームを載せて、物を運びます。



よくある失敗と対処法
- どのモーターも回らない:GNDが共通になっていない、スイッチがオフ、ENAとENBのジャンパーを外したのにピンをつないでいない、または電池が切れています。
- L298NのLEDは点いているが、モーターはうなるだけ:PWMの値がモーターの起動のしきい値より低いか、電池の電圧が低くなっています。速度を上げ、電池を充電しましょう。
- スケッチが書き込めない:違うポートやボードを選んでいるかもしれません。HC-05を0番と1番のピンにつないでいるなら、書き込みの間は外しましょう。ほかの原因はArduinoにコードが書き込めないときにあります。
- スマートフォンにHC-05は見えるが接続できない:モジュールが別のスマートフォンにつながっている、アプリに「付近のデバイス」の権限を与えていない、またはペアリングのPINが違います。
- 車が命令に遅れて反応する:loop()にdelay()があるか、シリアルモニタへの表示が多すぎます。待ち時間はmillis()で作りましょう。
- L298Nのヒートシンクがとても熱くなる:車輪が引っかかっているか、4WDの車で1チャンネルあたりの電流が大きすぎます。機械的な摩擦がないか確認しましょう。
- 電源を入れた瞬間に車がぴくっと動く:起動時、少しの間ピンが不定になっています。setup()の最初の行でピンを出力に設定し、drive(0, 0)を呼びましょう。
Arduinoのロボットカーは、モーター制御、電源の管理、無線通信、デバッグを1つのプロジェクトで学べる、すばらしい出発点です。完成すれば、新しいセンサーを足すたびに少しずつ賢くなるシャーシが手に入ります。BlueGraysアプリでは、L298NのBluetooth操作の車、障害物を避けるロボット、TCRT5000での白黒の面の検出のプロジェクトを、回路図とコード付きでステップごとに学べます。
よくある質問
Arduinoで車を作るには何が必要で、いくらかかりますか?
基本のBluetoothの車には、2WDのシャーシキット(TTモーター2個、車輪、キャスター)、Arduino Uno、L298Nモータードライバ、HC-05 Bluetoothモジュール、18650電池2本と電池ボックス、ジャンパーワイヤー数本が必要です。価格は販売店によって違います。モジュールは安く、予算のほとんどはボード、シャーシキット、電池と充電器にかかります。スターターキットをすでに持っていれば、費用はかなり下がります。
Arduinoのロボットカーにはどの電池を使えばいいですか?
最良の選択は、直列にした18650リチウムイオン電池2本です。7.4 Vになり、L298Nでの約2 Vの損失のあとでもモーターに5〜6 Vが残り、起動時に必要な大きな電流も出せます。9 Vの角形電池(PP3)は十分な電流を出せずリセットの原因になり、単3電池4本ではL298Nと組み合わせるとモーターがゆっくりしか回りません。
Arduinoの車がまっすぐ走らないのはなぜですか?
安いギア付きモーターは、同じPWMの値でも回る速さが違い、ゆるい車輪、キャスター、偏った重さもそれを大きくします。まず機械的な問題を直し、それからコードの補正値で速いほうのモーターを少し遅くしましょう。本当にまっすぐ走らせるには、エンコーダーで両方の車輪の速さを測ってそろえる必要があります。
モーターが動き出すとArduinoがリセットするのはなぜですか?
モーターは起動時に数アンペアを流し、弱い電池の電圧は一瞬崩れます。Unoのプロセッサは電源が下がると自分でリセットします。充電した18650電池を使い、モーターの端子の間に100 nFのコンデンサを、L298Nの入力に470〜1000 µFのコンデンサを入れ、速度を少しずつ上げましょう。それでも問題が続くなら、Arduinoを別の電源から給電し、GNDをつなぎます。
HC-05のBluetoothの車はiPhoneで動きますか?
いいえ。HC-05とHC-06はクラシックBluetoothのシリアルポートプロファイルを使い、iOSでは通常のアプリがこの種の接続を開けません。iPhoneから車を操作するには、HM-10などのBLEモジュールか、BLE対応のESP32を使いましょう。AndroidのスマートフォンならHC-05に問題なくつながります。
L298Nの代わりにL293Dモーターシールドを使えますか?
はい。L293DモーターシールドはArduino Unoの上に差し込むタイプで、4つのDCモーターを駆動できるので、4WDの車の配線が簡単になります。ただし、連続電流は1チャンネルあたり約0.6 Aしかないので、モーターが止まったときにL298Nより早く限界に達し、シールドは多くのピンを使います。より効率のよいものがほしいなら、TB6612FNGなどのMOSFETドライバは電圧の損失がずっと少なくなります。
この記事を読んだ後に作れるプロジェクト
全プロジェクトを見る
L298Nで作るBluetooth操作の車
スマートフォンをリモコンにして、自作のロボットカーを操作できます。ArduinoはBluetoothモジュールを通じてスマートフォンのリモコンアプリから指令を受け取り、モータードライバーで車輪を回します。前進、後退、左右や斜めへの移動ができ、速度もスマートフォンから調整できます。停止ボタンを押すと、短いブレーキ動作でモーターがすぐに止まります。

障害物回避ロボット
自分で進む道を見つける、賢い車を作ってみませんか?障害物回避ロボットは、前面の超音波センサーで周囲を常に調べます。障害物を見つけると停止し、サーボモーターで左右を確認して、最も障害物の少ない方向を選んで進みます。自動運転の基礎を学ぶのにぴったりの入門プロジェクトです。

BluetoothでスマートフォンからLEDを操作
スマートフォンで部屋の照明をつけたり消したりするための、小さな練習です。Bluetoothモジュールがスマートフォンから送られた文字をArduinoに伝えます。ある文字で赤いLEDが、別の文字で緑のLEDが点灯し、同じ文字を小文字で送ると消灯します。無線操作の仕組みを、ごくシンプルな形で学べます。

TCRT5000で床面の白黒を判別
ライントレースロボットの目となる小さなセンサーで、床面が黒か白かを判別できます。TCRT5000センサーは目に見えない光を床面に当て、戻ってくる光の量を調べます。白い面では緑のLED、黒い面では赤のLEDが点灯します。自分でロボットを作る前に学んでおきたい大切なステップです。

TCRT5000で反射(近接)を読み取る
目に見えない光を出し、その反射量を測る小さなセンサーで、前方の表面を検出できます。物体や明るい色の表面にセンサーを近づけるほど戻ってくる光が増え、Arduinoがその値を0.5秒ごとに画面に数値で表示します。ライントレースロボットや非接触式の水栓には、このようなセンサーが使われています。

HC-SR04で距離を測定(シリアルモニタ表示)
HC-SR04センサーは、コウモリが暗闇で道を見つけるのと同じ仕組みで動作します。人には聞こえない音を出し、その反響を捉えて前方の物体までの距離を測ります。Arduinoは0.5秒ごとに距離をセンチメートル単位でコンピューターの画面に表示し、3〜100センチメートルの測定値を示します。駐車センサーや障害物を避けるロボットなどのプロジェクトの基礎になります。

HC-SR04で作る駐車センサー
車の駐車センサーを小さく再現します。物体が近づくほど、ビープ音の間隔が短くなります。距離センサーが前方の物体までの距離を測り、20センチメートルより遠ければ緑のLEDが点灯します。近づくと赤いLEDが点滅してブザーが鳴り、さらに近づくほど警告の間隔が短くなります。車が壁にぶつからずに駐車できる仕組みを、机の上で確かめられます。

サーボモーターの使い方
小型サーボモーターのアームが、一方の端、中央、もう一方の端の3つの位置へ順番に回り、それぞれの位置で2秒間止まります。Arduinoが保持する角度をモーターに指示すると、モーターはその位置まで動いて止まります。ロボットアームや自動開閉するふたが動く仕組みを学べます。
ほかの記事
BlueGraysアプリ
この回路をスマホでステップごとに作る
回路図、コード、部品リストを1つの画面で確認できます。Arduino、ESP32、Picoのプロジェクトを200件以上用意しています。

