فاصله‌سنجی • HC-SR04 • ESP32 / Arduino

فاصله را بخوانیم؛ خطا را با صفر اشتباه نگیریم

در این پروژه یک فاصله‌سنج رومیزی می‌سازیم که علاوه بر عدد، معتبر بودن اندازه‌گیری را گزارش می‌کند. HC-SR04 برای یادگیری زمان‌سنجی و آزمایش فاصله تا یک هدف مناسب است؛ اما داشتن یک عدد در سریال، صحت اندازه‌گیری یا ایمنی سامانه را ثابت نمی‌کند. از اتصال امن Echo شروع می‌کنیم، زمان پالس را می‌خوانیم و سپس فیلتر ساده و مقایسه با VL53L0X را بررسی می‌کنیم.

نمای واقعی ماژول HC-SR04 با دو مبدل اولتراسونیک و چهار پایه مشخص‌شده VCC، Trig، Echo و GND
عکس واقعی نمونه HC-SR04 در راهنمای Adafruit؛ اثر Kattni Rembor با مجوز CC BY-SA 3.0. تغییر اندازه متناسب، حاشیه و تبدیل WebP؛ بدون برش یا تغییر اجزا. تصویر مشتق با همین مجوز است. عکس، تضمین نسخه ارسالی فروشگاه‌های ایران نیست.

۱. کاربرد و دلیل انتخاب برای بازار ایران

اندازه‌گیری روی میز، ثبت تغییر فاصله یک صفحه و تمرین تشخیص نزدیک‌شدن مانع، نقطه شروع‌های خوبی هستند. در بررسی امروز، ECA این مدل را موجود نشان داد؛ تجربه دارای نشان خریدار درباره کار با ماژول و مشکل خواندن صفر در نبود بازتاب نیز دیده شد. این شواهد از استفاده عملی حکایت می‌کنند، نه آمار فروش یا تضمین مشتری. صفحه همان مدل در آفتاب رایانه هم بررسی شد، ولی ناموجود بود.

این آموزش مدار ایمنی خودرو، جلوگیری تضمینی از برخورد یا کنترل خودکار پمپ نیست. نخست فقط گزارش سریال را آزمایش کنید؛ یک قرائت نامعتبر نباید فرمان حرکت یا روشن‌شدن بار ایجاد کند.

۲. فاصله چگونه از زمان به دست می‌آید؟

در رابط معمول Trig/Echo، میکروکنترلر یک پالس تحریک می‌فرستد. ماژول موج صوتی ارسال می‌کند و مدت پالس Echo نماینده زمان رفت‌وبرگشت است. رابطه آموزشی ما d = t × c / 2 است؛ تقسیم بر دو مسیر برگشت را حذف می‌کند.

با فرض سرعت ۳۴۰ متر بر ثانیه، ضریب تبدیل برابر 0.034 cm/µs می‌شود. مثلاً پالس فرضی ۱۰۰۰ میکروثانیه، در همین مدل محاسباتی ۱۷ سانتی‌متر می‌دهد. این مثال حسابی است، نه نتیجه آزمایش سخت‌افزاری. ضریب ثابت، تغییر شرایط هوا را جبران نمی‌کند.

۳. مشخصات و روش خواندن دیتاشیت

موردمرجع HC-SR04 معمولیبرداشت کاربردی
تغذیه۵ ولت DCتغذیه و سطح منطقی Echo را جدا بررسی کنید.
پالس Trigحداقل ۱۰ میکروثانیه HIGHکد یک پالس ۱۰ میکروثانیه‌ای درخواست می‌کند.
ارسال صوتهشت سیکل با فرکانس ۴۰ کیلوهرتزاین عدد با فاصله زمانی دو اندازه‌گیری یکی نیست.
محدوده معرفی‌شده۲ تا ۴۰۰ سانتی‌متربیرون این بازه در مثال معتبر حساب نمی‌شود؛ داخل بازه هم صحت تضمین نیست.
فاصله دو تحریکبیش از ۶۰ میلی‌ثانیه پیشنهاد شدهدر برنامه ۱۰۰ میلی‌ثانیه انتخاب کرده‌ایم.

منبع: دیتاشیت HC-SR04 با نام ELECFREAKS، میزبانی‌شده در SparkFun؛ همین فایل در بخش دانلود راهنمای رسمی Adafruit معرفی شده است. حدود مندرج در فایل به شرایط و هدف مناسب وابسته‌اند؛ عدد دقت تبلیغ‌شده را تضمین همه بردهای بی‌نام بازار ندانید.

اول نام و نسخه برد، سپس تغذیه، منطق ورودی/خروجی و نمودار زمانی را بخوانید. برخی بردهای جدید با ظاهر مشابه رابط‌های اضافه دارند؛ این مقاله فقط رابط Trig/Echo سازگار با HC-SR04 معمولی را آموزش می‌دهد. وجود I2C، UART یا سازگاری مستقیم با ۳٫۳ ولت را از ظاهر حدس نزنید.

۴. قطعات مورد نیاز

اتصال برق را قبل از جابه‌جایی سیم‌ها قطع کنید. اگر USB و منبع خارجی هم‌زمان وصل می‌شوند، مسیر تغذیه برد توسعه را بررسی کنید تا دو منبع به یکدیگر متصل نشوند.

۵. سیم‌کشی امن به ESP32 و Uno

پایه ماژولESP32 کلاسیک در مثالArduino Uno در مثال
VCC۵ ولت تنظیم‌شده، مطابق نسخه ماژول
GNDزمین مشترک منبع، سنسور و میکروکنترلر
TrigGPIO26D9
Echoاز تقسیم مقاومتی به GPIO27؛ اتصال مستقیم ممنوعD10 برای Uno با منطق ۵ ولت

Echo نسخه معمولی، خروجی با منطق ۵ ولت است. آن را مستقیم به ESP32 متصل نکنید. راهنمای پایه‌های Adafruit کاهش سطح Echo و پذیرش Trig با منطق ۳ یا ۵ ولت را برای نمونه خود توضیح می‌دهد. نمونه واقعی را کنترل کنید.

HC-SR04 Echo ---- 10k (1%) ----+---- GPIO27 (ESP32)
                             |
                           15k (1%)
                             |
                            GND
HC-SR04 GND ------------------+---- ESP32 GND

در این تقسیم، مقاومت ۱۰ کیلو‌اهم بین Echo و گره ورودی و مقاومت ۱۵ کیلو‌اهم بین همان گره و زمین قرار دارد. برای Echo دقیقاً ۵ ولت، خروجی محاسبه‌شده 5 × 15 / (10 + 15) = 3.0 V است. این طراحی مثال است، نه تضمین سطح همه ماژول‌ها. سطح واقعی HIGH، تلرانس مقاومت، تغذیه و لبه‌های پالس باید بررسی شوند.

در دیتاشیت ESP32، جدول DC Characteristics حداقل HIGH برابر 0.75 × VDD آمده؛ در ۳٫۳ ولت، ۲٫۴۷۵ ولت می‌شود. بنابراین صرف «کمتر از ۳٫۳ بودن» کافی نیست و ولتاژ باید از حد HIGH نیز بالاتر باشد. ولتاژ ۵ ولت ورودی مجاز فرض نمی‌شود. میانگین مولتی‌متر روی پالس، جای اندازه‌گیری دامنه با اسیلوسکوپ نیست.

شماره GPIOها انتخاب این مثال‌اند؛ برای C3، S3 یا بردی با پایه‌های مصرف‌شده باید عوض شوند. مستندات GPIO را همراه نقشه برد بخوانید. ترتیب فیزیکی پایه‌ها را از نام‌های چاپ‌شده روی برد مشخص کنید، نه از رنگ سیم.

۶. راه‌اندازی گام‌به‌گام

  1. با تغذیه قطع، پایه‌ها، زمین مشترک و تقسیم ولتاژ را کنترل کنید.
  2. برنامه خام فایل دانلودی را باز کنید و برد درست را انتخاب کنید. کتابخانه اضافی لازم نیست.
  3. Serial Monitor را روی ۱۱۵۲۰۰ قرار دهید. ابتدا فقط زمان Echo و پیام خطا را مشاهده کنید.
  4. یک صفحه صاف را روبه‌روی سنسور قرار دهید و در چند فاصله قابل‌اندازه‌گیری آزمایش کنید.
  5. هدف را بردارید یا زاویه آن را تغییر دهید؛ پیام نامعتبر باید از عدد فاصله جدا بماند.
  6. پس از تأیید سیگنال خام، برنامه اصلی با فیلتر را اجرا و دو خروجی خام و فیلترشده را مقایسه کنید.

مقادیر قبلی را هنگام خطا به‌عنوان قرائت تازه نمایش ندهید. اگر با برداشتن هدف همچنان عدد دارید، ممکن است بازتاب جسم دیگری دریافت شده باشد؛ آزمایش محیط را تغییر دهید و علت را جدا کنید.

۷. کد عملی با timeout و فیلتر میانه

کد زیر هر ۱۰۰ میلی‌ثانیه یک تلاش انجام می‌دهد. سه نمونه معتبر پیاپی برای فیلتر لازم است و هر خطا فیلتر را پاک می‌کند. این برنامه کاملاً غیرمسدودکننده نیست: pulseIn تا پایان پالس یا timeout منتظر می‌ماند. برای کار هم‌زمان حساس به زمان، باید ثبت لبه یا سخت‌افزار زمان‌سنج جداگانه طراحی شود.

#include <Arduino.h>

#if defined(ARDUINO_ARCH_ESP32)
const uint8_t TRIG_PIN = 26, ECHO_PIN = 27; // Classic ESP32 only
#else
const uint8_t TRIG_PIN = 9, ECHO_PIN = 10;   // Arduino Uno
#endif
const uint32_t PERIOD_MS = 100;     // Application choice; >60 ms between triggers
const unsigned long TIMEOUT_US = 30000;
const float SOUND_CM_PER_US = 0.0340f; // 340 m/s approximation, not compensated
float windowCm[3];
uint8_t validCount = 0, nextSlot = 0;
uint32_t lastSample = 0;
bool nearState = false;

void invalidReading(const __FlashStringHelper *reason) {
  validCount = nextSlot = 0;
  nearState = false; // Internal reset; output is UNKNOWN, not CLEAR.
  Serial.print(F("INVALID,")); Serial.println(reason);
}

float median3(float a, float b, float c) {
  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 setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  digitalWrite(TRIG_PIN, LOW);
  pinMode(ECHO_PIN, INPUT); // ESP32: external voltage divider is mandatory.
  Serial.println(F("HC-SR04: invalid does NOT mean zero distance or clear path."));
}

void loop() {
  uint32_t now = millis();
  if ((uint32_t)(now - lastSample) < PERIOD_MS) { delay(1); return; }
  lastSample = now;
  if (digitalRead(ECHO_PIN) == HIGH) { invalidReading(F("ECHO_ALREADY_HIGH")); return; }
  digitalWrite(TRIG_PIN, LOW); delayMicroseconds(3);
  digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  unsigned long us = pulseIn(ECHO_PIN, HIGH, TIMEOUT_US);
  if (us == 0) { invalidReading(F("NO_COMPLETE_ECHO")); return; }
  float cm = us * SOUND_CM_PER_US / 2.0f;
  if (cm < 2.0f || cm > 400.0f) { invalidReading(F("OUTSIDE_EXAMPLE_RANGE")); return; }
  windowCm[nextSlot] = cm;
  nextSlot = (nextSlot + 1) % 3;
  if (validCount < 3) ++validCount;
  Serial.print(F("echo_us=")); Serial.print(us);
  Serial.print(F(",raw_cm=")); Serial.print(cm, 1);
  if (validCount < 3) { Serial.println(F(",WARMING_FILTER")); return; }
  float filtered = median3(windowCm[0], windowCm[1], windowCm[2]);
  if (filtered < 30.0f) nearState = true;
  else if (filtered > 35.0f) nearState = false;
  Serial.print(F(",median_cm=")); Serial.print(filtered, 1);
  Serial.println(nearState ? F(",NEAR") : F(",NOT_NEAR"));
  // Educational indicator only: no safety, braking or automatic pump control.
}

دانلود برنامه اصلی، برنامه خام و راهنمای اتصال. هر فایل ino را در پوشه هم‌نام خودش قرار دهید. آزمون این بسته در حد کامپایل نرم‌افزاری است؛ روی سنسور فیزیکی آزمایش نشده است.

۸. تحلیل کد و معنی وضعیت‌ها

طبق مستندات Arduino برای pulseIn، زمان پالس بر حسب میکروثانیه بازگردانده می‌شود و timeout به‌صورت صریح قابل تنظیم است. ما ۳۰٬۰۰۰ میکروثانیه انتخاب کرده‌ایم؛ این یک حد انتظار نرم‌افزاری است، نه مشخصه تضمینی سنسور.

فیلتر میانه از سه مقدار، مقدار وسط را انتخاب می‌کند و می‌تواند یک نمونه پرت منفرد را کم‌اثر کند؛ خطای ثابت، هدف نامناسب و سیم‌بندی اشتباه را درمان نمی‌کند. آستانه‌های ۳۰ و ۳۵ سانتی‌متر عمداً متفاوت‌اند تا در مرز تصمیم نوسان کمتری ایجاد شود. این فاصله‌ها انتخاب آموزشی‌اند و باید برای پروژه واقعی آزموده شوند. پس از خطا، خروجی معتبر قبلی حفظ نمی‌شود؛ برنامه دوباره سه نمونه معتبر می‌خواهد.

۹. آزمون دقت، تکرارپذیری و تأثیر دما

برای یک آزمون پیشنهادی، در فاصله‌های ۲۰، ۵۰ و ۱۰۰ سانتی‌متر از یک مبنای ثابت، در هر نقطه ۱۰ قرائت ثبت کنید. عدد مرجع، حداقل، حداکثر و تعداد خطاها را کنار هم بنویسید. این فاصله‌ها و تعداد تکرار، برنامه آزمایش پیشنهادی‌اند؛ هیچ نتیجه‌ای از پیش برای آن‌ها ادعا نمی‌کنیم.

اگر همه اعداد نزدیک هم ولی دور از مرجع‌اند، تکرارپذیری خوب لزوماً به معنی دقت خوب نیست. خطای مبدا، هندسه نصب و ضریب تبدیل را بررسی کنید. در مقابل، پراکندگی زیاد با عوض‌شدن زاویه هدف را با یک ضریب کالیبراسیون ثابت پنهان نکنید.

سرعت صوت با دما تغییر می‌کند. راهنمای Adafruit درباره سرعت صوت نمونه جبران وابسته به دما دارد. کد فعلی عمداً با فرض ثابت ۳۴۰ متر بر ثانیه کار می‌کند؛ اگر دقت بیشتری لازم است، ابتدا دمای نماینده مسیر صوت را بسنجید و روش جبران را جدا اعتبارسنجی کنید. برای شروع خواندن دما، آموزش DS18B20 در دسترس است.

۱۰. خطاهای رایج و عیب‌یابی

نشانهبررسی عملی
همیشه نامعتبرزمین مشترک، پایه‌های Trig/Echo، سطح ورودی بعد از تقسیم و هدف آزمایش را کنترل کنید.
فاصله با برداشتن هدف صفر می‌شودکدی که صفر تابع را به فاصله تبدیل می‌کند اصلاح کنید؛ صفر تابع یعنی قرائت معتبر نداریم.
عدد با تغییر زاویه می‌پردآزمون را با هدف صاف و روبه‌رو تکرار کنید؛ بازتاب جانبی را بررسی کنید.
با اضافه‌شدن موتور رفتار عوض می‌شودنخست موتور را از آزمایش حذف و تغذیه و زمین را بررسی کنید؛ متوسط‌گیری جای رفع علت نیست.
چند سنسور نتیجه نامطمئن می‌دهندتنها یکی را فعال کنید و سپس زمان‌بندی نوبتی را با آزمون واقعی توسعه دهید.
Echo از ابتدا HIGH استسیم‌بندی و نسخه برد را کنترل کنید؛ در صورت نیاز، با قطع امن تغذیه آزمون را از نو شروع کنید.

برای دیدن پالس Trig و Echo از اسیلوسکوپ یا ورودی تحلیلگر منطقیِ سازگار با همان سطح ولتاژ استفاده کنید. واردکردن ۵ ولت به ورودی ابزار ۳٫۳ ولتی هم مجاز فرض نمی‌شود.

۱۱. HC-SR04 یا VL53L0X؟

معیارHC-SR04 معمولیVL53L0X
اصل سنجشرفت‌وبرگشت صوتزمان پرواز نور؛ فرستنده ۹۴۰ نانومتر
رابط این مقایسهTrig/Echo و زمان‌سنجی پالسI2C و خواندن نتیجه پردازش‌شده
نکته اتصالبرای ESP32 سطح Echo باید سازگار شود.تغذیه و مبدل سطح روی برد واسط بررسی شود؛ تراشه خام با ماژول یکی نیست.
روش تصمیمبا هدف و محیط واقعی خودتان بیازمایید.برای همان هدف، نتیجه و وضعیت خطا را کنار آزمایش اول بگذارید.

مرجع ویژگی‌های VL53L0X، صفحه رسمی ST است. برای سیم‌کشی و کد آن، آموزش مستقل VL53L0X را ببینید. صرف مقایسه حداکثر برد اسمی، برنده همه کاربردها را تعیین نمی‌کند. ابتدا اندازه هدف، محیط، فاصله مورد نیاز و رفتار هنگام خطا را مشخص کنید.

۱۲. نکات طراحی و توسعه

برد را محکم نصب کنید و جلوی دو مبدل را نپوشانید. شکل هدف و محل نصب باید بخشی از برنامه آزمون باشند. برد معمولی را برای زیر آب یا محیط خیس مناسب فرض نکنید؛ برای سطح مخزن، حفاظت محیطی و محدودیت کاربرد باید جداگانه تأیید شود. در پروژه چندحسگری، تداخل را با فعال‌کردن نوبتی و ثبت نتایج بررسی کنید، نه با فرض اینکه همه پالس‌ها مستقل‌اند.

اگر گزارش را با BLE می‌فرستید، علاوه بر فاصله، معتبر بودن و زمان آخرین اندازه‌گیری را نیز ارسال کنید؛ آموزش پروژه‌های مقدماتی BLE شروع مناسبی است. برای تشخیص صرف حرکت، PIR مسئله متفاوتی را حل می‌کند و خروجی آن جای فاصله نیست.

۱۳. خرید در ایران؛ بررسی ۱۹ شهریور ۱۴۰۵

وضعیت زیر در ۱۰ سپتامبر ۲۰۲۶ / ۱۹ شهریور ۱۴۰۵ بررسی شد و تضمین موجودی آینده نیست. قیمت ثابت درج نمی‌کنیم. هر دو لینک به صفحه HC-SR04 هستند؛ نسخه دقیق برد ارسالی را پیش از سفارش تأیید کنید.

در بازار، چینش قطعات پشت برد و قابلیت‌های نسخه‌ها تغییر می‌کند. نام HC-SR04 به‌تنهایی تضمین نمی‌کند تصویر، ولتاژ یا رابط‌های اضافی تمام فروشندگان یکسان باشد. لینک US-100، SRF05 یا مدل ضدآب را به جای این محصول معرفی نکرده‌ایم. منابع فروشگاهی فقط برای وضعیت خرید و شواهد بازار استفاده شده‌اند.

۱۴. پرسش‌های متداول

آیا Echo را مستقیم به ESP32 وصل کنم؟

برای HC-SR04 معمولی خیر؛ Echo با منطق ۵ ولت است و باید با تقسیم ولتاژ یا مبدل مناسب به سطح سازگار تبدیل شود.

آیا صفر شدن pulseIn یعنی فاصله صفر است؟

خیر. در این برنامه صفر تابع یعنی پالس کامل در زمان انتظار دریافت نشده و قرائت نامعتبر است، نه فاصله صفر یا مسیر خالی.

آیا کد کاملاً غیرمسدودکننده است؟

خیر. برنامه فاصله زمانی نمونه‌ها را کنترل می‌کند، اما pulseIn هنگام انتظار برای پالس می‌تواند اجرای حلقه را تا timeout متوقف کند.

آیا فیلتر میانه دقت قطعی ایجاد می‌کند؟

خیر. فیلتر می‌تواند اثر یک نمونه پرت را کاهش دهد، ولی خطای ثابت، هندسه نامناسب و اتصال اشتباه را اصلاح نمی‌کند.

آیا HC-SR04 همیشه از VL53L0X بهتر است؟

خیر. اصل سنجش و رابط این دو متفاوت است؛ انتخاب باید با هدف، محیط و آزمون خطاهای پروژه انجام شود، نه فقط حداکثر برد اسمی.

۱۵. جمع‌بندی و منابع اصلی

فاصله‌سنج مفید فقط عدد تولید نمی‌کند؛ باید هنگام نبود داده معتبر هم رفتار روشنی داشته باشد. ابتدا سطح Echo و زمان خام را بررسی کنید، سپس فیلتر و تصمیم‌گیری را اضافه کنید. در مسیر فاصله و سطح و راهنمای سنسورها می‌توانید موضوع‌های مرتبط را ادامه دهید.

متن و مثال آموزشی: LCENJ. کد برای کامپایل روی ESP32 کلاسیک و Arduino Uno بررسی می‌شود؛ آزمایش سخت‌افزاری انجام نشده و نتیجه اندازه‌گیری واقعی ادعا نشده است.

برای یک مسیر منظم از مبانی تا انتخاب و آزمون حسگر، دوره سنسورها در ۷ قدم را دنبال کنید.