ESP32 รีเซ็ตเองตอนมอเตอร์หมุน (Brownout) สาเหตุและวิธีแก้
ESP32 รีบูตทุกครั้งที่มอเตอร์ออกตัวและขึ้น Brownout detector was triggered เพราะไฟตก วิธีแยกไฟมอเตอร์ ใส่ตัวเก็บประจุ ใช้ buck 5 V และค่อยๆ เร่งมอเตอร์
ถ้า ESP32 รีสตาร์ทเองทุกครั้งที่มอเตอร์เริ่มหมุน และ Serial Monitor ขึ้นข้อความ Brownout detector was triggered
แปลว่าแรงดันไฟเลี้ยงบอร์ดตกลงชั่วขณะจนต่ำกว่าเกณฑ์ ชิปจึงรีเซ็ตตัวเองเพื่อป้องกันการทำงานผิดพลาด
ทางแก้คือแยกไฟของมอเตอร์ออกจากไฟของบอร์ด ให้มีไฟสำรองพอตอนกระแสกระชาก และไม่ควรปิดตัวตรวจ brownout
อาการที่เห็นใน Serial Monitor
Brownout detector was triggered
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
...
บรรทัดแรกคือตัวบอกสาเหตุ ส่วนที่ตามมาคือข้อความตอนบูตใหม่ ถ้าเห็นวนซ้ำทุกครั้งที่สั่งมอเตอร์ หรือทุกครั้งที่ WiFi เริ่มเชื่อมต่อ ปัญหาเป็นเรื่องไฟเลี้ยงแน่นอน บางครั้งบอร์ดไม่ขึ้นข้อความนี้แต่ค้างหรือรีเซ็ตเฉยๆ ก็มาจากสาเหตุเดียวกันได้
ทำไมไฟตกตอนมอเตอร์ออกตัว
- กระแสกระชากตอนเริ่มหมุน มอเตอร์ DC ตอนหยุดนิ่งมีความต้านทานต่ำ จังหวะออกตัวจึงดึงกระแสหลายเท่าของตอนหมุนปกติ โดยเฉพาะตอนสั่งจากหยุดไปเต็มกำลังทันที หรือตอนกลับทิศทาง
- มอเตอร์กับบอร์ดใช้ไฟเส้นเดียวกัน เช่นต่อมอเตอร์กับขา 5V/VIN ของบอร์ด หรือใช้ไฟจากพอร์ต USB ของคอมพิวเตอร์ ซึ่งจ่ายได้ราว 500 mA เท่านั้น
- WiFi ซ้ำเติม ESP32 ดึงกระแสเป็นจังหวะสั้นๆ สูงหลายร้อย mA ตอนส่งสัญญาณ ถ้าเกิดพร้อมกับมอเตอร์ออกตัว ไฟจะตกลึงกว่าเดิม
- แบตอ่อนหรือสายยาวเกิน แบตใกล้หมดและสายจัมเปอร์เส้นเล็กยาวๆ มีความต้านทาน แรงดันจึงตกมากขึ้นเมื่อกระแสสูง
วิธีแก้ เรียงจากสำคัญที่สุด
- แยกไฟมอเตอร์กับไฟบอร์ด ต่อแบตเข้าขา
VMของ motor driver โดยตรง แล้วใช้ buck converter ลดแรงดันแบตลงเป็น 5 V จ่ายเข้าขา5V(VIN) ของ ESP32 อีกทางหนึ่ง กระแสของมอเตอร์ไม่ต้องผ่านวงจรของบอร์ดเลย - ต่อ GND ร่วมกันทุกส่วน แบต, motor driver, buck และ ESP32 ต้องใช้กราวด์เดียวกัน ไม่งั้นสัญญาณ PWM จะไม่มีจุดอ้างอิง ให้เดินสายกราวด์ของมอเตอร์กลับไปที่แบตโดยตรง ไม่ผ่านบอร์ด
- ใช้ buck ที่จ่ายได้เหลือ buck 5 V 3 A มีกำลังสำรองพอสำหรับ ESP32 กับ servo และเซนเซอร์ ตัวเล็กๆ ที่จ่ายได้ไม่ถึง 1 A จะเป็นจุดอ่อนอีกจุด
- ใส่ตัวเก็บประจุ
- ตัวเก็บประจุอิเล็กโทรไลต์ 100–470 µF คร่อมขา 5V กับ GND ใกล้ ESP32 (ระวังขั้ว: ขาสั้นคือขั้วลบ) ช่วยเลี้ยงบอร์ดในจังหวะที่ไฟตก
- ตัวเก็บประจุเซรามิก 0.1 µF (104) บัดกรีคร่อมขั้วมอเตอร์แต่ละตัว ช่วยลดสัญญาณรบกวนจากแปรงถ่านของมอเตอร์
- ค่อยๆ เร่งมอเตอร์ในโค้ด แทนที่จะสั่งจาก 0 ไปเต็มกำลังทันที ให้ไล่ PWM ขึ้นทีละขั้น กระแสกระชากจะลดลงมาก (ดูโค้ดด้านล่าง)
- ชาร์จแบตให้เต็ม แบต 18650 สองก้อนอนุกรม (2S) ควรมีแรงดันรวมไม่ต่ำกว่าราว 7 V ตอนใช้งาน ถ้าต่ำกว่านี้อาการจะกลับมาแม้วงจรถูกแล้ว อ่านเรื่องเลือกและดูแลแบตได้ใน บทความเลือกแบตเตอรี่
วงจรที่แยกไฟถูกต้อง
แบต 2S (7.4 V) ──┬──▶ VM ของ TB6612FNG ──▶ มอเตอร์
│
└──▶ buck 5 V ──▶ 5V (VIN) ของ ESP32
│
3V3 ──▶ VCC ของ TB6612FNG (ลอจิก)
GND ของแบต, buck, TB6612FNG และ ESP32 ต่อถึงกันทั้งหมด
| TB6612FNG Motors | VM → แบต 7.4 VVCC → 3V3GND → GNDPWMA → GPIO25AIN1 → GPIO27AIN2 → GPIO14PWMB → GPIO26BIN1 → GPIO13BIN2 → GPIO4STBY → 3V3 (ต่อค้างไว้) |
|---|
โค้ดเร่งมอเตอร์แบบค่อยเป็นค่อยไป
ต่อยอดจากฟังก์ชัน motor() ใน บทความ TB6612FNG
เก็บความเร็วปัจจุบันไว้ แล้วขยับเข้าหาความเร็วเป้าหมายทีละไม่เกิน STEP ทุก 10 มิลลิวินาที
const int PWMA = 25, AIN1 = 27, AIN2 = 14; // ล้อซ้าย
const int PWMB = 26, BIN1 = 13, BIN2 = 4; // ล้อขวา
const int STEP = 8; // เปลี่ยนได้ไม่เกินเท่านี้ต่อ 10 ms (0 → 200 ใช้ราว 0.25 วินาที)
int targetL = 0, targetR = 0; // ความเร็วที่อยากได้ -255..255
int nowL = 0, nowR = 0; // ความเร็วที่สั่งอยู่จริง
void motor(int pwm, int in1, int in2, int speed) {
digitalWrite(in1, speed > 0);
digitalWrite(in2, speed < 0);
analogWrite(pwm, abs(speed));
}
int approach(int now, int target) {
if (now < target) return min(now + STEP, target);
if (now > target) return max(now - STEP, target);
return now;
}
void updateMotors() {
static unsigned long last = 0;
if (millis() - last < 10) return;
last = millis();
nowL = approach(nowL, targetL);
nowR = approach(nowR, targetR);
motor(PWMA, AIN1, AIN2, nowL);
motor(PWMB, BIN1, BIN2, nowR);
}
void setup() {
Serial.begin(115200);
int pins[] = { PWMA, AIN1, AIN2, PWMB, BIN1, BIN2 };
for (int p : pins) pinMode(p, OUTPUT);
}
void loop() {
updateMotors(); // เรียกทุกรอบ ห้ามใช้ delay() ยาวๆ
if (millis() % 4000 < 2000) { targetL = 200; targetR = 200; }
else { targetL = -150; targetR = -150; }
}
การกลับทิศจากเดินหน้าเป็นถอยหลังจะค่อยๆ ผ่าน 0 ไปเอง ซึ่งเป็นจังหวะที่มอเตอร์ดึงกระแสสูงที่สุด
ทำไมไม่ควรปิด brownout detector
ในเว็บบอร์ดมักแนะนำให้ใส่ WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) เพื่อปิดตัวตรวจ ซึ่งทำให้ข้อความหายไปจริง
แต่ไฟยังตกเหมือนเดิม สิ่งที่ตามมาคือ
- ชิปทำงานต่อที่แรงดันต่ำกว่าที่ออกแบบไว้ โค้ดอาจค้าง ค่าตัวแปรเพี้ยน หรือ WiFi หลุดแบบหาสาเหตุไม่เจอ
- ถ้าไฟตกตอนกำลังเขียน flash (เช่นบันทึกค่าตั้งด้วย Preferences) ข้อมูลหรือเฟิร์มแวร์อาจเสียหาย
- ปัญหาจริงยังอยู่ วันที่ใส่มอเตอร์แรงขึ้นหรือแบตอ่อนลง อาการจะกลับมาหนักกว่าเดิม
brownout detector เป็นสัญญาณเตือนที่มีประโยชน์ ใช้เป็นตัวทดสอบได้ด้วย: แก้วงจรแล้วสั่งมอเตอร์ออกตัวเต็มกำลังซ้ำๆ ถ้าไม่รีเซ็ตเลยแปลว่าไฟเลี้ยงพอแล้ว
ชิ้นส่วน
| ชิ้นส่วน | จำนวน | ราคาประมาณ | ร้าน |
|---|---|---|---|
| ESP32 DevKit V1 (30 ขา) | 1 | ฿130–฿250 | Shopee |
| TB6612FNG motor driver | 1 | ฿50–฿120 | Shopee |
| ชุดแชสซี 2WD มีมอเตอร์ TT 2 ตัว ล้อ 2 ล้อ และล้อ caster | 1 | ฿150–฿300 | Shopee |
| ถ่าน Li-ion 18650 | 2 | ฿60–฿150 | Shopee |
| รางถ่าน 18650 แบบ 2 ก้อน (2S) | 1 | ฿20–฿60 | Shopee |
| Buck converter 7.4 V → 5 V 3 A | 1 | ฿30–฿90 | Shopee |
| สวิตช์เปิด-ปิด | 1 | ฿5–฿20 | Shopee |
| สายจัมเปอร์ ผู้-ผู้ / ผู้-เมีย ชุด 40 เส้น | 1 | ฿30–฿60 | Shopee |
| แนะนำเพิ่ม | |||
| ที่ชาร์จถ่าน 18650 | 1 | ฿100–฿250 | Shopee |
| รวมโดยประมาณ | ฿535–฿1,200 | ||
ราคาประมาณการ ณ 2026-10-31 ยังไม่ได้ตรวจกับร้าน · บางลิงก์เป็นลิงก์ affiliate (อ่านเพิ่ม)
ตัวเก็บประจุ 100–470 µF และ 0.1 µF หาซื้อได้ตามร้านอะไหล่อิเล็กทรอนิกส์ทั่วไป ชิ้นละไม่กี่บาท
ลองในตัวจำลอง
หุ่นในตัวจำลองต่อไฟแบบแยกตามบทความนี้ไว้แล้ว เปิดหน้า Wiring เพื่อดูว่าไฟแต่ละเส้นไปที่ไหน และดูตารางกำลังไฟว่าราง 5 V กับ 3.3 V ใช้กระแสไปเท่าไร ตัวตรวจวงจรจะเตือนถ้าใช้เกินกำลังของรางนั้น