Здравствуйте уважаемые завсегдатые. Буквально месяц назад купил свой первый набор матрешка и куча прибамбасов к нему. Сейчас пробую создать свое устройство подключив к Ардуинке релешку и дальномер. Но возникла проблема... Нужно, чтобы релешка замыкалась и размыкалась в зависимости от показателя дальномера. Если расстояние менее 120 сантиметром и более 80, то реле замыкается, в остальных положениях размыкается. Но в реальности у меня получаются перещелкивания реле ВКЛ/ВЫКЛ по много раз даже когда дальномер ни кто не пересекает. Понимаю что проблема банально в коде, но что бы я не пытался придумать своими мозгами - не работает. Прошу пнуть меня в нужную сторону. Ниже код на данный момент: Код (C++): int Relay = 4; // Реле модуль подключен к цифровому выводу 4 int Echo = 2; // дальномер int Trig = 5; // дальномер void setup() { pinMode(Relay, OUTPUT); Serial.begin (9600); pinMode(Trig, OUTPUT); pinMode(Echo, INPUT); } unsigned int impulseTime=0; unsigned int distance_sm=0; void loop() { digitalWrite(Trig, HIGH); /* Подаем импульс на вход trig дальномера */ delayMicroseconds(10); // равный 10 микросекундам digitalWrite(Trig, LOW); // Отключаем impulseTime=pulseIn(Echo, HIGH); // Замеряем длину импульса int NEWdistance_sm=impulseTime/58; // Пересчитываем в сантиметры. if (NEWdistance_sm<300&&NEWdistance_sm>1) // отбрасываем бесконечные значения { distance_sm = (distance_sm * 4 + NEWdistance_sm) / 5; // <новое среднее> = (<старое среднее>*4 + <текущее значение>) / 5 Serial.println(distance_sm); // Выводим на порт if (distance_sm<120&&distance_sm>80) // Если расстояние менее 120 сантиметром и более 80 { digitalWrite(Relay, HIGH); // Свет горит delay(100); } else { digitalWrite(Relay, LOW); // иначе не горит } delay(100); /* ждем 0.1 секунды, Следующий импульс может быть излучён, только после исчезновения эха от предыдущего. Это время называется периодом цикла (cycle period). Рекомендованный период между импульсами должен быть не менее 50 мс. */ } else { } }
попробуй для управления дальномером использовать библиотеку NewPing.h http://boteon.com/blogs/materialy-po-robototehnike/urok-4-sozdanie-prototipa-ohrannoi-sistemy.html
С логикой в коде всё в порядке, если у вас рассчеты расстояния правильные. Не знаю формул для этого. Перепроверьте подключение, питание. Добавьте вывод ключевых переменных в Serial, и посмотрите, что там творится.
Блин, на самом деле все оказалось намного банальнее! Датчик плохо отражает сигнал от ворсистых поверхностей. По простому он зависает в попытке измерить расстояние до нее. Придется искать обходной путь в коде для этого. Долбаные законы физики! )))
Даже с библиотекой NewPing.h те же проблемы. Уже установил sonar.ping_median(100). Реже, но все равно криво меряет расстояние до ворсистой поверхности. Код (C++): #include <NewPing.h> #define echo 2 #define trig 5 int Relay = 4; // Реле модуль подключен к цифровому выводу 4 double distance=0; NewPing sonar(trig, echo, 300); void setup() { pinMode(Relay, OUTPUT); Serial.begin (9600); pinMode(trig, OUTPUT); pinMode(echo, INPUT); } void loop() { distance=sonar.convert_cm(sonar.ping_median(100)); Serial.println(distance); // Выводим на порт if (distance<120&&distance>80) // Если расстояние менее 120 сантиметром и более 80 { digitalWrite(Relay, HIGH); // Свет горит delay(10); } else { digitalWrite(Relay, LOW); // иначе не горит } delay(10); /* ждем 0.1 секунды, Следующий импульс может быть излучён, только после исчезновения эха от предыдущего. Это время называется периодом цикла (cycle period). Рекомендованный период между импульсами должен быть не менее 50 мс. */ }
до ворсистой поверхности в любом случае будет плохо мерять, она ведь поглощает звук. но зависать не должно, просто должно давать разные неправильные показания.
не очень понимаю из описани что конкретно должен делать этот робот, почему релешка должна быть включена именно в присутствии объекта на расстоянии от 80 до 120 см и почему детектируемый объект ворсистый, но можно например поставить в программе таймер. Если проблема в том, что когда объект на правильном расстоянии приходят неправильные сигналы, а когда объекта нет, то ложные правильные сигналы не приходят, то можно сделать просто - вставить в программу таймер, который будет обнуляться при каждом правильном сигнале - то есть например при нахождении объекта датчик выдает хаотичные результаты, но среди них хотя бы раз в секунду приходит правильный, то просто ставим таймер чтобы релешка могла отключиться только через 2 секунды и тогда дребезга туда-сюда не будет. вот если есть ложные срабатывания при отсутствии объекта - тогда хз кстати, делей(10) это не 0,1 секунды, а 0,01. а датчику этому нужен дилей побольше, 50мс кажется мимнимум и еще, вроде эхо-пин нет надобности ставить в инпут.
Этот датчик расположен в туалете на бачке прямо напротив входной двери. Логика проста: 1) Пока расстояние от 80 до 120 - это значит дверь в туалет закрыта и возле унитаза ни кого нет. Следовательно свет не нужен - выключаем. 2) Если датчик измеряет расстояние более чем 120 см. значит дверь открыта, следовательно нужно включить свет, так как кто-то входит или специально открыл дверь. 3) Если датчик измеряет расстояние меньше чем 80 см, значит кто-то находится в туалете возле унитаза - свет оставляем включенным. Проблема в том, что когда я зашел в туалет и нахожусь возле унитаза датчик плохо меряет расстояние и иногда выдает данные, которые заставляют релешку выключится и тут же включится. Я уже увеличил количество измерений, что бы нивелировать такие моменты с плохим измерением, но все равно бывают случаи когда релешка делает подряд переключение вкл-выкл. Естественно если я подключу к ней лампочку 220В, то такие переключения не очень благоприятно будут сказываться на сроке ее службы и вообще удобстве использования.
У вас же с датчика нестабильные показания, когда вы сидите. Значит будет срабатывать. А вообще от посиделок по 10 минут на унитазе можно заработать застой крови в нижних конечностях. Это вам не диван.
а в программе вроде наоборот. и зачем дистанция double, оно же в целых приходит. а, для усреднения, потому что время приходит. тогда нормально усреднять 100 результатов - не многовато?
я бы вот так сделал - тупо и по быдляцки Код (C++): #include <NewPing.h> #define echo 2 #define trig 5 #define Relay 4 int distance=0; unsigned long timer = millis(); NewPing sonar(trig, echo, 300); void setup() { pinMode(Relay, OUTPUT); Serial.begin (9600); } void loop() { if (millis()-timer > 10000) { // если с момента последней засечки времени прошло больше 10 секунд digitalWrite(Relay, LOW);} // выключает свет distance=sonar.ping_cm(); delay(100); Serial.println(distance); // Выводим на порт if (distance>120||distance<80) // Если расстояние более 120 сантиметром или менее 80 (дверь открыта или возле толчка кто-то тусит) { distance=sonar.ping_cm(); // измеряет второй раз (защита от случайных ложных включений) delay (100); if (distance>120||distance<80) {// если второй раз подряд дверь открыта или кто-то тусит digitalWrite(Relay, HIGH); // включает свет timer = millis(); //засекает время } } } то есть когда открывается дверь или кто-то заходит, приходит результат что расстояние больше 120 или меньше 80, тогда оно измеряется второй раз (это на случай если есть ложные включения при закрытой двери и пустом сортире), то есть свет будет включаться и таймер обнуляться только при двух подряд сигналах на включение. А выключаться свет будет автоматически через 10 секунд после того как перестали приходить по 2 подряд сигналы на включение. думаю должно работать. еще надо учитывать, что у этого датчика очень большой угол обзора, то есть маленькое разрешение, то есть если например дверь открыта, он может срабатывать на ближайший косяк например или другой какой-то неправильный предмет. тут больше подошло бы что-то лазерное, но нормальных лазерных дальномеров дешевых нету.
Ну ведь дверь-то у вас не ворсистая? Меряйте расстояние от нее, а точнее засекайте ее отдаление(открытие).