Показати повну версію : Ультразвуковой датчик HC-SR04 и Arduino UNO
Сергій М
24.09.2017, 13:19
Добрый вечер коллеги аквариумисты!
Для создания девайса для своего аквариума нужна Ваша помощь, о чём я и прошу. Речь идёт о автодоливе воды.
Имеется Arduino UNO, датчик расстояния HC-SR04, обычный светодиод и зуммер, и всякая нужная мелочь.
В сети нашёл самый простой и наиболее подходящий скетч:
#define echoPin 7 // Вывод Echo
#define trigPin 8 // Вывод Trigger
#define LEDPin 13 // Светодиод "вне зоны доступа"
int maximumRange = 20; // Максимально доступный диапазон
int minimumRange = 4; // Минимально доступный диапазон
long duration, distance; // Длительность эхо, расстояния
void setup() {
Serial.begin (9600); //Включаем отладочный вывод
//Настраиваем порты
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(LEDPin, OUTPUT);
}
void loop() {
//Выключаем Trigger
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
//Посылаем 10мкс импульс на Trigger
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
//Считаем длительность сигнала эхо
duration = pulseIn(echoPin, HIGH);
//Рассчитываем расстояние (по скорости звука)
distance = duration/58.2;
if (distance >= maximumRange || distance <= minimumRange){
/* Выводим отрицательное значение расстояния на компьютер и зажигаем светодиод
"Вне зоны доступа"*/
Serial.println("-1");
digitalWrite(LEDPin, HIGH);
}
else {
/* Отправляем расстояние на компьютер и гасим светодио */
Serial.println(distance);
digitalWrite(LEDPin, LOW);
}
//Delay 50ms before next reading.
delay(50);
}
Понравился тем что в рамках заданного расстояния можно отслеживать уровень воды. Вместо/или в парралель светодиоду установив пищалку получится "алярм", в случае когда уровень воды от автослива опустится ниже нужного уровня(20см, 5-я строчка скетча) или выше(4см, 6-я строчка) - светодиод и пищалка дадут знать.
Но это в вышеописанном скетче присутствует. Моя просьба в другом. Можете добавить ещё один диапазон, чтоб он как раз и управлял столь желаемым мной -автодоливом, посредством подключения через реле??? Тот диапазон что есть сейчас (4см-20см) - останется для аварийного сигнализирования. Новый нужен в внутренних рамках, например 5см-19см, получается по 1см до аварийного срабатывания диапазона 4см-20см. Данные расстояния приблизительные.
И можно ли сдетать так - чтоб светодиод /пищалка, диапазона 4-20 не просто включался - а моргал/пищал зуммером.
Огромная просьба откликнуться нашим программистам и отполировать код !!
yarishNEW
24.09.2017, 15:31
Актуальность в автодоливе для каких функций?
Arduino UNO - избыточное решение для такой функции как автодолив, если только он не завязан с другим функционалом который вы собираетесь завести на этот контроллер.
Сергій М
24.09.2017, 16:52
yarishNEW,
1) Для автодолива ... Автослив будет реализован тем контроллером который у меня сейчас (Мега 2560).
2) Arduino UNO у меня валялась в ящике (для другого проекта, пока не завершённого)
, вот и использовал это. Есть ещё где-то Нано, но не могу найти.
Если как Вы говорите - избыточна для такого проекта, то конечно было бы круто - полностью сделать отдельный, самодостаточный контроллер по автоматизации подмена воды в акве. С часами, реле управляющими клапанами слива, долива, с возможностью выбора графика подмен - 2 раза в день, 1раз в день, через день, 1 раз в неделю или любой другой режим.
Но для этого нужно уже намного сложнее код, я же не умею программировать вообще, кроме как выставить время, расстояния, таймеры и т.п в скетче.
alex_palace
24.09.2017, 17:44
Попробуйте что-то из описанных тут сайтов https://www.drive2.ru/b/2729013/ и думаю все получится :) У себя с логической частью уже разобрался а вот с визуализацией как раз проблема но с ней таких инструментов пока нет :(
Сергій М
24.09.2017, 18:04
alex_palace, Спасибо, попробую, но терзают меня сомнения ....
сколько будет времени потрачено на изучение работы на данных программах ...
Сергій М
24.09.2017, 18:21
Возможно я в шапке сложно описал потребности.
Сейчас есть :
0-4см - включается светодиод
4-20см - выключается светодиод
20-∞ - включается светодиод
Всё.
Нужно :
0-4см - включается светодиод 1
4-20см - выключается светодиод 1
20- ∞ включается светодиод 1
5-19см - включается светодиод 2
0-5см и 19-∞ - выключается светодиод 2
4-5см и 19-20 - включается светодиод 3
0-4, 5-19 и 20-∞ - выключается светодиод 3
Сищалку я запараллелю с светодиодом 1, функция "Алярм" - это в случае если клапана слива или долива перестараются, и уровень выйдет за рамки 4-20см. Пищать зумером и моргать если сложно программно, решу подключением через реле задержки ))) так смогу и посерьёзнее колокол сигнализации подключить, и прожектор вместо светодиода :024:
А Реле автодолива подключу к светодиоду 2, так клапан откроется и пойдёт долив воды.
AquaGomel
24.09.2017, 21:02
Если я правильно понял. Можно сделать изящнее, но если честно то лень. И естественно код нужно проверять. Если что не так пишите.
#include "Arduino.h"
#define echoPin 7 // HC-SR04
#define trigPin 8 // HC-SR04
#define LEDInfo 11
#define LEDWarning 12
#define LEDError 13
long duration, distance;
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(LEDInfo, OUTPUT);
pinMode(LEDWarning, OUTPUT);
pinMode(LEDError, OUTPUT);
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration / 58.2;
/*
* 0-4 20 - > - LEDError1 (ON)
* 5 -19 - LEDInfo2 (ON)
* 4-5 19-20 LEDWarning3 (ON)
*/
if ((distance >= 0 && distance < 4) || distance > 20) {
//LEDError1 (ON)
if (digitalRead(LEDError) == LOW) {
digitalWrite(LEDError, HIGH);
}
} else {
//LEDError1 (OFF)
if (digitalRead(LEDError) == HIGH) {
digitalWrite(LEDError, LOW);
}
}
if (distance >= 5 && distance <= 19) {
//LEDInfo2 (ON)
if (digitalRead(LEDInfo) == LOW) {
digitalWrite(LEDInfo, HIGH);
}
} else {
//LEDInfo2 (OFF)
if (digitalRead(LEDInfo) == HIGH) {
digitalWrite(LEDInfo, LOW);
}
}
if ((distance >= 4 && distance < 5) || (distance > 19 && distance <= 20)) {
// LEDWarning3 (ON)
if (digitalRead(LEDWarning) == LOW) {
digitalWrite(LEDWarning, HIGH);
}
} else {
// LEDWarning3 (OFF)
if (digitalRead(LEDWarning) == HIGH) {
digitalWrite(LEDWarning, LOW);
}
}
delay(50);
}
Сергій М
24.09.2017, 22:41
ого !!!!!!! прямо сейчас проверю !
Сергій М
24.09.2017, 23:11
AquaGomel, Всё просто идеально работает !! Огромное спасибо.
Хотел визуально проконтролировать работу сенсора с помощью "Монитор порта", а там пусто ))) прописал - Serial.begin(9600); // Starts the serial communication и ниже : #include "Arduino.h"
#define echoPin 7 // HC-SR04
#define trigPin 8 // HC-SR04
#define LEDInfo 11
#define LEDWarning 12
#define LEDError 13
long duration, distance;
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(LEDInfo, OUTPUT);
pinMode(LEDWarning, OUTPUT);
pinMode(LEDError, OUTPUT);
Serial.begin(9600); // Starts the serial communication
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration / 5.82;
/*
* 0-4 20 - > - LEDError1 (ON)
* 5 -19 - LEDInfo2 (ON)
* 4-5 19-20 LEDWarning3 (ON)
*/
if ((distance >= 0 && distance < 40) || distance > 200) {
//LEDError1 (ON)
if (digitalRead(LEDError) == LOW) {
Serial.println(distance);
digitalWrite(LEDError, HIGH);
}
} else {
//LEDError1 (OFF)
if (digitalRead(LEDError) == HIGH) {
Serial.println(distance);
digitalWrite(LEDError, LOW);
}
}
if (distance >= 50 && distance <= 190) {
//LEDInfo2 (ON)
if (digitalRead(LEDInfo) == LOW) {
Serial.println(distance);
digitalWrite(LEDInfo, HIGH);
}
} else {
//LEDInfo2 (OFF)
if (digitalRead(LEDInfo) == HIGH) {
Serial.println(distance);
digitalWrite(LEDInfo, LOW);
}
}
if ((distance >= 40 && distance < 50) || (distance > 190 && distance <= 200)) {
// LEDWarning3 (ON)
if (digitalRead(LEDWarning) == LOW) {
Serial.println(distance);
digitalWrite(LEDWarning, HIGH);
}
} else {
// LEDWarning3 (OFF)
if (digitalRead(LEDWarning) == HIGH) {
Serial.println(distance);
digitalWrite(LEDWarning, LOW);
}
}
delay(50);
}
и понял что даже прописать Serial.println(distance); в нужных местах я не умею, пока что. Так как значения в "Мониторе порта" изменялись исключительно при перемещении сенсора, дальше замирали до следующего перемещения.
Сергій М
24.09.2017, 23:20
Ах да, забыл - исправил (временно) для точности проверки :
с - distance = duration / 58.2; на distance = duration / 5.82; что следовательно привело к исправлению всех значений в мм, 0-40-50-190-200мм.
AquaGomel
25.09.2017, 00:44
Если я правильно понял то: Serial.println(distance); установлены внутри блока когда срабатывает включение или отключение канала. Если ван нужен реал-тайм значения distance просто добавьте строку Serial.println(distance); сразу за distance = duration / 5.82; А остальные Serial.println можно убрать. Однако в боевом применении не желательно оставлять Serial code67
Сергій М
25.09.2017, 08:34
Понял, учту, сейчас мне данная статистика о дистанции нужна исключительно для тонкой настройки автодолива, при окончательной установке на акву - данные строки будут удалены.
А пока - вечером всё ещё пару раз проверю и перейду к этапу сборки корпуса и прикручивания к акве ))
Сергій М
25.09.2017, 23:30
AquaGomel, Ещё один вопрос - есть ли возможность установки гистерезиса на включения, так как дребезжания на границах сумасшедшие, всему виной точность самого датчика - 3мм !!! из-за этого нет грани при переходе с одного режима в другой. Например мы установим условие 0-4см Led1, и 5-10см Led2,получится грань 4.5см (45мм), из-за проклятых 3мм точности как выясняется грани 45мм просто не существует, показания мелькают со скоростью пропорциональной обновлению информации ( delay(50); ), и меняются в радиусе 3мм - 44-47мм, 43-46мм, что приводит к постоянному дребезжанию. Даже в переключении на см, данный конфуз остаётся ((
Есть ли лекарство от этого ? Придётся отказываться от какой либо из функций (например LEDWarning3) и решит ли это проблему ?
AquaGomel
26.09.2017, 08:41
Дребезжание я так понимаю постоянное включение выключение каналов? Могу предположить что точность данного устройства достаточно невысокая, вернее даже не точность а разброс значений которые оно выдает. По даташиту у него разрешение: 0.3 cm поэтому между значениями "включить текущий канал выключить предыдущий" должен быть зазор не менее 30мм, однако смею предположить что естественные колебания воды на поверхности резко увеличат этот самый зазор. Мой вам совет: сделать зазор как минимум в 0.5 см между зонами включения светодиодов. Логику выключения выключения сделать такой: светодиоды включать при достижении какой либо зоны, остальные выключать только если зона смениться на другую. Если значение попадает в зазор между зонами светодиоды не выключать. Как-то так...
Сергій М
26.09.2017, 22:04
То-есть сделать так ?:
Сейчас (в мм) - Led1 0-40, Led2 40-50, Led3 50-190, Led2 190-200, Led1 200<
Сделать (в мм) - Led1 0-37, Led2 42-50, Led3 55-190, Led2 195-200, Led1 205<
Сергій М
26.09.2017, 22:08
Реле будет стоять с Led3 только в диапазоне 50-190, бребезжание диодов как-то всё равно, а вот реле и ЭМклапан долива, разве что MOSFET поставить, или твердотельные, хоть они и подороже будут.
AquaGomel
27.09.2017, 09:31
Реле будет стоять с Led3 только в диапазоне 50-190, бребезжание диодов как-то всё равно, а вот реле и ЭМклапан долива, разве что MOSFET поставить, или твердотельные, хоть они и подороже будут.
Проблема решается на программном уровне. Пробуйте:
#include "Arduino.h"
#define echoPin 7 // HC-SR04
#define trigPin 8 // HC-SR04
#define LEDInfo 11
#define LEDWarning 12
#define LEDError 13
long duration, distance;
// clearance to avoid rattling of sensors
const byte GapDistance = 3;
//LED3
const byte LEDInfoMin = 50;
const byte LEDInfoMax = 190;
//LED2
const byte LEDWarningMin = 40;
const byte LEDWarningMax = 200;
//LED1
const byte LEDErrorMin = 0;
const byte LEDErrorMax = 200;
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(LEDInfo, OUTPUT);
pinMode(LEDWarning, OUTPUT);
pinMode(LEDError, OUTPUT);
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration / 5.82;
/*
* 0-37 203 - > - LEDError1 (ON)
*/
if ((distance >= LEDErrorMin && distance < LEDWarningMin - GapDistance)
|| distance > LEDErrorMax + GapDistance) {
// LEDError1 (ON)
if (digitalRead(LEDError) == LOW) {
digitalWrite(LEDError, HIGH);
}
} else {
// LEDError1 (OFF)
if (digitalRead(LEDInfo) == HIGH) {
digitalWrite(LEDInfo, LOW);
}
// LEDWarning3 (OFF)
if (digitalRead(LEDWarning) == HIGH) {
digitalWrite(LEDWarning, LOW);
}
}
/*
* 53 -187 - LEDInfo2 (ON)
*/
if (distance >= LEDInfoMin + GapDistance && distance <= LEDInfoMax - GapDistance) {
// LEDInfo2 (ON)
if (digitalRead(LEDInfo) == LOW) {
digitalWrite(LEDInfo, HIGH);
}
} else {
// LEDError (OFF)
if (digitalRead(LEDError) == HIGH) {
digitalWrite(LEDError, LOW);
}
// LEDWarning3 (OFF)
if (digitalRead(LEDWarning) == HIGH) {
digitalWrite(LEDWarning, LOW);
}
}
/*
* 43-47 193-197 LEDWarning3 (ON)
*/
if ((distance >= LEDWarningMin + GapDistance && distance < LEDInfoMin - GapDistance)
|| (distance > LEDInfoMax + GapDistance && distance <= LEDWarningMax - GapDistance)) {
// LEDWarning3 (ON)
if (digitalRead(LEDWarning) == LOW) {
digitalWrite(LEDWarning, HIGH);
}
} else {
// LEDInfo (OFF)
if (digitalRead(LEDInfo) == HIGH) {
digitalWrite(LEDInfo, LOW);
}
// LEDWarning3 (OFF)
if (digitalRead(LEDError) == HIGH) {
digitalWrite(LEDError, LOW);
}
}
delay(50);
}
Сергій М
27.09.2017, 11:42
Спасибо, вечером всё проверю на практике!!
Сергій М
27.09.2017, 20:02
К сожалению что-то не так, на старом коде все диоды работали, хоть и часто переключались на гранях, в новом же работает согласно параметрам только 1 диод LEDWarning 12, остальные просто еле-еле моргают. Проверял все контакты - всё ок, так как тут же заливаю старый скетч - работает на ура.
aleksandrpat
26.03.2018, 20:47
Я интересуюсь радиоэлектроникой и вот недавно тестировал такой датчик. В характеристиках указано что он работает от 2 до 400 см. В реальности он работает от 5 см. В общем не буду долго писать вот тут почитайте http://elschemo.ru/dlya-nachinayushhix/rabota-s-ultrazvukovym-datchikom-hc-sr04/
vBulletin версії 3.8.7, © 2000-2025, Jelsoft Enterprises Ltd.
Переклад: © Віталій Стопчанський, 2004-2010