ガイド · 読了まで19分

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 Uno
Arduino Uno
L298N
L298N
HC-05
HC-05
18650リチウムイオン電池
18650リチウムイオン電池

Arduinoのロボットカーのしくみ

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

黄色のギア付きTTモーターと65 mmの車輪のセット
ロボットカーの定番のモーター:黄色のプラスチックのギアボックス付きTTモーターと65 mmの車輪です。ギアボックスでモーターの回転を48分の1に落とし、トルクを上げています。
項目黄色の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ケーブル1Nanoでも可。ピン番号は同じ
L298Nモータードライバモジュール11チャンネルあたり2 A。2つのモーターを別々に駆動
HC-05またはHC-06 Bluetoothモジュール1Androidのスマートフォンとの通信用
18650リチウムイオン電池25 A以上を出せるメーカー品
18650用2本電池ボックス(直列)12本を直列にして7.4 Vにする
18650用充電器11本ずつ別々に充電できる充電器
ジャンパーワイヤー(オス-メス、メス-メス)20+Arduino、L298N、HC-05の間
1 kΩと2 kΩの抵抗1 + 1HC-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」と書かれたとても安い電池はたいてい偽物。ここは節約しない
線、抵抗、コンデンサ、ねじ低ほとんどはスターターキットに入っている
Arduinoスターターキットをすでに持っていれば、ボード、ジャンパーワイヤー、抵抗はそろっています。必要なのはシャーシキット、L298N、HC-05、電池だけです。すべてが1箱に入った既製の「スマートカーキット」は、専用のモーター基板と既製のコードが付いていて便利ですが、値段が高く、配線を学ぶ機会もなくなります。

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時間のほうが現実的な数字です。自分の値で計算するには電池寿命ツールを使いましょう。

18650リチウムイオン充電池
18650リチウムイオン電池:直径18 mm、長さ65 mmで、満充電で4.2 V、平均3.6〜3.7 Vです。2本を直列にすると、ロボットカーに理想的な7.4 Vのパックになります。
電源電圧電流の供給能力ロボットカーには
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に別に給電する場合のみ
リチウムイオン電池は強力ですが、注意が必要です。電池を入れるときは、プラスとマイナスの向きを2回確認しましょう。逆に入れたりショートさせたりした18650電池はとても熱くなり、火事の原因になることがあります。1本あたりの電圧は決して3.0 Vを下回らないようにし、車が遅くなり始めたら(パックで約6.6 V)充電しましょう。TP4056モジュールは1本の電池しか充電できず、直列のパックを直接充電することはできません。電池をボックスから取り出して18650用の充電器で充電し、充電中は決して目を離さないでください。

残量を推測する代わりに、測ることもできます。電池のプラス(スイッチのあと)を、10 kΩの抵抗2本で作った分圧回路を通してA0につなぎます。8.4 VのパックはA0では4.2 Vになり、Arduinoが読める上限の5 Vを下回ります。分圧回路が流す電流は約0.4 mAだけなので、電池のもちには影響しません。

C++ (Arduino IDE)
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}

ステップごとの組み立て

  1. アクリル部品の保護紙をはがします。モーターに線が付いていなければ、各モーターに2本の線をはんだ付けし、はんだの部分をホットボンドで補強します。振動でモーターの線が取れるのが最も多い故障です。
  2. キットのT字型のアクリル金具と長いM3のねじで、モーターをシャーシの裏側に固定します。2つのモーターの軸がまっすぐ並び、モーターの線の端子が内側を向くようにします。
  3. エンコーダー円盤を使うつもりなら、今のうちにモーター軸の内側に取り付けます。車輪を付けたあとでは難しくなります。
  4. シャーシの反対側の中央に、スペーサーを使ってキャスターを取り付けます。シャーシが床と平行になる高さのスペーサーを選びます。
  5. D字型の軸に合わせて、車輪を奥まで押し込みます。車輪がゆるいと、車はずっとそれ続けます。
  6. 電池ボックスを両面テープかマジックテープで、重さが車輪の軸の近くにかかる位置に置きます。重さのほとんどがキャスターにかかると、駆動輪が空回りします。
  7. プラスチックのスペーサーで、ArduinoとL298Nを上段に取り付けます。ArduinoのUSBポートに楽に手が届き、L298Nのヒートシンクが外気に触れるようにします。金属のねじが基板の裏のはんだに触れないよう注意しましょう。
  8. 電池のプラスの線にスイッチを直列に入れ、電池を外さなくても車をオン・オフできるようにします。
  9. 各モーターの2本の線をより合わせてL298Nまで引き、すべての線を短くして結束バンドでまとめます。電池を入れる前に、テスターで電池の端子の間がショートしていないことを確かめましょう。
モーターをシャーシに取り付ける前に、各モーターの線を単3電池2本に短く当てて回る向きを確かめ、線に印を付けておきましょう。両方のモーターに「赤の線をプラスにすると前進」と印を付けておけば、配線で向きを間違えることはありません。

