首頁 › 動手做 › ESP32 避障小車

ESP32 避障小車:用超音波做一台會自己閃開障礙物的車

難度:入門時間:約 90 分鐘免焊接ESP32 套件 3.x

這是 TinyBot Forge 的第一個專案。做完之後,你會懂三件事:怎麼用超音波量距離、怎麼用 PWM 控制馬達速度,以及怎麼讓機器人根據感測器「自己做決定」。

✓ 本文程式已在 2026/09/29 以 Arduino ESP32 開發板套件 3.3.12 編譯通過(開啟全部編譯警告,0 個警告),開發板選 ESP32 Dev Module。

1. 需要的零件

零件數量說明
ESP32 DevKit V1(30 或 38 腳)1本文腳位以 38 腳版標示,30 腳版腳位名稱相同
HC-SR04 超音波感測器1量測範圍約 2–400 cm
L298N 馬達驅動板1最常見的紅色雙 H 橋模組
兩輪車架套件(含 2 顆 TT 減速馬達、萬向輪)1俗稱「智能小車底盤」
18650 電池 ×2 與雙槽電池盒1 組約 7.4 V;也可用 6 顆 3 號電池盒
電阻 1 kΩ、2 kΩ各 1給 ECHO 腳分壓用,不可省略
杜邦線(公對母、母對母)、小麵包板若干

零件購買連結整理中,上線後會放在這裡。

2. 運作原理

HC-SR04 發出一段 40 kHz 的超音波,碰到障礙物反彈回來。ECHO 腳維持高電位的時間,就是聲音來回所花的時間。聲速約 343 m/s,來回 1 公分大約是 58 微秒,所以:

距離(cm)= 高電位時間(µs)÷ 58

小車每隔約 70 毫秒量一次距離。前方超過 20 公分就直走;小於 20 公分就停車、倒退、右轉,右邊也擋住的話改往左轉。

3. 接線

ESP32 GPIO18 TRIGGPIO19 ECHOVIN ← 5VGND GPIO25 ENAGPIO26/27 IN1/2GPIO33 ENBGPIO32/13 IN3/4 HC-SR04VCC TRIG ECHO GND 分壓ECHO → 1kΩ → GPIO19GPIO19 → 2kΩ → GND L298NENA IN1 IN2ENB IN3 IN412V 輸入 · 5V 輸出GND(共地) 左馬達 右馬達 電池 7.4V L298N 5V → ESP32 VIN;所有 GND 接在一起
接線示意圖。逐腳接法請看下表。
從接到備註
HC-SR04 VCCL298N 5V 輸出HC-SR04 需要 5V
HC-SR04 TRIGESP32 GPIO 183.3V 觸發訊號 HC-SR04 讀得到
HC-SR04 ECHO1 kΩ → GPIO 19;GPIO 19 再經 2 kΩ 接 GND把 5V 分壓成約 3.3V
HC-SR04 GNDGND
L298N ENAESP32 GPIO 25先拔掉 ENA 上的跳帽
L298N IN1 / IN2ESP32 GPIO 26 / 27
L298N ENBESP32 GPIO 33先拔掉 ENB 上的跳帽
L298N IN3 / IN4ESP32 GPIO 32 / 13
L298N OUT1 / OUT2左馬達兩條線轉向相反就對調
L298N OUT3 / OUT4右馬達兩條線轉向相反就對調
電池 +L298N 12V 輸入保留 L298N 上「5V 使能」跳帽
電池 -L298N GND
L298N 5V 輸出ESP32 VIN用電池時不要同時插 USB 供電跑馬達
L298N GNDESP32 GND一定要共地,否則訊號不穩
最常燒板子的錯誤:HC-SR04 的 ECHO 腳直接接 ESP32。ECHO 輸出 5V,ESP32 腳位只能承受 3.3V,短時間可能還能動,但長期會損壞腳位。請一定加分壓電阻。

4. 安裝 ESP32 開發環境

  1. 安裝 Arduino IDE 2。
  2. 檔案 → 偏好設定 → 「額外的開發板管理員網址」,貼上:
    https://espressif.github.io/arduino-esp32/package_esp32_index.json
  3. 工具 → 開發板 → 開發板管理員,搜尋 esp32,安裝 Espressif Systems 的 esp32,版本 3.0 以上。
  4. 工具 → 開發板,選 ESP32 Dev Module,再選對 USB 序列埠。

電腦抓不到序列埠的話,通常是缺 USB 驅動:板子上的晶片是 CP2102 就裝 Silicon Labs 驅動,是 CH340 就裝 WCH 驅動。

5. 程式

/*
 * TinyBot Forge — ESP32 避障小車
 * https://tinybotforge.com
 *
 * 硬體:ESP32 DevKit V1、HC-SR04 超音波感測器、L298N 馬達驅動板、兩顆 TT 直流馬達
 * 環境:Arduino IDE 2.x + ESP32 開發板套件 3.x(使用 ledcAttach / ledcWrite 新版 API)
 *
 * 注意:HC-SR04 的 ECHO 腳輸出 5V,ESP32 腳位只能承受 3.3V,
 *       ECHO 必須經過分壓電阻(1kΩ + 2kΩ)再接到 GPIO 19。
 */

// ---------- 腳位 ----------
const int PIN_TRIG = 18;   // HC-SR04 TRIG
const int PIN_ECHO = 19;   // HC-SR04 ECHO(經分壓)

