Радар на 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?
Сердце системы — 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 Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| HC-SR04 VCC | 5V | VIN (5 V) | VBUS (пин 40) |
| HC-SR04 GND | GND | GND | GND |
| HC-SR04 Trig | D10 | GPIO 26 | GP14 |
| HC-SR04 Echo | D11 | GPIO 27 (через делитель) | GP13 (через делитель) |
| SG90 коричневый (GND) | GND | GND | GND |
| SG90 красный (+5 V) | 5V | VIN (5 V) | VBUS (пин 40) |
| SG90 оранжевый (сигнал) | D9 | GPIO 13 | GP15 |
На Uno монтаж получается аккуратнее, если провода 5 V и GND датчика и сервопривода подключить к шинам «плюс» и «минус» макетной платы, а сами шины — к пинам 5V и GND Arduino. Вставь конденсатор 470 µF в те же шины: длинную ножку (+) на 5 V, а короткую, отмеченную полосой на корпусе, на GND. У некоторых сервоприводов провода чёрный, красный и белый; тогда чёрный — это GND, а белый — сигнал. Чтобы перепроверить расположение пинов на своей плате, воспользуйся утилитой распиновки.
Крепление датчика на сервоприводе

Прежде чем надеть качалку, выставь сервопривод на 90 градусов: просто загрузи короткий тестовый скетч с radarServo.write(90) и оставь сервопривод в этом положении. Затем надень качалку так, чтобы датчик смотрел прямо вперёд. Тогда 0° указывает вправо, 90° — прямо вперёд, а 180° — влево, и направления на экране Processing точно совпадают с реальными. Когда приклеиваешь HC-SR04 к качалке двусторонним скотчем или термоклеем, следи, чтобы оба цилиндра были параллельны земле: если датчик наклонён вниз, он примет поверхность стола за предмет. Оставь проводам достаточный запас, чтобы они не натягивались при повороте на 180 градусов, и закрепи сервопривод на тяжёлом основании или в коробке: корпус, который трясётся на каждом шаге, портит измерения.
Сборка радара на Arduino шаг за шагом
- Подключи детали по таблице выше, не забудь конденсатор и закрепи датчик на сервоприводе.
- Открой Arduino IDE; библиотека Servo входит в комплект IDE, так что дополнительно ничего устанавливать не нужно.
- Загрузи код радара, приведённый ниже. Если не получается выбрать плату или порт, загляни в статью Код не загружается в Arduino.
- Открой монитор порта на скорости 9600 бод; если бегут строки угла и расстояния вроде «30,45», со стороны Arduino всё готово. После этого обязательно закрой монитор порта.
- Установи на компьютер Processing 4, открой новый скетч и вставь код экрана радара.
- Нажми «Run» (запуск): в консоли внизу появится список портов, и откроется окно радара. Если провести рукой перед датчиком, должны появиться красные линии.
Код радара для Arduino
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().
Зелёный экран радара в Processing
Processing — бесплатная программа на основе Java, созданная для визуального программирования, и её интерфейс очень похож на Arduino IDE: пишешь код и нажимаешь «Run». Библиотека Serial, нужная для последовательной связи, поставляется вместе с Processing; её можно добавить через меню Sketch › Import Library («Скетч › Импортировать библиотеку») или просто положиться на строку import в начале кода. Код ниже вставляется в Processing, а не в 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 = 100 | Processing | Наибольшее расстояние, которое охватывает экран; внешняя дуга — 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 °C | 331,3 м/с | 60,4 µs | около 104 см |
| 10 °C | 337,4 м/с | 59,3 µs | около 102 см |
| 20 °C | 343,4 м/с | 58,2 µs | около 100 см |
| 30 °C | 349,5 м/с | 57,2 µs | около 99 см |
| 40 °C | 355,5 м/с | 56,3 µs | около 97 см |
Можно измерять температуру в комнате датчиком DHT11 или DS18B20 и учитывать скорость звука, а единичные неверные измерения отбрасывать, беря медиану из трёх. Просто добавь две функции ниже в основной код и замени вызов measureCm() в loop() одной из них. Медианный фильтр делает три измерения на шаг, поэтому развёртка немного замедляется.
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 и сервопривод подключаются так же, как выше.

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.
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 роли не играет; тот же экран радара работает без изменений.
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]); или сними качалку и надень её, развернув. |
Идеи, как развить проект радара
- Охранный радар с сигнализацией: когда предмет подходит ближе 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 (вывод в порт)
Датчик HC-SR04 работает совсем как летучая мышь, которая находит дорогу в темноте: он посылает звук, которого ты не слышишь, слушает эхо и измеряет, насколько далеко предмет перед ним. Arduino каждые

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

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

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

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

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

Измерение расстояния с выводом на LCD
Инструмент, который измеряет расстояние без линейки: двигай рукой перед датчиком туда-сюда и смотри, как меняется число. HC-SR04 посылает звуковую волну и слушает эхо, а Arduino вычисляет расстояние в
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