配線図

配線は2つの部分に分けて考えましょう。電源側(電池、スイッチ、L298N、モーター)と信号側(ArduinoからL298NとHC-05への細い線)です。L298NのENAとENBのピンにある小さなジャンパーを外します。速度をコードで設定するため、これらのピンをArduinoのPWM出力につなぎます。L298Nの5Vジャンパーはそのままにします。パックは12 V未満なので、ボード自体のレギュレーターがドライバのロジックに給電します。

L298N 2チャンネルモータードライバモジュール
L298Nモータードライバ:モーターは両側の青いねじ端子に、電池は前の3端子につなぎます。ENA、IN1〜IN4、ENBのピンはArduinoにつなぎます。
L298Nの端子接続
OUT1、OUT2左のモーター(4WDでは左の2つのモーターを並列に)
OUT3、OUT4右のモーター(4WDでは右の2つのモーターを並列に)
12Vスイッチを通して電池のプラス
GND電池のマイナスとArduinoのGNDピン(共通GND)
5VArduino Unoでは何もつながない。ESP32とPicoではボードに給電する
5Vジャンパー付けたまま(電池は12 V未満)
ENAとENBのジャンパー外す。ピンはArduinoのPWM出力へ
接続Arduino UnoESP32Raspberry Pi Pico
L298NのENA(左のモーターの速度)D5(PWM)GPIO 25GP15
L298NのIN1D7GPIO 27GP14
L298NのIN2D8GPIO 33GP13
L298NのENB(右のモーターの速度)D6(PWM)GPIO 26GP10
L298NのIN3D9GPIO 32GP12
L298NのIN4D4GPIO 4GP11
HC-05のTXDD10(SoftwareSerialのRX)不要(Bluetooth内蔵)GP1(UART0 RX)
HC-05のRXDD11、1 kΩ / 2 kΩの分圧回路を通して不要GP0(UART0 TX)、直接
HC-05のVCC5V不要L298Nの5V出力
ボードの電源VIN ← スイッチのあとの電池のプラス5V(VIN) ← L298Nの5V出力VSYS ← L298Nの5V出力
GNDL298NのGNDと電池のマイナスと共通共通共通
3つのルールは決して破らないでください。すべてのGND(電池のマイナス、L298N、Arduino、HC-05)をつなぐこと、モーターをArduinoの5Vピンから決して給電しないこと、そしてL298Nの5V出力をArduinoのVINピンにつながないことです。VINには最低7 Vが必要で、5 VではArduinoのレギュレーターが正しく動かず、ボードが不安定になります。HC-05のRXDピンは3.3 Vの入力なので、UnoのTXの5 Vの信号を1 kΩと2 kΩの分圧回路で下げます。D11 → 1 kΩ → RXD、RXD → 2 kΩ → GNDです(5 V × 2/3 ≈ 3.3 V)。

速度用のピンに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秒の待ち時間はそのためのものです。

C++ (Arduino IDE)
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モジュールで解説しています。

HC-05 Bluetoothモジュール
HC-05:クラシックBluetooth(SPP)でスマートフォンとつながります。初期設定の速度は9600ボー、ペアリングのPINは1234か0000です。
  1. 下のスケッチを書き込む間、車のスイッチはオフのままでかまいません。ArduinoとHC-05はUSBから給電されます。HC-05のLEDが速く点滅していれば、モジュールは接続を待っています。
  2. AndroidスマートフォンのBluetooth設定でHC-05を見つけ、PIN 1234(だめなら0000)でペアリングします。
  3. 操作アプリを開き、Bluetoothと付近のデバイスの権限を許可して、デバイスの一覧からHC-05を選びます。接続されると、モジュールのLEDは2秒ごとに2回短く点滅します。
  4. ArduinoをUSBでつないだまま、シリアルモニタを9600ボーで開き、アプリのボタンを押します。各ボタンが送る文字が画面に表示されます。アプリが違う文字を送るなら、コードのcaseの行をそれに合わせて変えましょう。
  5. USBケーブルを抜き、スイッチを入れ、車を床に置いて走らせます。
C++ (Arduino IDE)
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()でわかります。

HC-05とHC-06はクラシックBluetoothを使うので、iPhoneでは動きません。iOSはこの種のシリアル接続を許可していないからです。iPhoneで操作したいなら、HM-10などのBLEモジュールか、BLE対応のESP32を使いましょう。自分で操作アプリを作りたいなら、App InventorでArduinoとBluetoothのガイドを見てみましょう。

車がまっすぐ走らない:原因と対処法