const int PIN_ENA = 25;    // 左馬達速度(PWM)
const int PIN_IN1 = 26;    // 左馬達方向
const int PIN_IN2 = 27;
const int PIN_ENB = 33;    // 右馬達速度(PWM)
const int PIN_IN3 = 32;    // 右馬達方向
const int PIN_IN4 = 13;

// ---------- 參數(可依你的車調整) ----------
const int PWM_FREQ = 1000;      // PWM 頻率 1 kHz
const int PWM_BITS = 8;         // 解析度 8 bit → 速度 0–255
const int SPEED_CRUISE = 170;   // 直走速度
const int SPEED_TURN   = 160;   // 轉彎速度
const float STOP_CM    = 20.0;  // 小於這個距離就閃避
const unsigned long BACK_MS = 350;  // 倒車時間
const unsigned long TURN_MS = 450;  // 轉彎時間

// ---------- 馬達 ----------
// speed:-255(全速後退)到 255(全速前進)
void setMotor(int pinEn, int pinA, int pinB, int speed) {
  speed = constrain(speed, -255, 255);
  digitalWrite(pinA, speed > 0 ? HIGH : LOW);
  digitalWrite(pinB, speed < 0 ? HIGH : LOW);
  ledcWrite(pinEn, abs(speed));
}

void drive(int left, int right) {
  setMotor(PIN_ENA, PIN_IN1, PIN_IN2, left);
  setMotor(PIN_ENB, PIN_IN3, PIN_IN4, right);
}

void stopCar() { drive(0, 0); }

// ---------- 超音波測距 ----------
// 回傳公分;超過量測範圍回傳 999
float readOnceCm() {
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  unsigned long us = pulseIn(PIN_ECHO, HIGH, 25000UL);  // 25 ms ≈ 4 公尺
  if (us == 0) return 999.0;
  return us / 58.0;  // 聲速換算:來回 1 cm ≈ 58 µs
}

// 量三次取中位數,濾掉偶發的錯誤讀數
float readDistanceCm() {
  float a = readOnceCm(); delay(10);
  float b = readOnceCm(); delay(10);
  float c = readOnceCm();
  if (a > b) { float t = a; a = b; b = t; }
  if (b > c) { float t = b; b = c; c = t; }
  if (a > b) { float t = a; a = b; b = t; }
  return b;
}

// ---------- 閃避 ----------
void avoid() {
  stopCar();
  delay(100);
  drive(-SPEED_CRUISE, -SPEED_CRUISE);   // 倒車
  delay(BACK_MS);

  drive(SPEED_TURN, -SPEED_TURN);        // 先試右轉
  delay(TURN_MS);
  stopCar();
  delay(80);
  if (readDistanceCm() > STOP_CM * 1.5) return;

  drive(-SPEED_TURN, SPEED_TURN);        // 右邊也擋住,改往左轉兩倍時間
  delay(TURN_MS * 2);
  stopCar();
  delay(80);
}

void setup() {
  Serial.begin(115200);

  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  pinMode(PIN_IN1, OUTPUT);
  pinMode(PIN_IN2, OUTPUT);
  pinMode(PIN_IN3, OUTPUT);
  pinMode(PIN_IN4, OUTPUT);

  ledcAttach(PIN_ENA, PWM_FREQ, PWM_BITS);
  ledcAttach(PIN_ENB, PWM_FREQ, PWM_BITS);

  stopCar();
  Serial.println("TinyBot 避障小車:2 秒後出發");
  delay(2000);
}

void loop() {
  float cm = readDistanceCm();
  Serial.printf("距離 %.1f cm\n", cm);

  if (cm < STOP_CM) {
    avoid();
  } else {
    drive(SPEED_CRUISE, SPEED_CRUISE);
  }
  delay(40);
}
下載 .ino 檔

程式重點

6. 測試與調整

  1. 先架空測試:把車底墊高讓輪子懸空,上傳程式,打開序列埠監控視窗(115200 baud),用手在感測器前移動,確認距離數字合理。
  2. 確認轉向:輪子應該往前轉。哪一邊轉反了,就把那顆馬達的兩條線對調。
  3. 放到地上跑。
想調整改這個參數
車子太快、撞上才閃調低 SPEED_CRUISE,或調高 STOP_CM
轉不夠角度調高 TURN_MS
馬達嗡嗡叫但不轉調高速度數值;TT 馬達低於約 120 常常推不動

7. 常見問題

距離一直顯示 999

沒收到回音。檢查 ECHO 分壓接線、HC-SR04 是否有 5V 供電、GND 是否共地。

一接馬達 ESP32 就重開機

馬達啟動瞬間電流很大,把電壓拉低了。改用充飽的 18650,不要只靠 USB 供電;ESP32 的 VIN 與 GND 之間可以並一顆 100 µF 電容。

上傳時出現 Failed to connect

按住板子上的 BOOT 鍵,等畫面出現 Connecting… 再放開。

車子走不直

兩顆 TT 馬達本來就有轉速差異。把跑比較快那一邊的速度調低 5 到 15。

下一步:讓它更聰明

這是「ESP32 機器人 10 個專案」的第 1 個專案。免費下載「ESP32 機器人零件與接線速查表」,一張 A4 把常用接法整理好。

免費下載速查表 PDF