ไฟช่วยจอดรถในโรงรถด้วย ESP32 + HC-SR04 ไฟเขียว เหลือง แดง

ทำไฟช่วยจอดรถติดผนังโรงรถด้วย ESP32 HC-SR04 และไฟ LED WS2812B เปลี่ยนสีตามระยะ ตั้งจุดจอดด้วยปุ่มกดค้าง จำค่าไว้แม้ไฟดับ และปิดไฟเองเมื่อรถจอดนิ่ง ไม่ต้องเจาะกันชนรถ

เขียนเมื่อ

ติด HC-SR04 กับไฟ LED เส้นสั้นๆ ไว้ที่ผนังด้านหน้ารถ ESP32 วัดระยะทุกครึ่งวินาทีแล้วเปลี่ยนสีไฟ: เขียว ยังเข้าได้อีก เหลือง ใกล้แล้ว ชะลอ แดง หยุด และแดงกะพริบ เลยจุดแล้ว ถอยหน่อย คนขับเห็นไฟผ่านกระจกหน้า ไม่ต้องลงมาดูหรือแขวนลูกเทนนิสจากเพดาน ชิ้นส่วนรวมราว ฿320–650 ใกล้กับชุดเซนเซอร์ถอยจอด แต่ไม่ต้องเจาะกันชนรถ และไฟเส้นที่เหลือเอาไปใช้ต่อได้

ซื้อหรือทำเอง

ซื้อสำเร็จ: ชุดเซนเซอร์ถอยจอด 4 ตัว ส่งเสียงเตือนเมื่อใกล้สิ่งกีดขวาง ราคาประมาณ ฿350–800 ติดที่กันชนรถ

ทำเอง: ใช้ของ 6 อย่าง รวมราว ฿320–650 (รายการพร้อมลิงก์อยู่ในหัวข้อชิ้นส่วนด้านล่าง) ติดที่ผนังโรงรถ ไม่ต้องแตะตัวรถเลย

โปรเจกต์นี้เป็นที่นิยมในต่างประเทศในชื่อ garage parking assistant เพราะทำเสร็จได้ในวันเดียว

ชิ้นส่วน

ชิ้นส่วนจำนวนราคาประมาณร้าน
ESP32 DevKit V1 (30 ขา)1฿130–฿250Shopee
Ultrasonic HC-SR041฿30–฿60Shopee
ตัวต้านทาน 1 kΩ + 2 kΩ (แบ่งแรงดัน 5 V → 3.3 V)1฿2–฿10Shopee
ไฟเส้น WS2812B 1 m 60 ดวง (5 V)1฿120–฿250—
ปุ่มกด tactile 12 mm + ฝาครอบ1฿5–฿15Shopee
สายจัมเปอร์ ผู้-ผู้ / ผู้-เมีย ชุด 40 เส้น1฿30–฿60Shopee
รวมโดยประมาณ฿317–฿645

ราคาประมาณการ ณ 2026-10-31 ยังไม่ได้ตรวจกับร้าน · บางลิงก์เป็นลิงก์ affiliate (อ่านเพิ่ม)

ไฟเส้น 1 m มี 60 ดวง ตัดใช้แค่ 10 ดวงตรงรอยตัดบนเส้น ส่วนที่เหลือเก็บไว้ทำโปรเจกต์อื่น ไฟเลี้ยงใช้อะแดปเตอร์ USB 5 V 1–2 A ตัวไหนก็ได้

ต่อสาย

ชิ้นส่วนขาต่อกับ
HC-SR04VCC5 V จากอะแดปเตอร์
TRIGGPIO 26
ECHOGPIO 34 ผ่านตัวต้านทาน 1 kΩ / 2 kΩ (ECHO ส่ง 5 V ขา ESP32 รับได้ 3.3 V)
GNDGND
ไฟ WS2812B5V5 V จากอะแดปเตอร์
DINGPIO 25 ผ่านตัวต้านทาน 330 Ω
GNDGND
ปุ่มตั้งจุดจอดสองขาGPIO 27 กับ GND
ESP325V (VIN)5 V จากอะแดปเตอร์
อะแดปเตอร์ 5 V ──┬──▶ 5V ของ ESP32
                 ├──▶ VCC ของ HC-SR04
                 └──▶ 5V ของไฟ WS2812B
GND ของทุกชิ้นต่อถึงกัน

ติดตั้งที่ผนัง

โค้ด (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);
}

ตั้งจุดจอด

  1. ขับรถเข้าไปจอดตรงตำแหน่งที่ต้องการ (เหลือที่เดินหน้ารถ ปิดประตูโรงรถได้)
  2. กดปุ่มค้าง 2 วินาที ไฟกะพริบสีน้ำเงิน 3 ครั้ง แปลว่าบันทึกแล้ว
  3. ถอยรถออกแล้วลองเข้าใหม่ ไฟควรเป็นแดงพอดีตอนรถอยู่ตำแหน่งเดิม ถ้าอยากให้เตือนเร็วขึ้น เพิ่มค่า SLOW_CM

ค่าที่บันทึกด้วย Preferences อยู่ใน flash ของ ESP32 ไฟดับหรือถอดปลั๊กก็ไม่หาย ไม่ต้องตั้งใหม่

ปัญหาที่พบบ่อย

ลองในตัวจำลอง

หุ่นในตัวจำลองมี HC-SR04 ตัวเดียวกัน ลากกล่องเข้าหาหุ่นทีละนิดในหน้า World แล้วดูค่าระยะที่อ่านได้ จะเห็นว่าค่าเปลี่ยนอย่างไรเมื่อวัตถุเฉียงหรืออยู่นอกกรวยของเซนเซอร์ ซึ่งเป็นเรื่องเดียวกับตอนติดตั้งในโรงรถ

ลองวัดระยะด้วย HC-SR04 ในตัวจำลอง →

อยากเปลี่ยนไฟเส้นเป็นจอ ดู ต่อจอ OLED SSD1306 กับ ESP32 และแยกกดสั้นกับกดค้างให้ปุ่มทำได้หลายอย่างด้วย ต่อปุ่มกดกับ ESP32