Дальномер AJ-SR04M - укрощение строптивого

step962
Offline
Зарегистрирован: 23.05.2011

Прелюдия:

Уже больше года пылились у меня в закромах два вышеупомянутых модуля, заказанных в свое время на Aliexpress для использования в запланированной системе автоматического сбора дождевой воды. В свою очередь эта система, конструктивно представляющая собой водонапорную башню (две бочки для сбора дождевой воды внизу под водосточными трубами и две — на высоте около 5 метров — на потолке второго этажа бани), станет в будущем частью автоматизированной системы полива стратегически важных грядок на дачном участке. Это не только грядки в теплице, но и те, что находятся под открытым небом, но требуют обильного полива. Уж больно утомили два последних засушливых сезона, вынуждавших практически ежедневно стоять по полтора часа над грядками, разбрызгивая воду до полного ее исчерпания в неглубоком колодце, доставшемся от прежнего хозяина участка.

Людия

Если верить Интернетам, программирование этого модуля практически не отличается от обращения с его широко распространенным собратом (HC-SR04).  

int trigPin = 10;
int echoPin = 11;

void setup() {
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() { 
  int duration, distance;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH); 
  distance = duration / 58;
  Serial.print(distance);
  Serial.println(" cm");
  delay(100);
}

Некоторое отличие лишь в получаемых результатах, ибо датчик AJ-SR04M нет смысла приближать к препятствию ближе, чем на 18 см. Это плата за объединение передатчика и приемника в единое целое - требуется некоторое время для завершения переходных процессов из режима передачи в режим приема.

Первая попытка, она же первый облом:

Первый блин оказался комом. Датчик был без труда установлен в подготовленном для этой цели кронштейне, размещенном примерно в четверти метра над зеркалом воды в наполненной до краев бочке. Первое значение снять, измеренное рулеткой значение примерно соответствует ему (отклонение в 1 см не в счет - это легко списать погрешность измерений). Вычерпываю из бочки воду, провожу измерения и скучнею с каждым новым замером - результаты от датчика все больше отстают от того, что замерено рулеткой, пока вообще не перестают изменяться. Что-то явно пошло не так... Сам датчик явно в порядке, ведь проводившиеся незадолго перед этим измерения до стены давали точные результаты. Ошибка, по-видимому, кроется в схеме измерения. Остается найти, где именно. Как говаривал Семен Семенович Горбунков - "будем искать".

step962
Offline
Зарегистрирован: 23.05.2011

Нашел бумажку с записью результатов измерений:

Рулетка Датчик
36 35
50 45
57 45 (иногда проскакивает 50)
63 51 (иногда проскакивает 52, 41, 61)

С показания 51 датчик перестал следить за снижением уровня воды в бочке.

rkit
Offline
Зарегистрирован: 23.11.2016

Интересно, наступит ли когда-нибудь тот день, когда вы все уже прекратите пытаться сделать измерительный прибор из парктроника? Как и вообще разводить телеметрию в сраном баке для полива. Каждый месяц новый страдалец приходит с этой гениальной идеей.

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Поставь сортирный клапан и не насилуй мосх.

step962
Offline
Зарегистрирован: 23.05.2011

Злые вы. И нетерпеливые. Немного терпения - все будет хорошо. Все поженятся. Проживут долго и счастливо. И умрут в один день.

А пока:

Вторая попытка, тоже безуспешная

 После некоторого раздумья я таки решил набраться мудрости у изготовителей датчика и изучить "this fucking manual". Ну а там естественным образом наткнулся на диаграмму направленности и понял, что шансов заглянуть в бочку этим датчиком в его девственном состоянии у меня нет:

Датчик вполне себе неплохо "видит" препятствия и на углах вплоть до 90. Стало быть, при первой попытке датчик (относительно) правильно определял расстояние до тех пор, пока стенки бочки особо не выделялись над поверхностью воды. А по мере вычерпывания сигнал, отраженный от стенок бочки, становился все более заметным и вносил все больший вклад в регистрируемое датчиком эхо. А с некоторого момента полностью забил собой отражение от воды (отодвигавшееся все больше и больше вправо по оси времени).

Вот такую модель построил мой "изнасилованный мосх" и выдал рекомендацию сузить каким-то образом "широкоугольное" зрение строптивого датчика. Первая мысль, пришедшая в голову - засунуть датчик в трубку небольшого диаметра и отсечь таким образом боковые части лепестка направленности.

