ไฟช่วยจอดรถในโรงรถด้วย ESP32 + HC-SR04 ไฟเขียว เหลือง แดง
ทำไฟช่วยจอดรถติดผนังโรงรถด้วย ESP32 HC-SR04 และไฟ LED WS2812B เปลี่ยนสีตามระยะ ตั้งจุดจอดด้วยปุ่มกดค้าง จำค่าไว้แม้ไฟดับ และปิดไฟเองเมื่อรถจอดนิ่ง ไม่ต้องเจาะกันชนรถ
ติด HC-SR04 กับไฟ LED เส้นสั้นๆ ไว้ที่ผนังด้านหน้ารถ ESP32 วัดระยะทุกครึ่งวินาทีแล้วเปลี่ยนสีไฟ: เขียว ยังเข้าได้อีก เหลือง ใกล้แล้ว ชะลอ แดง หยุด และแดงกะพริบ เลยจุดแล้ว ถอยหน่อย คนขับเห็นไฟผ่านกระจกหน้า ไม่ต้องลงมาดูหรือแขวนลูกเทนนิสจากเพดาน ชิ้นส่วนรวมราว ฿320–650 ใกล้กับชุดเซนเซอร์ถอยจอด แต่ไม่ต้องเจาะกันชนรถ และไฟเส้นที่เหลือเอาไปใช้ต่อได้
ซื้อหรือทำเอง
ซื้อสำเร็จ: ชุดเซนเซอร์ถอยจอด 4 ตัว ส่งเสียงเตือนเมื่อใกล้สิ่งกีดขวาง ราคาประมาณ ฿350–800 ติดที่กันชนรถ
ทำเอง: ใช้ของ 6 อย่าง รวมราว ฿320–650 (รายการพร้อมลิงก์อยู่ในหัวข้อชิ้นส่วนด้านล่าง) ติดที่ผนังโรงรถ ไม่ต้องแตะตัวรถเลย
- บอร์ด ESP32 DevKit: วัดระยะและเลือกสีไฟ
- HC-SR04 พร้อมตัวต้านทานแบ่งแรงดัน: วัดระยะถึงรถ
- ไฟเส้น WS2812B: ใช้ 10 ดวง แสดงสีเขียว เหลือง แดง
- ปุ่มกด: ตั้งจุดจอด
- สายจัมเปอร์ และอะแดปเตอร์ USB 5 V 1–2 A
โปรเจกต์นี้เป็นที่นิยมในต่างประเทศในชื่อ garage parking assistant เพราะทำเสร็จได้ในวันเดียว
ชิ้นส่วน
| ชิ้นส่วน | จำนวน | ราคาประมาณ | ร้าน |
|---|---|---|---|
| ESP32 DevKit V1 (30 ขา) | 1 | ฿130–฿250 | Shopee |
| Ultrasonic HC-SR04 | 1 | ฿30–฿60 | Shopee |
| ตัวต้านทาน 1 kΩ + 2 kΩ (แบ่งแรงดัน 5 V → 3.3 V) | 1 | ฿2–฿10 | Shopee |
| ไฟเส้น WS2812B 1 m 60 ดวง (5 V) | 1 | ฿120–฿250 | — |
| ปุ่มกด tactile 12 mm + ฝาครอบ | 1 | ฿5–฿15 | Shopee |
| สายจัมเปอร์ ผู้-ผู้ / ผู้-เมีย ชุด 40 เส้น | 1 | ฿30–฿60 | Shopee |
| รวมโดยประมาณ | ฿317–฿645 | ||
ราคาประมาณการ ณ 2026-10-31 ยังไม่ได้ตรวจกับร้าน · บางลิงก์เป็นลิงก์ affiliate (อ่านเพิ่ม)
ไฟเส้น 1 m มี 60 ดวง ตัดใช้แค่ 10 ดวงตรงรอยตัดบนเส้น ส่วนที่เหลือเก็บไว้ทำโปรเจกต์อื่น ไฟเลี้ยงใช้อะแดปเตอร์ USB 5 V 1–2 A ตัวไหนก็ได้
ต่อสาย
| ชิ้นส่วน | ขา | ต่อกับ |
|---|---|---|
| HC-SR04 | VCC | 5 V จากอะแดปเตอร์ |
TRIG | GPIO 26 | |
ECHO | GPIO 34 ผ่านตัวต้านทาน 1 kΩ / 2 kΩ (ECHO ส่ง 5 V ขา ESP32 รับได้ 3.3 V) | |
GND | GND | |
| ไฟ WS2812B | 5V | 5 V จากอะแดปเตอร์ |
DIN | GPIO 25 ผ่านตัวต้านทาน 330 Ω | |
GND | GND | |
| ปุ่มตั้งจุดจอด | สองขา | GPIO 27 กับ GND |
| ESP32 | 5V (VIN) | 5 V จากอะแดปเตอร์ |
อะแดปเตอร์ 5 V ──┬──▶ 5V ของ ESP32
├──▶ VCC ของ HC-SR04
└──▶ 5V ของไฟ WS2812B
GND ของทุกชิ้นต่อถึงกัน
- ต่อไฟเส้นกับอะแดปเตอร์โดยตรง อย่าดึงไฟให้ LED ผ่านบอร์ด ESP32 LED หนึ่งดวงกินได้ถึงราว 60 mA ตอนขาวสุด โค้ดนี้ตั้งความสว่างไว้ต่ำ ใช้จริงไม่ถึง 200 mA
- สัญญาณ 3.3 V กับไฟเส้น 5 V WS2812B ส่วนใหญ่รับสัญญาณ 3.3 V จาก ESP32 ได้ถ้าสาย DIN สั้น ถ้าไฟกะพริบมั่วหรือสีเพี้ยน ให้ใส่ชิปแปลงระดับ 74AHCT125 ที่ขา DIN บอร์ด level shifter แบบ MOSFET ที่ใช้กับ I²C อาจช้าเกินไปสำหรับสัญญาณของไฟเส้น
- แบ่งแรงดันขา ECHO วิธีต่อละเอียดอยู่ใน ต่อ HC-SR04 กับ ESP32 ให้ถูก
ติดตั้งที่ผนัง
- ติด HC-SR04 สูงประมาณระดับกันชนหน้า (40–60 cm จากพื้น) หันตรงไปทางรถ เสียงต้องกระทบผิวที่ค่อนข้างเรียบ เช่น กันชนหรือป้ายทะเบียน
- ติดไฟ LED สูงระดับสายตาคนขับ หรือบนผนังที่มองเห็นผ่านกระจกหน้า
- HC-SR04 วัดได้ไกลราว 4 m และมองเป็นกรวยแคบราว 15° ถ้ามีของวางระหว่างเซนเซอร์กับรถ เช่น ถังขยะ ค่าจะผิด
- โรงรถที่ฝุ่นเยอะหรือโดนฝน ให้ใส่กล่องแต่เปิดรูให้ตัวส่งและตัวรับเสียงโผล่ออกมา ถ้าโดนน้ำบ่อยให้เปลี่ยนเป็นรุ่นกันน้ำ JSN-SR04T
โค้ด (Arduino IDE)
ติดตั้งไลบรารี Adafruit NeoPixel จาก Library Manager ส่วน Preferences มากับบอร์ด ESP32 อยู่แล้ว ใช้เก็บระยะจอดลง flash
#include <Adafruit_NeoPixel.h>
#include <Preferences.h>
#include <algorithm>
const int TRIG = 26, ECHO = 34; // ECHO ผ่านตัวต้านทาน 1 kΩ / 2 kΩ
const int LED_PIN = 25, BUTTON = 27, LEDS = 10;
const float SLOW_CM = 60; // เหลือง: อีกไม่ถึง 60 cm จะถึงจุดจอด
const float RANGE_CM = 200; // เริ่มเปิดไฟเมื่อรถอยู่ห่างจากจุดจอดไม่เกิน 2 m
const float TOO_CLOSE_CM = 10; // เลยจุดจอดเกิน 10 cm: แดงกะพริบ
const unsigned long IDLE_OFF_MS = 30000; // รถนิ่ง 30 วินาที: ปิดไฟ
Adafruit_NeoPixel strip(LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
Preferences prefs;
float stopCm = 80; // ระยะจากผนังที่ต้องหยุด ตั้งใหม่ด้วยปุ่ม
/* ---------- วัดระยะ ---------- */
float readCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned long us = pulseIn(ECHO, HIGH, 30000); // รอไม่เกิน 30 ms (ราว 5 m)
return us ? us / 58.0 : NAN;
}
// ค่ากลางจาก 5 ครั้ง: ค่าที่กระโดดเพราะเสียงสะท้อนผิดทางจะถูกตัดทิ้ง
float distanceCm() {
float v[5];
int n = 0;
for (int i = 0; i < 5; i++) {
float d = readCm();
if (!isnan(d)) v[n++] = d;
delay(20); // รอเสียงสะท้อนรอบก่อนจางไป
}
if (n == 0) return NAN;
std::sort(v, v + n);
return v[n / 2];
}
/* ---------- ไฟ ---------- */
void fill(uint32_t color, int count) {
strip.clear();
for (int i = 0; i < count; i++) strip.setPixelColor(i, color);
strip.show();
}
void showDistance(float d) {
float left = d - stopCm; // ระยะที่ยังเข้าได้อีก (ติดลบ = เลยแล้ว)
if (isnan(d) || left > RANGE_CM) { fill(0, 0); return; } // ไม่มีรถ หรือยังไกล
if (left < -TOO_CLOSE_CM) { // เลยจุดจอด: แดงกะพริบ
bool on = (millis() / 250) % 2;
fill(on ? strip.Color(255, 0, 0) : 0, LEDS);
return;
}
if (left <= 0) { fill(strip.Color(255, 0, 0), LEDS); return; } // หยุด
if (left < SLOW_CM) { fill(strip.Color(255, 160, 0), LEDS); return; } // ชะลอ
int lit = map(long(left), long(RANGE_CM), long(SLOW_CM), 1, LEDS); // เขียว ยิ่งใกล้ยิ่งยาว
fill(strip.Color(0, 255, 0), constrain(lit, 1, LEDS));
}
/* ---------- โปรแกรมหลัก ---------- */
void setup() {
Serial.begin(115200);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(BUTTON, INPUT_PULLUP);
strip.begin();
strip.setBrightness(60); // 0–255: สว่างพอเห็นในโรงรถ ไม่แสบตา
prefs.begin("parking", false);
stopCm = prefs.getFloat("stop", stopCm); // ค่าที่บันทึกไว้ ยังอยู่แม้ไฟดับ
}
void loop() {
static unsigned long lastMeasure = 0, stillSince = 0, heldSince = 0;
static float d = NAN, lastMoving = NAN;
// กดปุ่มค้าง 2 วินาทีตอนรถจอดตรงจุดที่ต้องการ: บันทึกระยะนี้เป็นจุดจอด
if (digitalRead(BUTTON) == LOW) {
if (!heldSince) heldSince = millis();
if (millis() - heldSince > 2000 && !isnan(d)) {
stopCm = d;
prefs.putFloat("stop", stopCm);
for (int i = 0; i < 3; i++) { fill(strip.Color(0, 0, 255), LEDS); delay(150); fill(0, 0); delay(150); }
heldSince = 0;
while (digitalRead(BUTTON) == LOW) delay(10); // รอปล่อยปุ่ม
}
} else {
heldSince = 0;
}
if (millis() - lastMeasure < 500) return; // วัดวินาทีละ 2 ครั้ง
lastMeasure = millis();
d = distanceCm();
Serial.printf("distance %.0f cm stop %.0f cm\n", d, stopCm);
// ระยะเปลี่ยนเกิน 3 cm = รถยังขยับ
if (isnan(lastMoving) || isnan(d) || fabs(d - lastMoving) > 3) { lastMoving = d; stillSince = millis(); }
if (millis() - stillSince > IDLE_OFF_MS) fill(0, 0); // จอดนิ่งแล้ว ปิดไฟ
else showDistance(d);
}
ตั้งจุดจอด
- ขับรถเข้าไปจอดตรงตำแหน่งที่ต้องการ (เหลือที่เดินหน้ารถ ปิดประตูโรงรถได้)
- กดปุ่มค้าง 2 วินาที ไฟกะพริบสีน้ำเงิน 3 ครั้ง แปลว่าบันทึกแล้ว
- ถอยรถออกแล้วลองเข้าใหม่ ไฟควรเป็นแดงพอดีตอนรถอยู่ตำแหน่งเดิม ถ้าอยากให้เตือนเร็วขึ้น เพิ่มค่า
SLOW_CM
ค่าที่บันทึกด้วย Preferences อยู่ใน flash ของ ESP32 ไฟดับหรือถอดปลั๊กก็ไม่หาย ไม่ต้องตั้งใหม่
ปัญหาที่พบบ่อย
- ไฟกะพริบสลับสีตอนรถอยู่ไกล เสียงสะท้อนจากพื้นหรือผนังด้านข้าง ยกเซนเซอร์ให้สูงขึ้นเล็กน้อยและหันให้ตรง หรือลด
RANGE_CM - ระยะอ่านได้ 0 หรือไม่มีค่า เช็กตัวต้านทานแบ่งแรงดันที่ขา ECHO และไฟ 5 V ของเซนเซอร์
- LED ไม่ติดหรือสีมั่ว ต่อสายเข้าฝั่ง
DINไม่ใช่DOUT(ดูลูกศรบนเส้นไฟ) GND ของไฟเส้นต้องต่อกับ GND ของ ESP32 - ไฟไม่ดับแม้รถจอดนิ่ง พัดลมหรือของที่แกว่งอยู่หน้าเซนเซอร์ทำให้ระยะเปลี่ยน เพิ่มค่า 3 cm ในเงื่อนไข
fabs(d - lastMoving)
ลองในตัวจำลอง
หุ่นในตัวจำลองมี HC-SR04 ตัวเดียวกัน ลากกล่องเข้าหาหุ่นทีละนิดในหน้า World แล้วดูค่าระยะที่อ่านได้ จะเห็นว่าค่าเปลี่ยนอย่างไรเมื่อวัตถุเฉียงหรืออยู่นอกกรวยของเซนเซอร์ ซึ่งเป็นเรื่องเดียวกับตอนติดตั้งในโรงรถ
ลองวัดระยะด้วย HC-SR04 ในตัวจำลอง →
อยากเปลี่ยนไฟเส้นเป็นจอ ดู ต่อจอ OLED SSD1306 กับ ESP32 และแยกกดสั้นกับกดค้างให้ปุ่มทำได้หลายอย่างด้วย ต่อปุ่มกดกับ ESP32