Arduino-дальномер и цифровой уровень: пошаговое руководство
Обзор
Устройство совмещает ультразвуковой дальномер (HC-SR04), акселерометр MPU6050 (угол наклона), LCD 16×2 и одну кнопку для управления. Четыре режима:
- Выбор единиц измерения (см, дюймы, метры, футы).
- Измерение расстояния с сохранением двух последних значений.
- Вычисление площади по двум перпендикулярным измерениям.
- Цифровой уровень: тангаж (Pitch) и крен (Roll) относительно горизонта.




Схема и PCB
Схема: HC-SR04 (Trig/Echo), MPU6050 (I2C), LCD (параллельно), кнопка с подтяжкой, делитель напряжения для контраста LCD. Плата спроектирована в EasyEDA, заказ в JLCPCB.


Сборка корпуса
Корпус из прозрачного акрила 5 мм (верх 4 мм под LCD). Вырез под LCD — дрель + пила + рашпил. Отверстия под ультразвуковой датчик, кнопку, тумблер — фрезерными коронками. Эпоксидный клей, верхняя крышка на болтах/гайках. Питание — крона 9 В.


Программный код
Библиотеки: Wire.h (I2C), LiquidCrystal.h. Переменные: режимы (program), единицы (unitSelect), буферы измерений.
Инициализация
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int MPU = 0x68;
#define trigPin 8
#define echoPin 9
#define selectButton 10
int16_t AcX, AcY, AcZ;
long duration; float distance;
int program = 0; float d=0, d1=0, d2=0, area=0;
int axis = 0, angle = 0, unitSelect = 0;
String unit = "cm";
void setup() {
Wire.begin();
Wire.beginTransmission(MPU); Wire.write(0x6B); Wire.write(0); Wire.endTransmission(true);
lcd.begin(16, 2);
pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(selectButton, INPUT_PULLUP);
}
Главный цикл: машина состояний
void loop() {
switch (program) {
case 0: // Выбор единиц
lcd.setCursor(0,0); lcd.print("Select Unit: "); lcd.setCursor(13,0); lcd.print(unit); lcd.print(" ");
if (digitalRead(selectButton) == 0) {
if (unitSelect == 0) { unit = "in"; unitSelect = 1; }
else if (unitSelect == 1) { unit = "m"; unitSelect = 2; }
else if (unitSelect == 2) { unit = "ft"; unitSelect = 3; }
else if (unitSelect == 3) { unit = "cm"; unitSelect = 0; }
delay(500);
if (digitalRead(selectButton) == 0) { program = 1; lcd.clear(); delay(500); }
}
break;
case 1: // Дальномер
distance = getDistance();
lcd.setCursor(0,0); lcd.print("Dist: "); lcd.print(distance); lcd.print(" "); lcd.setCursor(14,0); lcd.print(unit);
lcd.setCursor(0,1); lcd.print("d:"); lcd.setCursor(8,1); lcd.print("d:");
if (digitalRead(selectButton) == 0) {
if (d == 0) { lcd.setCursor(0,1); lcd.print("d: "); lcd.setCursor(2,1); lcd.print(distance); d=1; delay(100); }
else if (d == 1) { lcd.setCursor(8,1); lcd.print("d: "); lcd.setCursor(10,1); lcd.print(distance); d=0; delay(100); }
delay(500);
if (digitalRead(selectButton) == 0) { program=2; d=0; lcd.clear(); delay(500); }
}
break;
case 2: // Площадь
distance = getDistance();
lcd.setCursor(0,0); lcd.print("Area: "); lcd.print(area); lcd.setCursor(12,0); lcd.print(unit); lcd.print("^2");
if (d == 0) { lcd.setCursor(0,1); lcd.print("d1: "); lcd.setCursor(3,1); lcd.print(distance); }
else if (d == 1) { lcd.setCursor(9,1); lcd.print("d2: "); lcd.setCursor(12,1); lcd.print(distance); }
else if (d == 2) { lcd.setCursor(6,0); lcd.print(area); }
if (digitalRead(selectButton) == 0) {
if (d == 0) { lcd.setCursor(0,1); lcd.print("d1: "); lcd.setCursor(3,1); lcd.print(distance); d=1; d1=distance; delay(100); }
else if (d == 1) { lcd.setCursor(9,1); lcd.print("d2: "); lcd.setCursor(12,1); lcd.print(distance); d=2; d2=distance; area=d1*d2; delay(100); }
else if (d == 2) { lcd.clear(); d=0; area=0; delay(100); }
delay(500);
if (digitalRead(selectButton) == 0) { program=3; d=0; lcd.clear(); delay(500); }
}
break;
case 3: // Уровень (Pitch/Roll)
Wire.beginTransmission(MPU); Wire.write(0x3B); Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AcX = Wire.read()<<8 | Wire.read();
AcY = Wire.read()<<8 | Wire.read();
AcZ = Wire.read()<<8 | Wire.read();
if (axis == 0) { // Pitch (вокруг Y)
angle = atan(-1 * AcX / sqrt(pow(AcY,2) + pow(AcZ,2))) * 180 / PI;
lcd.setCursor(0,0); lcd.print("Pitch");
} else { // Roll (вокруг X)
angle = atan(-1 * AcY / sqrt(pow(AcX,2) + pow(AcZ,2))) * 180 / PI;
lcd.setCursor(0,0); lcd.print("Roll ");
}
lcd.setCursor(0,1); lcd.print("Angle: "); lcd.print(abs(angle)); lcd.print(" "); lcd.setCursor(10,1); lcd.print("deg");
if (digitalRead(selectButton) == 0) {
if (axis == 0) axis = 1; else axis = 0; delay(100);
delay(500);
if (digitalRead(selectButton) == 0) { program=0; lcd.clear(); delay(500); }
}
break;
}
}
Функция измерения расстояния с конвертацией единиц
float getDistance() {
digitalWrite(trigPin, LOW);
digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2; // см
if (unitSelect == 1) { distance = distance; unit = "cm"; }
else if (unitSelect == 2) { distance *= 0.393701; unit = "in"; }
else if (unitSelect == 3) { distance *= 0.01; unit = "m"; }
else if (unitSelect == 0) { distance *= 0.0328; unit = "ft"; }
return distance;
}
Формулы углов взяты из Application Note Freescale Tilt Sensing Using a Three-Axis Accelerometer. Кнопка переключает Pitch/Roll, долгое нажатие — выход в меню единиц.
Полный код
/* DIY Digital Range Measurer and Spirit Level
by Dejan Nedelkovski, www.HowToMechatronics.com */
// ... (полный листинг, объединяющий все части выше)
Заключение
Компактный прибор «все в одном» на одной плате, с интуитивным одно-кнопочным интерфейсом. Полезен для быстрых замеров и выравнивания. Файлы проекта (EasyEDA, код) открыты.
Производственный процесс
- Сборка DCC-командной станции для модельной железной дороги на Arduino с бесплатным приложением
- Цифровые кости на Arduino: генератор случайных чисел с LCD-дисплеем и кнопкой
- Создание анимации и игр на LCD 16×2 с Arduino UNO
- Детектор аудиочастот на Arduino: измеряем пик громкости с высокочувствительным модулем
- Собираем свой Tamagotchi на Arduino: цифровой питомец своими руками
- Крестики-нолики на Arduino с матрицей MAX7219 и картонным корпусом
- Сборка вольтметра на Arduino с дисплеем Nokia 5110 — Пошаговое руководство
- Сборка надежного таймера обратного отсчета на Arduino с 7-сегментным дисплеем SparkFun
- Управление Arduino Uno из Python 3: команды через последовательный порт и демонстрация с LED
- Сборка компактного FM-радио на Arduino Nano и RDA5807M