Сказано - сделано. Датчик был помещен в отрезок канализационной трубы диаметром 40 мм и закреплен там примерно в 5 см от обреза. Нести полученную конструкцию на дачу "для проверки в полевых условиях" не пришлось. На всех направлениях и на любых расстояниях от препятствий Ардуина стабильно выводила в терминал одно и то же значение - пресловутые 18 см. Что для этого датчика является индикатором расположения ближе минимальной дистанции обнаружения. Труба оказалась не только канализационной но и громогласной - с удовольствием поглощала уходящую в стороны часть излучаемой энергии и сама становилась излучателем еще долго после окончания излучения.

"Насилие над мосхом" продолжилось, теперь в поисках борьбы с наведеным излучением трубы.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ну то, что канализационная труба хорошо отражает ультразвук, вещь достаточно очевидная. Если уж было желание попытаться как-то избавиться от влияния боковых поверхностей, единственный вариант - труба из материала хорошо поглощающего ультразвук.

Притом, очень хорошо.

Порядок "коэффициента поглощения", исходя из положения бокового лепестка на 3 м и минимальной дальности 0.18 я бы оценил в (3.0/0.18)^2=280. Честно говоря, не готов сказать навскидку, существуют ли такие в природе.

step962 пишет:

Злые вы. И нетерпеливые. Немного терпения - все будет хорошо. Все поженятся. Проживут долго и счастливо. И умрут в один день.

Может, не стоит тянуть кота за хвост, и следует сразу переходить к последнему пункту?

rkit
Offline
Зарегистрирован: 23.11.2016

step962 пишет:

И нетерпеливые.

Вот бы взять эту терпеливость, да к поливу грядок приложить, вместо забивания гвоздей отверткой.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

У меня система водоснабжения несколько другая, но может сама идея и использованные компоненты помогут. 

На даче жены много лет назад сделана система подачи воды из колодца. Уровень воды в колодце весной выше уровня земли (родник вода холодная чистая, вытекает через трубу на уровне земли) Ближе к концу лета уровень воды падает до небольшой лужи на дне колодца, бывает высыхает совсем.  Когда воды мало откачивается очень быстро, и насос оголялся,  но и заполняется - быстро.

В колодце подвешен насос для чистой воды Gardena cо встроенной  автоматикой, датчики  кондукторного типа. Опустилась ниже среднего датчика - выключился, поднялось  выше верхнего - включилось.