両方のモーターに「前進」で同じPWMの値を与えても車が少しずつ片側にそれていくなら、心配はいりません。これはロボットカーで最も多い問題です。安いギア付きモーターは、同じ電圧でも回る速さが違います。ギアの摩擦、ブラシ、磁石の違いで、どのモーターも少しずつ違うのです。そこにゆるい車輪、向きが変わり続けるキャスター、片側に寄った重さが加われば、2メートルで20〜30 cmそれるのはまったく普通のことです。まず機械的な原因を直し、それから残った差をソフトウェアで補正しましょう。

症状考えられる原因対処法
いつも同じ側にそれるモーターの速さが違うTRIMでソフトウェア補正、またはエンコーダー
走り出しでふらつき、そのあとまっすぐになる片方のモーターの起動が遅い、またはキャスターの向きが変わるソフトスタート。首振りキャスターの代わりにボールキャスター
それ方が毎回違う車輪がゆるい、タイヤが滑る、モーターの金具が曲がっている車輪を軸の奥まで差し込み、ねじを締める
前進せずその場で回転する片方のモーターの線が逆OUT端子でそのモーターの線を入れ替える
電池が減るにつれてそれが大きくなる低い電圧ではモーター間の差が大きくなる電池を充電する。TRIMは満充電で設定する
速くなると片側に引っぱられる重さが片側に寄っている電池と基板を中央の、車輪の軸の近くに移す

機械的な問題を直したら、ソフトウェアで微調整します。コードのTRIM定数は、速いほうのモーターを割合で遅くします。プラスの値で左のモーターを、マイナスの値で右のモーターを遅くします。次のようにキャリブレーションしましょう。

  1. 電池を満充電にします。満充電でキャリブレーションすると、結果が安定します。
  2. 床に2メートルのまっすぐなテープを貼り、テープに沿って車を始点に置きます。
  3. 最初のスケッチのloop()にforward()と3秒の待ち時間だけを残し、車を走らせます。
  4. 車が右にそれるなら左のモーターが速いので、TRIMを3増やします。左にそれるならTRIMを3減らします。
  5. 2メートルでのそれが数センチになるまで繰り返し、同じTRIMの値をBluetoothのスケッチにコピーします。
  6. 最もよく使う速度でキャリブレーションしましょう。モーター間の差は速度によって少し変わります。

完全にまっすぐ走らせたり距離を測ったりするための次のレベルがエンコーダーです。キットの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をつなぎます。
C++ (Arduino IDE)
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()
問題が電源かコードかを簡単に見分ける方法があります。VINの線を外し、ArduinoはパソコンのUSBから給電したままにして(GNDの接続はそのまま)、モーターを電池で動かします。リセットが止まれば、問題は確実に電源側です。VINとGNDの間にテスターをつなぎ、車が走り出すときの電圧を見ると、落ち込みが直接わかります。ほかの原因についてはArduinoがリセットを繰り返すときをご覧ください。

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しか持っていないからです。

C++ (Arduino IDE)
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のパーセントで指定します。

MicroPython
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度曲がらせます。これは迷路を解くロボットの基本です。
  • ロボットアーム:車の上にサーボで動く小さなロボットアームを載せて、物を運びます。
HC-SR04
HC-SR04
TCRT5000
TCRT5000
SG90サーボ
SG90サーボ

よくある失敗と対処法

  • どのモーターも回らない: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操作の車
#80上級
プレミアム

L298Nで作るBluetooth操作の車

スマートフォンをリモコンにして、自作のロボットカーを操作できます。ArduinoはBluetoothモジュールを通じてスマートフォンのリモコンアプリから指令を受け取り、モータードライバーで車輪を回します。前進、後退、左右や斜めへの移動ができ、速度もスマートフォンから調整できます。停止ボタンを押すと、短いブレーキ動作でモーターがすぐに止まります。

5.0(38)
65
障害物回避ロボット
#81上級
プレミアム

障害物回避ロボット

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

5.0(38)
49
BluetoothでスマートフォンからLEDを操作
#34初級
プレミアム

BluetoothでスマートフォンからLEDを操作

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

4.8(68)
89
TCRT5000で床面の白黒を判別
#78中級
プレミアム

TCRT5000で床面の白黒を判別

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

4.7(40)
49
TCRT5000で反射(近接)を読み取る
#77中級
プレミアム

TCRT5000で反射(近接)を読み取る

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

4.6(33)
43
HC-SR04で距離を測定(シリアルモニタ表示)
#27初級

HC-SR04で距離を測定(シリアルモニタ表示)

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

4.6(46)
71
HC-SR04で作る駐車センサー
#28中級
プレミアム

HC-SR04で作る駐車センサー

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

4.8(64)
85
サーボモーターの使い方
#35初級
プレミアム

サーボモーターの使い方

小型サーボモーターのアームが、一方の端、中央、もう一方の端の3つの位置へ順番に回り、それぞれの位置で2秒間止まります。Arduinoが保持する角度をモーターに指示すると、モーターはその位置まで動いて止まります。ロボットアームや自動開閉するふたが動く仕組みを学べます。

4.7(48)
67