Руководства · 11 мин чтения

Радар на Arduino: HC-SR04, сервопривод SG90 и экран в Processing

Радар на Arduino шаг за шагом: подключение HC-SR04 и сервопривода SG90, код угла и расстояния, зелёный экран радара в Processing, мини-радар на OLED и частые ошибки.

Радар на Arduino — это проект, в котором ультразвуковой датчик расстояния HC-SR04 закрепляют на сервоприводе SG90 и поворачивают от 0 до 180 градусов, чтобы измерять и направление, и расстояние до ближайших предметов, а результат показывают на компьютере в виде зелёного экрана радара, как в кино. Под каждым углом Arduino делает измерение и отправляет по последовательному порту строку «угол,расстояние»; небольшая программа на Processing, запущенная на компьютере, читает эти числа и рисует вращающуюся линию развёртки, а найденные предметы — красными линиями.

В этом руководстве подробно разобран каждый шаг: от списка деталей и схемы подключения до кода Arduino и экрана радара в Processing. Мы также разберём мини-радар на OLED-дисплее, которому не нужен компьютер, версии для ESP32 и Raspberry Pi Pico, настройку скорости развёртки и точности измерений и решение самых частых ошибок последовательного порта. Проект дешёвый, собирается за полдня и входит в число проектов на Arduino, которые больше всего привлекают внимание на школьных презентациях.

Arduino Uno
Arduino Uno
HC-SR04
HC-SR04
Сервопривод SG90
Сервопривод SG90
Макетная плата
Макетная плата

Как работает радар на Arduino?

Сердце системы — HC-SR04. Один из двух цилиндров на датчике (T) посылает короткую пачку звука частотой 40 kHz, которую человек не слышит; когда звук ударяется о предмет и отражается, второй цилиндр (R) принимает эхо. Arduino измеряет время этого пути туда и обратно в микросекундах. Звук распространяется в воздухе со скоростью около 343 м/с, поэтому на один сантиметр ему нужно около 29 микросекунд; так как путь проходится дважды, туда и обратно, формула принимает вид расстояние (см) = время (µs) / 58. Сервопривод поворачивает датчик шаг за шагом, и на каждом шаге измерение повторяется. В итоге получается «под этим углом, на таком-то расстоянии в сантиметрах что-то есть», то есть полярная координата. Чтобы нарисовать её на экране, угол и расстояние переводятся в положение пикселя по формулам x = расстояние × cos(угол) и y = расстояние × sin(угол).

ДетальЗадачаОсновные параметры
HC-SR04Ультразвуковое измерение расстояния40 kHz, 2–400 см, угол измерения около 15°, 5 V, 15 mA
Сервопривод SG90Поворачивает датчик на 0–180°0,1 с/60° (4,8 V), момент 1,8 кг·см, 4,8–6 V, 9 г
Arduino UnoИзмеряет, управляет сервоприводом, отправляет данные16 MHz, логический уровень 5 V, последовательный порт по USB
ProcessingРисует экран радара на компьютереБесплатный, на основе Java, библиотека Serial в комплекте
OLED SSD1306 (необязательно)Экран мини-радара без компьютера128×64 пикселя, I2C, адрес 0x3C

Список деталей для радара на Arduino

  • Arduino Uno или Nano и USB-кабель с передачей данных (кабели только для зарядки не появляются на компьютере как порт).
  • Ультразвуковой датчик расстояния HC-SR04.
  • Микросервопривод SG90 и пластиковые качалки, которые лежат с ним в пакете.
  • Макетная плата и 8–10 перемычек «папа–папа» и «папа–мама».
  • Электролитический конденсатор на 470 µF (не меньше 10 V): он не даёт напряжению питания проседать, когда сервопривод движется.
  • Двусторонний скотч, термоклей или небольшой кронштейн, напечатанный на 3D-принтере, чтобы закрепить датчик на сервоприводе.
  • По желанию: I2C OLED-дисплей 0,96 дюйма (для версии без компьютера) и внешний адаптер 5 V 2 A.

Схема подключения радара на Arduino

ПодключениеArduino UnoESP32Raspberry Pi Pico
HC-SR04 VCC5VVIN (5 V)VBUS (пин 40)
HC-SR04 GNDGNDGNDGND
HC-SR04 TrigD10GPIO 26GP14
HC-SR04 EchoD11GPIO 27 (через делитель)GP13 (через делитель)
SG90 коричневый (GND)GNDGNDGND
SG90 красный (+5 V)5VVIN (5 V)VBUS (пин 40)
SG90 оранжевый (сигнал)D9GPIO 13GP15

На Uno монтаж получается аккуратнее, если провода 5 V и GND датчика и сервопривода подключить к шинам «плюс» и «минус» макетной платы, а сами шины — к пинам 5V и GND Arduino. Вставь конденсатор 470 µF в те же шины: длинную ножку (+) на 5 V, а короткую, отмеченную полосой на корпусе, на GND. У некоторых сервоприводов провода чёрный, красный и белый; тогда чёрный — это GND, а белый — сигнал. Чтобы перепроверить расположение пинов на своей плате, воспользуйся утилитой распиновки.