Gardena качает воду в бочку 1.5 тонны. Наверху бочки стоит тоже трех-электродный датчик кондукторного типа от Овен. Датчик подключен к блоку автоматики тоже от Овен САУ-М2, который в зависимости от уровня в бочке включает Гардену  (поддерживает максимальный высокий уровень в бочке, естественно с небольшим гистерезисом, чтобы Гардену не мучить.  

Ну а дальше насосная станция, разводка по потребителям.

Работает все это уже очень давно, никаких проблем.  У Овена в принципе и измерители уровня есть, посмотрите, может найдете.

Я тоже измеритель уровня хотел в колодец, но ограничился этой автоматикой, все равно повлиять на уровень не могу.

Если напряжение на Гардену САУ-М2 дает и не снимает его за 1 час - сигнал, что нет воды в колодце, или бочка заполняется с пустой - весной.   

step962
Offline
Зарегистрирован: 23.05.2011

andriano пишет:

...

единственный вариант - труба из материала хорошо поглощающего ультразвук.

Притом, очень хорошо.

...

Ну, как говорится - бинго. Так что

Третья попытка - удачная

Я не стал искать трубу из супер-пупер поглощающего материала. У меня перед глазами пронеслись сонмы микрофонов на трибунах - все как один в поролоновых чехлах, призванных отсекать помехи от ветра. В памяти всплыла и теплоизоляция для труб, представляющая собой ту самую поролоновую трубу. Солидную такую, толстостенную, но при этом абсолютно нежесткую. Да еще и с разрезом вдоль. Но вот если эту изоляцию не надеть на трубу, а вставить вовнутрь, то... Сказано - сделано: во время следующего заезда в Мерлен я подобрал пару изоляция+труба такую, чтобы изоляция с натягом входила вовнутрь. Получилось труба пятидесятка (дватцатисантиметровый отрезок) и изоляция 28/13 (внутренний диаметр 28 мм, толщина стенки 13). Приехал домой, забил изоляцию в трубу - последние сантиметры давались со значительным трудом. Вставил датчик. Получилась вот такая конструкция:

Помня облом, случившийся при второй попытке, я проверил получившуюся конструкцию, не отходя от десктопа - в терминал выводились числа, примерно соответствующие расстоянию до того препятствия, на который я направлял датчик. Можно было выходить в поле...

Дальше - рутинные действия:

Закрепляю датчик над бочкой, заполненной до перелива. Подключаю его к ардуинке, снабженной bluetooth-модулем и соответствующим скетчем. Устанавливаю связь со смартфоном, на котором крутится приложение MoDyz, позволяющего использовать смартфон в качестве дисплея для ардуинки, и начинаю записывать в табличку показания с датчика и текущее расстояние от среза трубы до водной поверхности, понемногу вычерпывая воду:

Датчик От среза трубы до воды
26 23
30 28
35 32
42 40
48 46
55 52
... и т.д.
104 101

Все. Уперлись в дно. Во всем диапазоне измерений разница составляла 2-3 см, что соответствовало расстоянию от датчика до среза трубы плюс погрешность измерения рулеткой. Погрешность не более +/- 1 см, что для стандартной 200-литровой бочки составляет 4-5 л. Точность более чем достаточная для проектируемой мной системы водосбора и -распределения.

Можно двигаться дальше.

step962
Offline
Зарегистрирован: 23.05.2011

В процессе принуждения дальномера к корректному измерению уровня воды в бочке скетч обрастал дополнительными функциями и разросся до размера в полторы сотни строк. В нем появился блок функций для работы с двумя последовательными портами: аппаратный используется для отладки (ввод/вывод через терминал Arduino IDE), а программный (SoftwareSerial) - для подключения Bluetooth-модуля и общения через него со смартфоном.

    /* скетч для проверки работы ультразвукового дальномера AJ-SR04M
     * с выводом информации на дисплей Android-устройства
     */
// библиотека для обеспечения работы с Bluetooth-модулем, обеспечивающим связь с дисплеем Android-устройства
#include <SoftwareSerial.h>

// библиотека, автоматизирующая процесс создания управляющих строковых последовательностей
#include <mdwriter.h>
#include <mdsender_bt.h>

// номера пинов, используемых модулем AJ-SR04M
#define TRIG_PIN 3
#define ECHO_PIN 4

SoftwareSerial mySerial(7, 6); // RX, TX
MD_Sender_BT mdScout;

String cmdBuffer,sResponse;
short sceneNum,idx;
int distance, distances[10];
unsigned long nextMillis;

void setup() {
  Serial.begin(9600);
  Serial.println("+--------== avr_MD_AJ-SR04M ==--------+");
  Serial.println("|       testing AJ-SR04M module       |");
  Serial.print  ("| Trigger pin: "); Serial.println(TRIG_PIN);
  Serial.print  ("|    Echo pin: "); Serial.println(ECHO_PIN);
  Serial.println("+-------------------------------------+");
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  mySerial.begin(9600); // инициализация и настройка скорости програмного последовательного порта
  sResponse = "";
  cmdBuffer = "";
  sceneNum = 0; // вывод результатов измерений на смартфон отключен
  nextMillis = millis();
  // инициируем массив считанных данных
  for(int i=0;i<10;i++) distances[i]=i;
}

void loop() {
  if((long)(nextMillis-millis())<=0) {  // чтение и вывод показаний дальномера каждую секунду
    nextMillis = nextMillis + 1000;
    getDistance();
  }
  readSerialData();
}

void getDistance() {
  int duration;
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  duration = pulseIn(ECHO_PIN, HIGH);
  distance = duration / 58;
  idx--; if(idx<0) idx=9;

  distances[idx] = distance;
  Serial.print(distance);
  Serial.print(" cm  - ");
  Serial.println(cmdBuffer);
  if(sceneNum==1) drawScene();
}

void addCmdString(String sCmd) {
  sResponse += sCmd;
  if(sResponse.length()>100) sendString(sResponse);
}

void drawScene() {
  String sDistance;
  char dist[8];
  int i, y, y0=170;
  boolean b;
  if(sceneNum==1) { // сцена уже отрисована, делаем только вывод текущего показания дальномера
    sDistance = String(distance)+" см";
    addCmdString(mdScout.setTextSize(30));
    addCmdString(mdScout.setTextColors(C_BLUE,C_LTGRAY));
    addCmdString(mdScout.fillRectangle(70,y0-30,390,y0+105,C_LTGRAY));
    addCmdString(mdScout.fillRectangle(400,y0-30,530,y0+300,C_LTGRAY));
    addCmdString(mdScout.outTextR(370,y0+10,"Расстояние:"));
    addCmdString(mdScout.setTextSize(50));
    addCmdString(mdScout.outTextR(370,y0+85,sDistance));
    addCmdString(mdScout.setTextSize(20));
    y=y0; b=false;
    addCmdString(mdScout.setTextColors(C_YELLOW,C_RED));
    for(i=idx;i<10;i++) {
      addCmdString(mdScout.outTextR(520,y,String(distances[i])));
      y=y+30;
      if(!b) {addCmdString(mdScout.setTextColors(C_BLUE,C_LTGRAY)); b=true;}
    }
    for(i=0;i<idx;i++) {
      addCmdString(mdScout.outTextR(520,y,String(distances[i])));
      y=y+30;
    }
  }
  else { // первый вызов функции - рисуем статические элементы сцены и включаем вывод результатов измерений на смартфон
    sceneNum = 1;
    sResponse = "";
    addCmdString(mdScout.setDisplayColors(C_BLACK,C_LTGRAY));
    addCmdString(mdScout.setTextSize(30));
    addCmdString(mdScout.setTextColors(C_RED,C_LTGRAY));
    addCmdString(mdScout.outTextC(270,75,"Тестирование"));
    addCmdString(mdScout.outTextC(270,120,"модуля AJ-SR04M"));
  }
  sendString(sResponse);
}

void showHelp() {
  Serial.println("Help information");
  Serial.println("drw    drawing scene on Android-display");
  Serial.println("drwend end of drawing scene on Android-display");
}

void readSerialData() {
  char c;
  if (mySerial.available()) {
    c = (char)mySerial.read();
    Serial.write(c);
    if (c==0x0A || c==0x0D) interpreteCommand();
    else cmdBuffer=cmdBuffer+c;
  }
  if (Serial.available()) {
    c = (char)Serial.read();
    if (c==0x0A || c==0x0D) interpreteCommand();
    else cmdBuffer=cmdBuffer+c;
  }
} // of readSerialData

void sendString(String s) {
  Serial.print("Send string via bluetooth: ");
  for(int i=0;i<s.length();i++) {
    mySerial.write(s.charAt(i));
    Serial.write(s.charAt(i));
  }
  mySerial.write('\r'); mySerial.write('\n');
  Serial.write('\r'); Serial.write('\n');
  sResponse = "";
} // of sendString

void interpreteCommand() {
  if(cmdBuffer.length()==0) return;
  if(cmdBuffer.equalsIgnoreCase("getprotocol"))       sendString("protocol=AJ-SR04M");
  else if(cmdBuffer.equalsIgnoreCase("help"))         showHelp();
  else if(cmdBuffer.equalsIgnoreCase("drw"))          drawScene();
  else if(cmdBuffer.equalsIgnoreCase("enddrw"))       sceneNum=0; // отключаем вывод результатов измерений на смартфон
  else {
    Serial.print("Unknown command: <");
    Serial.print(cmdBuffer);
    Serial.println(">");
  }
  cmdBuffer = "";
} // of interpreteCommand

Смартфон в будущем проекте системы водосбора (дождевая вода плюс подкачка из колодца), подъема воды в водонапорные бочки, установленные на высоте около 5 метров на потолке мансардного этажа, и орошения (капельный полив в теплице и на высоких грядках) будет использоваться в качестве переносного терминала для мониторинга ситуации с запасами воды и ее движением во всех элементах системы и настройки логики работы перекачивающих насосов.

Приложение для смартфона - Introductory MoDyz - с июня этого года доступно для скачивания в магазине Google Play. Оно превращает смартфон/планшет в дисплей высокого разрешения, на котором с помощью набора команд можно рисовать все, что душе угодно. Так же, как и на обычном дисплее, только с существенной экономией ограниченных ресурсов микроконтроллера: для работы с ним потребуется пожертвовать лишь двумя выводами (для подключения Bluetooth-модуля), кроме того, экономится и программная память, так как графическая библиотека как таковая отсутствует. Все связанные с графикой вещи реализованы на стороне смартфона, на долю микроконтроллера остается только коммуникация - отправка команд графики / создания органов управления, прием команд от органов управления и реакция на них.

Построением изображения (отправкой соответствующих команд) в скетче занимается функция drawScene() (строки 72-109), а реакцией на команды от смартфона - interpreteCommand() (строки 143-155). В процессе приручения дальномера ничего, кроме вывода текста, не потребовалось, поэтому использовался весьма ограниченный набор функций:

- задание цвета и размера шрифта (функции setTextColors() и setTextSize())

- вывод текста (функции outTextC() и outTextR())

- заполнение прямоугольников (подготовка области для вывода текста - функция fillRectangle())

Результат их применения - на картинке: