HC-SR04 безбожно врёт
- Войдите на сайт для отправки комментариев
Помогите решить проблему. Требуется создать GPS трекер для грузовых контейнеров, который помимо координат должен передавать наполненность контейнера, вскрытие и пожар. Основное требование - устройство должно работать без зарядки до 6 месяцев. В качестве датчика наполнения я выбрал ультразвуковой сонар HC-SR04. Скетч, написанный мной в начале лета всех устраивал, но сейчас, то ли из за холода, то ли просто время пришло, короче начали массово садиться аккумуляторы. Было решено переделать девайсы. В старом использовались 12 V аккумуляторы + КРЕН 5 (КР142ЕН5) который, как выяснилось сам потребляет энергию, в новом же я решил использовать Li-Pol аккумулятор на 3,7v. Соответственно Ардуину я взял Arduino pro mini на 3,3v HC-SR04 запитал через DC/DC преобразователь, так как эти модули отказываются работать от 3,3 v. Всё прекрасно работало, пока я не решил загонять МК в сон. Скачал на этом форуме пример, поправил его, и тут выяснилась приниприятная вещь. По отдельности скетчи работают нормально (один для сонара, другой для сна), а вот вместе, ну ни как не хотят. Сонар ужасно врёт (показывает расстояние от 6 см до реального, но каждый раз разное), а тот что отвечает за сон, виснет, при чём в тот момент, когда он всё узнал и должен отправить данные на сервер. Хотя на данный момент он ни чего не отправляет, а вместо отправки на сервер, отправляет соответствующее сообщение в консоль.
Вот злосчастный скетч.
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <SoftwareSerial.h>
int wakePin = 2; // Пин используемый для просыпания (прерывания)
int sleepStatus = 0; // Переменная для хранения статуса (спим, проснулись)
int LedPin=13; // Светодиод, включение обвязки
int count; // Счётчик пробуждений
const int slp = 3; // Количество пробуждений до включения сонара
bool wdog, alarm; // Сработал таймер, тревога
#include <Ultrasonic.h>
Ultrasonic ultrasonic(10,11); //trig, echo
int ds = 0; //Здесь хранится расстояние для сравнения
bool snr = false;
#include <TinyGPS.h>
TinyGPS gps;
SoftwareSerial ss(4, 3); //RX, TX
String lat, lon; //Здесь хранятся широта и долгота для сравнения
bool gpson;
ISR (WDT_vect)
{
wdog = true;
wakeUpNow(); // пробуждение по таймеру
}
void wakeUpNow() // Прерывание сработает после пробуждения
{
if (sleepStatus) // Если мы спали,
{
sleep_disable(); // то первое, что нужно сделать после просыпания - выключить спящий режим
wdt_disable(); // загоняем собаку в конуру
sleepStatus = 0; // В переменную заносим статус бодрствования
if(wdog == false){ // если не по таймеру, значит тревога
alarm = true;
}
}
}
void setup()
{
//сон - пробуждение
count = 0;
pinMode(LedPin, OUTPUT);
pinMode(wakePin, INPUT);
digitalWrite(wakePin, HIGH); // Подтягивем ногу к 5.
digitalWrite(LedPin, LOW);
delay(5000); // на всякий случай, если войдет в бесконечный цикл, можно будет перепрошить
//инициализация портов
Serial.begin(115200); // удалить после настройки
//предварительные установки
gpson = false;
wdog = false;
alarm = false;
Serial.println("INIT");
}
void sleepNow() // Функция увода ардуины в спячку.
{
delay(5000);
// подготовка WatchDog
wdog = false;
MCUSR = 0; // clear various "reset" flags
WDTCSR = bit (WDCE) | bit (WDE); // allow changes, disable reset
// set interrupt mode and an interval
WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // set WDIE, and 8 seconds delay
//WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1); // set WDIE, and 1 second delay
wdt_reset(); // pat the dog
// конец подготовки WatchDog
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Здесь устанавливается режим сна
sleep_enable(); // Включаем sleep-бит в регистре mcucr. Теперь возможен слип
attachInterrupt(0, wakeUpNow, FALLING); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 2 на 5в.)
sleepStatus = 1; // В переменную заносим статус сна
sleep_mode(); // Здесь устройство перейдет в режим сна!!!
sleep_disable(); // Первое, что нужно сделать после просыпания - выключить спящий режим
detachInterrupt(0); // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться
}
void transmit(int d, String l){
if(d == 1){
Serial.println("TRANSMIT "+l);
}
digitalWrite(LedPin, HIGH); // Выключаем светодиод
delay(500);
snr = false;
Serial.println("SLEEP");
sleepNow(); // Вызов функции sleep() для засыпания
}
String sonar(){ // функция определения расстояния
int us = 0;
delay(5000);
for (int i = 0; i < 10; i++){
us = us + ultrasonic.Ranging(CM);
Serial.println(ultrasonic.Ranging(CM));
delay(1000);
Serial.println("OK");
}
us = us/10;
if(ds != us){
Serial.println("TR");
transmit(1,String(us));
ds = us;
} else {
Serial.println("ITOGO "+String(us));
Serial.println("SLEEP");
snr = false;
sleepNow();
}
}
void get_gps(){ // получаем координаты
ss.begin(9600);
bool newData = false;
unsigned long chars;
unsigned short sentences, failed;
String locla, loclo;
// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (ss.available())
{
char c = ss.read();
// Serial.write(c); // uncomment this line if you want to see the GPS data flowing
if (gps.encode(c)) // Did a new valid sentence come in?
newData = true;
}
}
if (newData)
{
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
locla = String(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
loclo = String(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
Serial.println("LAT= "+locla+" LON= "+loclo); // удалить после настройки
if(gpson == false){
gpson = true;
transmit(0,"917"); // инициализация выполнена
} else {
if((lat != locla)or(lon != loclo)){
transmit(0,"902"); // тревога
lat = locla;
lon = loclo;
}
}
}
}
void loop()
{
if(alarm == true){
Serial.println("ALARM");
digitalWrite(LedPin, LOW);
delay(5000);
get_gps();
alarm = false;
}
if(gpson == false){
delay(5000);
get_gps();
} else {
if(snr == false){
if(count < slp){
count++;
sleepNow();
} else {
snr = true;
count = 0;
Serial.println("WAKE");
digitalWrite(LedPin, LOW);
sonar(); //включаем сонар
}
}
}
}
А вот схема![]()
С зависанием вроде разобрался, у меня в функции sonar вместо void стояло String. Наверно осталось от старой, где она возвращала расстояние. А вот глюк с расстояниями так и остался...
А вот что выводится в консоль
есть такое дело, сам наступил на эти грабли, после подачи питания на HC-SR04 нужно выждать около 1 секунды, сделать замер, игнорировать его, выждать 100мс и произвести новый замер, он будет валидный.
Спасибо за информацию, так оно и есть. Даже 10 замеров с вычислением среднего арифметического делать не нужно. Только интервалы колеблются для каждого из сонаров. Для одного 100мс нормально, а для другого 400 ставить пришлось.
кстати про враньё, у меня он лежит на полке и смотрит в крышу, слева дистанция в сантиметрах http://savepic.net/8531887.htm