Когда HC-SR04 питается от 5 V, его пин Echo тоже выдаёт 5 V. Для Arduino Uno это нормально, но пины ESP32 и Raspberry Pi Pico не выдерживают 5 V. Поставь на линию Echo делитель напряжения из резисторов 1 kΩ и 2 kΩ (Echo → 1 kΩ → GPIO, GPIO → 2 kΩ → GND); напряжение на пине упадёт примерно до 3,3 V. Номиналы можно проверить в калькуляторе делителя напряжения.

Крепление датчика на сервоприводе

Микросервопривод SG90
Сервопривод SG90: коричневый провод — GND, красный — +5 V, оранжевый — сигнал. HC-SR04 приклеен к пластиковой качалке сервопривода.

Прежде чем надеть качалку, выставь сервопривод на 90 градусов: просто загрузи короткий тестовый скетч с radarServo.write(90) и оставь сервопривод в этом положении. Затем надень качалку так, чтобы датчик смотрел прямо вперёд. Тогда 0° указывает вправо, 90° — прямо вперёд, а 180° — влево, и направления на экране Processing точно совпадают с реальными. Когда приклеиваешь HC-SR04 к качалке двусторонним скотчем или термоклеем, следи, чтобы оба цилиндра были параллельны земле: если датчик наклонён вниз, он примет поверхность стола за предмет. Оставь проводам достаточный запас, чтобы они не натягивались при повороте на 180 градусов, и закрепи сервопривод на тяжёлом основании или в коробке: корпус, который трясётся на каждом шаге, портит измерения.

Сборка радара на Arduino шаг за шагом

  1. Подключи детали по таблице выше, не забудь конденсатор и закрепи датчик на сервоприводе.
  2. Открой Arduino IDE; библиотека Servo входит в комплект IDE, так что дополнительно ничего устанавливать не нужно.
  3. Загрузи код радара, приведённый ниже. Если не получается выбрать плату или порт, загляни в статью Код не загружается в Arduino.
  4. Открой монитор порта на скорости 9600 бод; если бегут строки угла и расстояния вроде «30,45», со стороны Arduino всё готово. После этого обязательно закрой монитор порта.
  5. Установи на компьютер Processing 4, открой новый скетч и вставь код экрана радара.
  6. Нажми «Run» (запуск): в консоли внизу появится список портов, и откроется окно радара. Если провести рукой перед датчиком, должны появиться красные линии.

Код радара для Arduino

C++ (Arduino IDE)
1#include <Servo.h>
2
3const byte SERVO_PIN  = 9;     // SG90 turuncu kablo / SG90 orange wire
4const byte TRIG_PIN   = 10;    // HC-SR04 Trig
5const byte ECHO_PIN   = 11;    // HC-SR04 Echo
6const int  MIN_ANGLE  = 0;     // tarama başlangıcı / sweep start
7const int  MAX_ANGLE  = 180;   // tarama sonu / sweep end
8const int  STEP       = 2;     // adım başına derece / degrees per step
9const int  STEP_DELAY = 40;    // ölçümden önce bekleme (ms) / wait before measuring (ms)
10
11Servo radarServo;
12int angle = MIN_ANGLE;
13int dir = STEP;
14
15int measureCm() {
16  digitalWrite(TRIG_PIN, LOW);
17  delayMicroseconds(2);
18  digitalWrite(TRIG_PIN, HIGH);                         // 10 µs tetik darbesi / 10 µs trigger pulse
19  delayMicroseconds(10);
20  digitalWrite(TRIG_PIN, LOW);
21  unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000UL);  // en çok 30 ms bekle / wait at most 30 ms
22  if (us == 0) return 0;                                // yankı yok = menzil dışı / no echo = out of range
23  return us / 58;                                       // gidiş-dönüş süresi → cm / round-trip time → cm
24}
25
26void setup() {
27  Serial.begin(9600);
28  pinMode(TRIG_PIN, OUTPUT);
29  pinMode(ECHO_PIN, INPUT);
30  radarServo.attach(SERVO_PIN);
31  radarServo.write(angle);
32  delay(500);                                           // başlangıç konumuna gitsin / reach the start position
33}
34
35void loop() {
36  radarServo.write(angle);                              // servoyu yeni açıya döndür / move the servo to the new angle
37  delay(STEP_DELAY);                                    // titreşim geçsin / let the vibration settle
38  int distance = measureCm();
39
40  Serial.print(angle);                                  // biçim: açı,mesafe / format: angle,distance
41  Serial.print(',');
42  Serial.println(distance);
43
44  if (angle + dir > MAX_ANGLE || angle + dir < MIN_ANGLE) dir = -dir;  // uçta yön değiştir / reverse at the ends
45  angle += dir;
46}

Как работает код

Часть кодаЧто делает
STEP и STEP_DELAYЗадают, на сколько градусов сервопривод поворачивается за шаг и сколько ждать перед измерением; этими двумя константами настраивается скорость развёртки.
measureCm()Подаёт импульс 10 µs на пин Trig, с помощью pulseIn измеряет, сколько пин Echo остаётся в HIGH, и делит на 58, чтобы получить сантиметры.
pulseIn(..., 30000UL)Ждёт не больше 30 мс и возвращает 0, если эхо не пришло. Без этого таймаута функция могла бы зависать до 1 секунды, когда датчик смотрит в пустоту.
radarServo.write(angle)Поворачивает сервопривод на нужный угол; библиотека превращает значение 0–180 в импульс 544–2400 µs.
Serial.print ... printlnОтправляет каждое измерение одной строкой «угол,расстояние»; конец строки сообщает Processing, что «данные получены полностью».
dir = -dirМеняет направление, когда угол доходит до 180 или 0, поэтому сервопривод без остановки ходит туда и обратно.

Данные так просты не случайно: одну строку через запятую легко читать в мониторе порта, а разобрать её можно одной строкой кода в Processing, Python или Excel. Расстояние 0 означает «под этим углом в пределах дальности ничего нет», и Processing такие значения не рисует. Если открыть те же данные в «Плоттере по последовательному соединению» (Serial Plotter) в Arduino IDE, будет видно, как угол растёт и падает пилой, а расстояние подскакивает каждый раз, когда датчик проходит мимо предмета. Для этого проекта delay вполне подходит; если нужно читать кнопку или зажигать светодиод, пока радар работает, перепиши цикл на millis().

Если сервопривод гудит и дёргается ровно на 0° или 180°, он упирается в механический предел. Сузь развёртку до 10–170° или запускай сервопривод через radarServo.attach(SERVO_PIN, 500, 2400) и подстрой диапазон импульсов под свой сервопривод.

Зелёный экран радара в Processing

Processing — бесплатная программа на основе Java, созданная для визуального программирования, и её интерфейс очень похож на Arduino IDE: пишешь код и нажимаешь «Run». Библиотека Serial, нужная для последовательной связи, поставляется вместе с Processing; её можно добавить через меню Sketch › Import Library («Скетч › Импортировать библиотеку») или просто положиться на строку import в начале кода. Код ниже вставляется в Processing, а не в Arduino IDE.

C++ (Arduino IDE)
1// Processing 4 çizimi: Arduino IDE'ye değil, Processing'e yapıştır / Processing 4 sketch: paste into Processing, not the Arduino IDE
2import processing.serial.*;                       // Serial kütüphanesi / Serial library
3
4Serial port;
5int angle = 0;                                    // son açı / last angle
6int distance = 0;                                 // son mesafe (cm) / last distance (cm)
7final int MAX_CM = 100;                           // ekrandaki en uzak mesafe / farthest distance on screen
8float R;                                          // radar yarıçapı (piksel) / radar radius (pixels)
9
10void setup() {
11  size(1200, 700);
12  R = width * 0.45;
13  printArray(Serial.list());                      // portları konsola yaz / print the ports to the console
14  String portName = Serial.list()[0];             // gerekirse [1] ya da "COM4" yaz / use [1] or "COM4" if needed
15  port = new Serial(this, portName, 9600);        // Arduino ile aynı baud / same baud as the Arduino
16  port.bufferUntil('\n');                         // satır sonunu bekle / wait for the end of a line
17  background(0);
18}
19
20void draw() {
21  noStroke();
22  fill(0, 12);                                    // yarı saydam siyah: solan iz / translucent black: fading trail
23  rect(0, 0, width, height);
24  translate(width / 2, height - 60);              // radar merkezi alt ortada / radar centre at the bottom middle
25  drawGrid();
26  drawSweep();
27  drawObject();
28  drawLabels();
29}
30
31void drawGrid() {
32  noFill();
33  strokeWeight(2);
34  stroke(98, 245, 31);
35  for (int i = 1; i <= 4; i++) {
36    float d = 2 * R * i / 4;
37    arc(0, 0, d, d, PI, TWO_PI);                  // 25-50-75-100 cm yayları / 25-50-75-100 cm arcs
38  }
39  for (int a = 0; a <= 180; a += 30) {
40    line(0, 0, R * cos(radians(a)), -R * sin(radians(a)));   // 30 derecelik çizgiler / 30-degree lines
41  }
42}
43
44void drawSweep() {
45  strokeWeight(5);
46  stroke(30, 250, 60);
47  line(0, 0, R * cos(radians(angle)), -R * sin(radians(angle)));   // tarama çizgisi / sweep line
48}
49
50void drawObject() {
51  if (distance <= 0 || distance > MAX_CM) return;  // menzil dışı / out of range
52  float p = R * distance / MAX_CM;                 // cm → piksel / cm → pixels
53  float c = cos(radians(angle));
54  float s = sin(radians(angle));
55  strokeWeight(7);
56  stroke(255, 10, 10);
57  line(p * c, -p * s, R * c, -R * s);              // nesneden dışa kırmızı çizgi / red line from the object outwards
58}
59
60void drawLabels() {
61  resetMatrix();
62  noStroke();
63  fill(0);
64  rect(0, height - 40, width, 40);                 // yazı şeridi / text strip
65  fill(98, 245, 31);
66  textSize(20);
67  for (int i = 1; i <= 4; i++) {
68    text(MAX_CM * i / 4 + " cm", width / 2 + R * i / 4 + 4, height - 66);   // yay etiketleri / arc labels
69  }
70  String d = (distance > 0 && distance <= MAX_CM) ? distance + " cm" : "-";
71  text("Açı / Angle: " + angle + "°", 40, height - 12);
72  text("Mesafe / Distance: " + d, width / 2, height - 12);
73}
74
75void serialEvent(Serial p) {
76  String msg = p.readStringUntil('\n');            // "açı,mesafe" satırı / "angle,distance" line
77  if (msg == null) return;
78  String[] parts = split(trim(msg), ',');
79  if (parts.length == 2) {
80    angle = int(parts[0]);
81    distance = int(parts[1]);
82  }
83}

Самая важная часть кода — функция serialEvent(). Благодаря bufferUntil('\n') Processing собирает входящие данные, пока не придёт конец строки, а затем автоматически вызывает эту функцию с готовой строкой. Строка очищается от пробелов и символа \r функцией trim(), делится на две части по запятой с помощью split() и превращается в числа через int(). Тем временем draw() выполняется около 60 раз в секунду: сначала закрашивает экран полупрозрачным чёрным прямоугольником (fill(0, 12)), затем заново рисует сетку, линию развёртки и предмет. Поскольку старые линии с каждым кадром немного темнеют, затухающий след, как на настоящих экранах радаров, появляется сам собой.

НастройкаГде?Что делает
MAX_CM = 100ProcessingНаибольшее расстояние, которое охватывает экран; внешняя дуга — 100 см, внутренние дуги показывают 25, 50 и 75 см.
Serial.list()[0]ProcessingВыбирает первый последовательный порт компьютера; если Arduino стоит в списке ниже, измени индекс или впиши имя напрямую, например «COM4».
9600ОбаСкорость в бодах; значение в Serial.begin у Arduino и в Processing должно совпадать.
fill(0, 12)ProcessingСкорость затухания; 5 даёт длинный след, 30 — изображение почти без следа.
size(1200, 700)ProcessingРазмер окна; уменьши его, если оно не помещается на экране. Радиус зависит от ширины, поэтому высота должна быть больше половины ширины.

Настройка скорости сервопривода и времени развёртки

По даташиту SG90 при 4,8 V поворачивается на 60 градусов за 0,1 секунды, поэтому шаг в 2 градуса он проходит за несколько миллисекунд. На самом деле время развёртки задаёт не сервопривод, а ожидание и измерение на каждом шаге. После остановки сервопривода качалка и датчик ещё немного покачиваются; если мерить в этот момент, расстояния скачут. Производитель HC-SR04 также советует выдерживать между двумя измерениями около 60 мс, потому что эхо предыдущего импульса, отражаясь по комнате, может попасть в следующее измерение. На практике 50–60 мс на шаг в сумме (ожидание + измерение) — хороший баланс. Полная развёртка занимает примерно (180 / шаг + 1) × время шага.

ШагSTEP_DELAYОдна развёртка (0→180°)Результат
1°20 мсоколо 7 сСамая плавная картинка, но медленно; один и тот же предмет измеряется много раз.
2°40 мсоколо 5 сРекомендуемая настройка: плавно и стабильно.
3°50 мсоколо 4 сБыстрее; благодаря лучу датчика шириной 15° ни один предмет не теряется.
5°70 мсоколо 3,5 сКартинка выглядит рваной; крупные шаги вызывают больше раскачки, поэтому ожидание должно быть дольше.

Для плавного движения держи шаг маленьким, а ожидание коротким; если нужна скорость, увеличь шаг и немного удлини ожидание. Если ограничить развёртку нужной зоной (например, 45–135°), время тоже сократится вдвое. Если сервопривод сам дёргается, Arduino время от времени перезагружается, а Processing теряет связь, дело не в скорости, а в питании: SG90 при движении может потреблять около 100–250 mA, а под нагрузкой до 600 mA. Добавь конденсатор и при необходимости запитай сервопривод от внешнего источника 5 V с общей землёй (GND) с Arduino.

Повышение точности измерений

Хотя на бумаге HC-SR04 обещает разрешение 3 мм, точность радара определяют три вещи: ширина луча, скорость звука и тип поверхности. Звуковой луч датчика расходится конусом примерно в 15 градусов. Поэтому тонкая ручка на расстоянии 50 см появляется на экране не точкой, а дугой шириной 15–20 градусов; угловое разрешение радара задаёт этот луч, а не шаг сервопривода, и настоящее направление на предмет — середина дуги. Скорость звука меняется с температурой и рассчитывается по формуле v = 331.3 + 0.606 × T (м/с, T в °C). Число 58 в коде соответствует примерно 22 °C; в холодном гараже показания получаются завышенными на несколько процентов.

ТемператураСкорость звукаТуда и обратно на 1 смПредмет на 100 см (при /58)
0 °C331,3 м/с60,4 µsоколо 104 см
10 °C337,4 м/с59,3 µsоколо 102 см
20 °C343,4 м/с58,2 µsоколо 100 см
30 °C349,5 м/с57,2 µsоколо 99 см
40 °C355,5 м/с56,3 µsоколо 97 см

Можно измерять температуру в комнате датчиком DHT11 или DS18B20 и учитывать скорость звука, а единичные неверные измерения отбрасывать, беря медиану из трёх. Просто добавь две функции ниже в основной код и замени вызов measureCm() в loop() одной из них. Медианный фильтр делает три измерения на шаг, поэтому развёртка немного замедляется.

C++ (Arduino IDE)
1// Ana radar koduna eklenecek fonksiyonlar / functions to add to the main radar sketch
2
3// Sıcaklığa göre düzeltilmiş ölçüm / temperature-compensated reading
4int measureCmTemp(float tempC) {
5  digitalWrite(TRIG_PIN, LOW);
6  delayMicroseconds(2);
7  digitalWrite(TRIG_PIN, HIGH);
8  delayMicroseconds(10);
9  digitalWrite(TRIG_PIN, LOW);
10  unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000UL);
11  if (us == 0) return 0;                                // yankı yok / no echo
12  float v = 331.3 + 0.606 * tempC;                      // ses hızı (m/s) / speed of sound (m/s)
13  return (int)(us * v / 20000.0 + 0.5);                 // µs × (m/s) / 20000 = cm
14}
15
16// Üç ölçümün ortancası: tek seferlik sıçramaları atar / median of three: drops one-off spikes
17int medianCm() {
18  int a = measureCm(); delay(20);
19  int b = measureCm(); delay(20);
20  int c = measureCm();
21  return max(min(a, b), min(max(a, b), c));
22}
23
24// loop() içinde kullanım / use inside loop():
25// int distance = medianCm();
26// int distance = measureCmTemp(18.5);                  // sıcaklık DHT11'den gelebilir / temperature can come from a DHT11
  • Мягкие поверхности (шторы, ткань, поролон) поглощают звук; предмет может не появиться там, где он стоит.
  • Наклонные поверхности отражают звук в сторону; плоская коробка, повёрнутая к датчику под углом больше 45°, может читаться как пустое место.
  • Предметы ближе 2 см измерить нельзя; на практике всё, что ближе 3–4 см, считай ненадёжным.
  • Углы комнаты дают многократные отражения и могут создавать далёкие «призраки», которых на самом деле нет; проверяй на пустом открытом месте.
  • Дальность: в даташите указано 400 см, но стабильные показания на небольших предметах обычно получаются примерно до 2 метров; выбирай MAX_CM с учётом этого.

Мини-радар на OLED-дисплее (без компьютера)

Если нужно, чтобы радар был переносным устройством на батарейках без компьютера, вместо Processing можно взять OLED-дисплей 0,96 дюйма. Нижняя середина экрана SSD1306 128×64 становится центром радара; на нём рисуются полукруг радиусом 60 пикселей, линия развёртки и точки, показывающие последний предмет, измеренный под каждым углом. Подключение дисплея (SDA → A4, SCL → A5) и установка библиотеки описаны в руководстве OLED-дисплей SSD1306; HC-SR04 и сервопривод подключаются так же, как выше.

I2C OLED-дисплей SSD1306 0,96 дюйма
OLED-дисплей 0,96″: в мини-радаре без компьютера он становится полукруглым экраном развёртки 128×64 пикселя.
C++ (Arduino IDE)
1#include <Wire.h>
2#include <Adafruit_GFX.h>
3#include <Adafruit_SSD1306.h>
4#include <Servo.h>
5
6const byte SERVO_PIN = 9;                 // SG90 sinyal / SG90 signal
7const byte TRIG_PIN  = 10;                // HC-SR04 Trig
8const byte ECHO_PIN  = 11;                // HC-SR04 Echo
9const int  MAX_CM    = 50;                // ekrandaki en uzak mesafe / farthest distance on screen
10const int  STEP      = 3;                 // adım başına derece / degrees per step
11const int  CX = 64, CY = 63, R = 60;      // radar merkezi ve yarıçapı (piksel) / radar centre and radius (px)
12
13Adafruit_SSD1306 display(128, 64, &Wire, -1);
14Servo radarServo;
15uint8_t dist[180 / STEP + 1];             // her açının son ölçümü (cm) / last reading per angle (cm)
16int angle = 0;
17int dir = STEP;
18
19int measureCm() {
20  digitalWrite(TRIG_PIN, LOW);
21  delayMicroseconds(2);
22  digitalWrite(TRIG_PIN, HIGH);
23  delayMicroseconds(10);
24  digitalWrite(TRIG_PIN, LOW);
25  unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000UL);
26  if (us == 0) return 0;                  // yankı yok / no echo
27  return us / 58;
28}
29
30void setup() {
31  pinMode(TRIG_PIN, OUTPUT);
32  pinMode(ECHO_PIN, INPUT);
33  radarServo.attach(SERVO_PIN);
34  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
35    for (;;);                             // ekran bulunamadı / display not found
36  }
37  display.setTextColor(SSD1306_WHITE);
38}
39
40void loop() {
41  radarServo.write(angle);
42  delay(20);                              // çizim de zaman aldığı için kısa / short, drawing takes time too
43  int d = measureCm();
44  dist[angle / STEP] = (d > 255) ? 255 : d;   // byte'a sığdır / fit into a byte
45
46  display.clearDisplay();
47  display.drawCircle(CX, CY, R, SSD1306_WHITE);       // dış yay, alt yarısı ekran dışında / outer arc, lower half off-screen
48  display.drawCircle(CX, CY, R / 2, SSD1306_WHITE);   // orta yay = MAX_CM / 2 / middle arc = MAX_CM / 2
49  for (int i = 0; i <= 180 / STEP; i++) {
50    if (dist[i] > 0 && dist[i] <= MAX_CM) {
51      float rad = radians(i * STEP);
52      int r = map(dist[i], 0, MAX_CM, 0, R);          // cm → piksel / cm → pixels
53      display.fillCircle(CX + r * cos(rad), CY - r * sin(rad), 1, SSD1306_WHITE);
54    }
55  }
56  float rad = radians(angle);
57  display.drawLine(CX, CY, CX + R * cos(rad), CY - R * sin(rad), SSD1306_WHITE);  // tarama çizgisi / sweep line
58  display.setCursor(0, 0);
59  display.print(angle);                   // açı / angle
60  display.setCursor(98, 0);
61  display.print(d);                       // mesafe / distance
62  display.print(F("cm"));
63  display.display();
64
65  if (angle + dir > 180 || angle + dir < 0) dir = -dir;   // uçta yön değiştir / reverse at the ends
66  angle += dir;
67}

В этой версии расстояния хранятся по углам в массиве dist, поэтому точки остаются на экране после прохода линии развёртки и обновляются на следующем проходе. Центр круга лежит на нижнем краю экрана, так что нижняя половина круга выходит за пределы дисплея и библиотека её не рисует, остаётся аккуратный полукруг. Передача одного кадра на экран по I2C на 400 kHz занимает около 25 мс, поэтому ожидание сокращено до 20 мс, а шаг увеличен до 3 градусов; развёртка занимает около 4–5 секунд. Шкалу 50 см на маленьком экране читать легче, поэтому MAX_CM равен 50. Половина из 2 КБ памяти Uno уходит на буфер дисплея, поэтому важно хранить массив в байтах (uint8_t).

Радар на ESP32

Библиотека Servo для Arduino на ESP32 не работает; вместо неё установи через «Менеджер библиотек» библиотеку ESP32Servo. Остальной код почти такой же. ESP32 работает от 3,3 V, поэтому не забудь делитель напряжения на линии Echo датчика HC-SR04; а вот импульса 3,3 V на линии Trig большинству датчиков для запуска хватает. Этот код использует 115200 бод, поэтому в коде Processing тоже замени 9600 на 115200. Благодаря Wi-Fi на ESP32 позже можно отправлять данные радара не на компьютер, а на веб-страницу в телефоне; если ESP32 для тебя в новинку, начни со статьи Что такое ESP32.

C++ (Arduino IDE)
1#include <ESP32Servo.h>                // Kütüphane Yöneticisi: ESP32Servo / Library Manager: ESP32Servo
2
3const int SERVO_PIN  = 13;             // SG90 sinyal / SG90 signal
4const int TRIG_PIN   = 26;             // HC-SR04 Trig
5const int ECHO_PIN   = 27;             // 1k/2k bölücüden / through the 1k/2k divider
6const int STEP       = 2;              // adım başına derece / degrees per step
7const int STEP_DELAY = 40;             // ölçümden önce bekleme (ms) / wait before measuring (ms)
8
9Servo radarServo;
10int angle = 0;
11int dir = STEP;
12
13int measureCm() {
14  digitalWrite(TRIG_PIN, LOW);
15  delayMicroseconds(2);
16  digitalWrite(TRIG_PIN, HIGH);
17  delayMicroseconds(10);
18  digitalWrite(TRIG_PIN, LOW);
19  unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000UL);
20  if (us == 0) return 0;               // yankı yok / no echo
21  return us / 58;
22}
23
24void setup() {
25  Serial.begin(115200);                       // Processing'de de 115200 / 115200 in Processing too
26  pinMode(TRIG_PIN, OUTPUT);
27  pinMode(ECHO_PIN, INPUT);
28  radarServo.setPeriodHertz(50);              // standart servo 50 Hz / standard servo 50 Hz
29  radarServo.attach(SERVO_PIN, 500, 2400);    // SG90 darbe aralığı (µs) / SG90 pulse range (µs)
30  radarServo.write(angle);
31  delay(500);
32}
33
34void loop() {
35  radarServo.write(angle);
36  delay(STEP_DELAY);
37  int distance = measureCm();
38  Serial.printf("%d,%d\n", angle, distance);  // açı,mesafe / angle,distance
39  if (angle + dir > 180 || angle + dir < 0) dir = -dir;   // uçta yön değiştir / reverse at the ends
40  angle += dir;
41}

Радар на Raspberry Pi Pico и MicroPython

На Pico отдельная библиотека для сервопривода не нужна: достаточно задать ширину импульса ШИМ-сигнала 50 Hz через duty_ns(). Время эха измеряется функцией machine.time_pulse_us(), которая при таймауте возвращает отрицательное число. Пины Pico тоже работают на 3,3 V, поэтому делитель на линии Echo обязателен. Сохрани код на Pico как main.py через Thonny, а затем закрой Thonny: иначе порт останется занятым и Processing не сможет подключиться. Pico открывает виртуальный последовательный порт по USB, поэтому значение скорости в Processing роли не играет; тот же экран радара работает без изменений.

MicroPython
1from machine import Pin, PWM, time_pulse_us
2import time
3
4servo = PWM(Pin(15))                     # SG90 sinyal / SG90 signal
5servo.freq(50)                           # standart servo 50 Hz / standard servo 50 Hz
6trig = Pin(14, Pin.OUT)
7echo = Pin(13, Pin.IN)                   # bölücüden gelir / comes through the divider
8
9def set_angle(a):
10    # 0° = 500 µs, 180° = 2400 µs darbe / pulse
11    servo.duty_ns(500000 + a * 1900000 // 180)
12
13def measure_cm():
14    trig.value(0)
15    time.sleep_us(2)
16    trig.value(1)                        # 10 µs tetik / 10 µs trigger
17    time.sleep_us(10)
18    trig.value(0)
19    t = time_pulse_us(echo, 1, 30000)    # en çok 30 ms bekle / wait at most 30 ms
20    if t < 0:
21        return 0                         # yankı yok / no echo
22    return t // 58
23
24angle, step = 0, 2
25set_angle(angle)
26time.sleep_ms(500)
27
28while True:
29    set_angle(angle)
30    time.sleep_ms(40)                    # servo otursun / let the servo settle
31    print("{},{}".format(angle, measure_cm()))   # açı,mesafe / angle,distance
32    if angle + step > 180 or angle + step < 0:
33        step = -step                     # uçta yön değiştir / reverse at the ends
34    angle += step

Частые ошибки и их решение

Симптом или сообщение об ошибкеПричинаРешение
Error opening serial port COM3: Port busy (порт занят)Порт держит монитор порта или «Плоттер по последовательному соединению» в Arduino IDE, Thonny или второе окно Processing.Закрой монитор порта и другие программы и снова запусти скетч Processing; при необходимости отключи и снова подключи USB-кабель.
ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 (список портов пуст)Serial.list() пуст: плата не подключена, кабель только для зарядки или не установлен драйвер CH340.Используй кабель с передачей данных и установи драйвер; если Arduino IDE видит порт, Processing тоже его увидит.
Окно открывается, но линия развёртки не движетсяВыбран не тот порт (в Windows первым в списке часто стоит COM1) или не совпадают скорости.Найди место Arduino в списке в консоли, замени на Serial.list()[1] или аналогичное и задай одинаковую скорость с обеих сторон.
The package “processing.serial” does not exist (пакет не найден). You might be missing a library (не хватает библиотеки).Не удаётся найти библиотеку Serial; в установщике Processing 4.4.8 её не было.Обнови Processing до более новой версии или используй 4.4.7 и проверь, что строка import написана правильно.
Error opening serial port /dev/ttyACM0: Permission denied (нет доступа)В Linux у твоего пользователя нет доступа к последовательному порту.Добавь своего пользователя в группу dialout (sudo usermod -a -G dialout $USER), затем выйди из системы и войди снова.
Пока открыт Processing, код не загружается в ArduinoПорт занят программой Processing.Перед загрузкой останови скетч Processing кнопкой «Stop».
Расстояние всегда 0 или бессмысленноеTrig и Echo перепутаны, на датчике нет питания или предмет вне дальности.Сверь подключение с таблицей и сначала проверь всё простым скетчем, который только измеряет расстояние.
Сервопривод дёргается, а Arduino сама перезагружаетсяUSB-порт не может дать ток, нужный сервоприводу, и напряжение проседает.Добавь конденсатор 470 µF или запитай сервопривод от внешнего источника 5 V с общей землёй GND.
Лево и право на экране радара поменялись местамиСервопривод или датчик установлен в обратную сторону.В Processing напиши angle = 180 - int(parts[0]); или сними качалку и надень её, развернув.
При отладке держись такого порядка: сначала убедись, что в мониторе порта идут строки «угол,расстояние», затем закрой монитор порта и запусти Processing. Если со стороны Arduino данные идут правильно, проблема почти всегда в выборе порта или скорости.

Идеи, как развить проект радара

  • Охранный радар с сигнализацией: когда предмет подходит ближе 30 см, включай зуммер и красный светодиод; объедини это с идеями из статьи Сигнализация на Arduino.
  • Робот, объезжающий препятствия: поставь радар на переднюю часть робота; когда робот останавливается, он сканирует влево и вправо и поворачивает в самую свободную сторону. Подробности — в статье Робот, объезжающий препятствия.
  • Карта комнаты: сохраняй данные развёртки на модуль SD-карты и строй по ним облако точек на компьютере.
  • Беспроводной радар: отправляй показания с ESP32 по Wi-Fi на веб-страницу в телефоне; с веб-сервером на ESP32 можно рисовать в реальном времени.
  • Более чёткая карта: вместо HC-SR04 используй лазерный (ToF) датчик с узким лучом; варианты найдёшь в сравнении датчиков расстояния.
  • Умная трость: собери трость, которая предупреждает незрячих людей о препятствиях с помощью датчика расстояния и вибромотора: проект умной трости.

Радар на Arduino объединяет в одной сборке датчик расстояния, управление сервоприводом, последовательную связь и рисование графики на компьютере, поэтому это отличный следующий шаг для новичков. Чтобы укрепить основы, загляни ещё в руководства по датчику расстояния HC-SR04 и сервоприводу. В приложении BlueGrays есть пошаговые проекты: измерение расстояния с HC-SR04, парктроник, работа с сервоприводом и робот, объезжающий препятствия, у каждого схема подключения и код с комментариями.

Частые вопросы

Радар на Arduino — это настоящий радар?

Строго говоря, нет: это сонар. Настоящие радары излучают радиоволны, а в этом проекте используются звуковые волны 40 kHz от HC-SR04. Его называют «радаром на Arduino», потому что принцип работы тот же (послать волну, засечь время эха, нарисовать результат с направлением), а изображение похоже на экран радара.

На каком расстоянии радар на Arduino обнаруживает предметы?

По даташиту дальность HC-SR04 — 2–400 см. Большие ровные поверхности вроде стен можно измерить на 3–4 метра, но для предметов вроде ножек стула или людей надёжная дальность обычно 1,5–2 метра. Если задать MAX_CM в коде Processing под эту дальность, картинка будет самой понятной.

Что нужно, чтобы собрать радар на Arduino?

Достаточно Arduino Uno или Nano, ультразвукового датчика HC-SR04, сервопривода SG90, макетной платы, нескольких перемычек и конденсатора 470 µF для сервопривода. Экран радара на компьютере рисует бесплатная программа Processing; для версии без компьютера добавляется OLED-дисплей 0,96 дюйма.

Можно ли сделать радар на Arduino без Processing?

Да. С OLED-дисплеем SSD1306 радар можно рисовать прямо на Arduino и превратить его в переносное устройство на батарейках. Даже без дисплея значения угла и расстояния можно смотреть в виде графика в «Плоттере по последовательному соединению» (Serial Plotter) в Arduino IDE.

Как исправить ошибку «Port busy» в Processing?

Эта ошибка означает, что последовательный порт занят другой программой. Закрой монитор порта и плоттер в Arduino IDE, Thonny или любой другой оставшийся открытым скетч Processing и попробуй снова. Если ошибка не уходит, отключи USB-кабель и подключи его снова.

Почему сервопривод дёргается, а Arduino перезагружается?

При движении SG90 потребляет короткие импульсы большого тока, и линия 5 V у Arduino с питанием от USB на мгновение проседает. Обычно помогает конденсатор 470 µF на питании сервопривода; если нет, запитай сервопривод от внешнего источника 5 V с общей землёй GND с Arduino.

Все проекты
Измерение расстояния HC-SR04 (вывод в порт)
#27Новичок

Измерение расстояния HC-SR04 (вывод в порт)

Датчик HC-SR04 работает совсем как летучая мышь, которая находит дорогу в темноте: он посылает звук, которого ты не слышишь, слушает эхо и измеряет, насколько далеко предмет перед ним. Arduino каждые

4.6(46)
71
Работа с сервоприводом
#35Новичок
Premium

Работа с сервоприводом

Рычаг маленького сервопривода по очереди поворачивается в три положения: до упора в начало, ровно на середину и до упора в конец, задерживаясь на каждой остановке на две секунды. Arduino сообщает мото

4.7(48)
67
Парктроник на HC-SR04
#28Средний
Premium

Парктроник на HC-SR04

Мини-версия автомобильного парктроника: чем ближе предмет, тем чаще сигнал. Датчик расстояния измеряет предмет перед собой; если он дальше 20 сантиметров, горит зелёный светодиод, а если ближе — мигае

4.8(64)
85
Робот, объезжающий препятствия
#81Продвинутый
Premium

Робот, объезжающий препятствия

Как насчёт того, чтобы собрать умную машину, которая сама находит дорогу? Робот, объезжающий препятствия, постоянно осматривает всё вокруг благодаря ультразвуковому датчику спереди. Встретив препятств

5.0(38)
49
Ультразвуковой датчик расстояния HC-SR04 на ESP32
#116Средний

Ультразвуковой датчик расстояния HC-SR04 на ESP32

Ультразвуковой датчик HC-SR04 вычисляет расстояние по времени, за которое испущенная им звуковая волна отражается от предмета и возвращается (Time of Flight). В этом проекте ESP32 подаёт импульс 10 микросекунд на пин TRIG датчика, а длительность эха читает с пина ECHO через pulseIn(). Вычисленное расстояние в сантиметрах выводится на I2C LCD 16x2. HC-SR04 работает от 5V, поэтому на пине ECHO нужен делитель напряжения.

4.9(28)
45
Парктроник на ESP32 (HC-SR04 + шкала из 5 светодиодов + зуммер + OLED)
#142Продвинутый
Premium

Парктроник на ESP32 (HC-SR04 + шкала из 5 светодиодов + зуммер + OLED)

ESP32-версия автомобильного парктроника! Ультразвуковой датчик HC-SR04 измеряет расстояние до предмета перед ним. По мере уменьшения расстояния шкала из 5 светодиодов заполняется (зелёный → жёлтый → красный), а интервал сигналов зуммера сокращается. Когда предмет совсем близко (меньше 10 см), звучит непрерывная тревога и горят все светодиоды. OLED SSD1306 показывает расстояние в см крупным шрифтом и сообщение состояния (STOP / CAUTION / CLOSE / STOP! / DANGER).

0.0(0)
14
Измерение расстояния с выводом на LCD
#31Продвинутый
Premium

Измерение расстояния с выводом на LCD

Инструмент, который измеряет расстояние без линейки: двигай рукой перед датчиком туда-сюда и смотри, как меняется число. HC-SR04 посылает звуковую волну и слушает эхо, а Arduino вычисляет расстояние в

4.6(45)
59