Ультразвуковые датчики (HC-SR04) обычно используются для нахождения расстояния от объекта до определенной точки. Эту задачу измерения расстояния достаточно легко выполнить с помощью платы Arduino. Но в этой статье мы постараемся сделать нечто другое. Мы попытаемся определить расстояние между двумя ультразвуковыми датчиками, один из которых будет работать в качестве передатчика, а другой – в качестве приемника. Используя этот механизм мы, к примеру, можем отслеживать местоположение одного передатчика с помощью нескольких приемников. Эта технология называется триангуляцией и она может быть использована в системах автоматической доставки (транспортировки, парковки грузов) с помощью роботов и других подобных применениях.
В целом, эта технология достаточно хорошо известна и можно использовать подобные готовые решения, однако мы несколько усложнили традиционный подход. Но сразу скажем что использованная нами технология не претендует на абсолютную точность и может работать с "некоторой натяжкой". Поэтому для использования в реальных системах ее, скорее всего, следует доработать.
Необходимые компоненты
- Две плата Arduino (любые модели) (купить на AliExpress).
- Два ультразвуковых датчика HCSR04 (купить на AliExpress).
Работа схемы
Схемы передающей и приемной части нашей системы представлены на следующем рисунке.
На первый взгляд может показаться что не обязательно соединять все контакты ультразвуковых датчиков с платой Arduino потому что в каждой части мы будем использовать как бы половину датчика. Но давайте не будем спешить с выводами и посмотрим статью дальше.
Как работает на самом деле ультразвуковой датчик HC-SR04
Использование этого датчика вместе с Arduino представлено в этой статье, однако более подробно принципы его работы рассмотрены в статье про его применение совместно с микроконтроллером AVR.
Временные диаграммы работы датчика представлены на следующем рисунке.
Датчик имеет контакты Trigger и Echo, которые используются для измерения расстояния как показано на представленных диаграммах. Сначала мы должны подать запускающий в работу датчик импульс длительностью 10 мкс на контакт Trigger, после этого датчик излучает в пространство серию из 8 ультразвуковых импульсов. Эти импульсы отражаются от препятствия и возвращаются обратно к датчику.
На временных диаграммах показано, что после того как приемник осуществит прием этих импульсов датчик устанавливает напряжение высокого уровня на контакте Echo на длительность, равную времени распространения ультразвуковой волны до препятствия и обратно.
Но мы более детально исследовали работу этого датчика и установили, что датчик не ждет возвращения ультразвуковой волны назад. Он устанавливает напряжение высокого уровня на контакте Echo сразу после излучения серии импульсов и снимает это напряжение (то есть возвращает состояние контакта в 0) после того как ультразвуковая волна вернется назад. Поэтому правильные временные диаграммы работы этого датчика должны быть такими, какими они показаны на следующем рисунке.
Как сделать так чтобы датчик HC-SR04 работал только как передатчик
Как следует из представленных временных диаграмм для этого нужно объявить контакт Trigger выходным контактом и подать на него напряжение высокого уровня в течение 10 микросекунд. Это приведет к тому что датчик начнет излучать серию ультразвуковых импульсов. То есть всегда, когда нам нужно задействовать датчик HC-SR04 только в качестве передатчика, нам нужно просто подать импульс высокого уровня длительностью 10 мкс на его контакт Trigger.
Как сделать так чтобы датчик HC-SR04 работал только как приемник
Как следует из временных диаграмм прямым способом мы это сделать не можем поскольку мы не можем непосредственно управлять появлением сигнала на контакте Echo. Но мы можем использовать следующий "лайфхак". Мы можем просто заклеить передающую часть датчика непрозрачной лентой как показано на рисунке ниже, что приведет к тому что ультразвуковая волна не будет излучаться и, следовательно, не будет влиять на состояние контакта Echo.
Теперь чтобы подать на контакт echo напряжение высокого уровня нам теперь просто нужно подать импульс длительностью 10 мкс на контакт-"пустышку" trigger. Теперь напряжение низкого уровня появится на контакте echo только тогда, когда наш приемный датчик примет ультразвуковую волну от нашего передающего датчика.
Измерение расстояния между двумя ультразвуковыми датчиками HC-SR04
Теперь, когда мы знаем как заставить работать этот датчик только в качестве передатчика и только в качестве приемника, нам нужно просто излучить ультразвуковую волну передающим датчиком, принять ее приемным датчиком и измерить время прохождения волны от передатчика до приемника. На первый взгляд все кажется просто, но на самом деле "напрямую" это не работает.
Проблема здесь заключается в том, что приемный датчик не знает момент времени когда передающий датчик начал передавать ультразвуковую волну. А без знания этого момента времени мы не можем определить расстояние. Чтобы решить эту проблему необходимо чтобы на контакте Echo приемного датчика устанавливалось напряжение высокого уровня когда передающий датчик только начал передавать ультразвуковую волну. Другими словами, передающий и приемный модули должны запускаться в работу (при помощи подачи импульса 10 мкс на их контакты trigger) в одно и то же время. Этого можно достичь с помощью использования метода, показанного на следующем рисунке.
На представленном рисунке Tx представляет передающий датчик, а Rx – приемный. Как можно видеть из диаграммы, передающий датчик должен просто передавать ультразвуковые волны периодически, с известной задержкой между ними.
В приемном датчике мы должны в какой-нибудь момент времени (случайным образом) подать на контакт trigger высокий уровень. И мы должны оставить напряжение высокого уровня на нем до тех пор пока на контакте echo не появится напряжение низкого уровня – а это случится только когда приемный датчик примет ультразвуковую волну от передающего датчика. То есть как только на нем появится напряжение низкого уровня мы можем предположить что передающий датчик только что излучил волну. Теперь, когда на контакте echo появилось напряжение низкого уровня, мы можем просто подождать известную нам задержку и затем подать напряжение высокого уровня на контакт trigger приемного датчика. Таким образом, передающий и приемный датчики войдут в синхронизм и после этого мы непосредственным образом можем измерять длительность импульса на контакте echo с помощью функции pulseIn() и затем рассчитывать расстояние.
Объяснение программы для передающего датчика
В передающем датчике нам все что нужно делать – это просто запускать в работу датчик (чтобы он излучал ультразвуковую волну) через периодические интервалы времени.
1 2 3 |
digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); |
Представленные строки кода позволяют сформировать импульс длительностью 10 мкс на контакте trigger датчика.
Объяснение программы для приемного датчика
В приемном датчике мы должны заклеить передающую часть непрозрачной лентой (как обсуждалось ранее). И затем мы должны просто использовать описанный ранее в статье метод чтобы приемный датчик синхронизировался с передающим датчиком.
1 2 3 4 5 |
Trigger_US(); while (digitalRead(echoPin)==HIGH); delayMicroseconds (10); Trigger_US(); duration = pulseIn(echoPin, HIGH); |
Сначала мы запускаем в работу датчик с помощью функции Trigger_US() и затем в цикле while ждем до тех пор пока на контакте echo будет напряжение высокого уровня. Как только на контакте echo появится напряжение низкого уровня мы ждем заранее известную нам задержку – она должна быть в интервале от 10 до 30 микросекунд (можно экспериментально определить наилучшее значение для этой задержки или использовать прием описанный нижу в данной статье). После этой задержки мы снова запускаем в работу датчик с помощью функции Trigger_US() и затем используем функцию pulseIn() чтобы определить длительность импульса.
И затем по известной формуле мы можем рассчитать расстояние.
1 |
distance= duration*0.034; |
Работа проекта
Сделайте все необходимые соединения в схеме. Заклейте передающую часть приемного датчика. Загрузите коды программ (приведены в конце статьи) в обе платы Arduino. Откройте окно монитора последовательной связи (serial monitor) в приемной части системы и вы должны увидеть как в нем будет печататься расстояние между датчиками. Более подробно этот процесс можно посмотреть на видео, приведенном в конце статьи.
Примечание: метод может работать неточно, улучшению его работы может помочь улучшенная идея по синхронизации датчиков, представленная далее.
Улучшенная идея по калибровке датчиков используя известное расстояние
Одним из главных недостатков описанного метода является то, что мы предполагаем что на контакте Echo появляется низкий уровень сразу после того как передатчик передающего датчика излучил волну. Однако это не совсем так поскольку волне нужно время чтобы она "долетела" от передающего датчика до приемного. Следовательно, скорее всего, в результате этого метода передающий и приемный датчики не достигнут идеального синхронизма.
Чтобы преодолеть этот недостаток мы можем сначала откалибровать датчик используя известное расстояние – в этом случае мы можем точно определить время распространения волны от передающего датчика до приемного. Давайте обозначим это время как дельта D как показано на следующем рисунке.
Теперь мы точно можем определить через какое время нам нужно подавать напряжение высокого уровня на контакт Trigger приемного модуля чтобы достичь идеальной синхронизации с контактом trigger передающей части. Эту длительность можно рассчитать как известная задержка минус дельта D. К сожалению, из-за недостатка времени мы не смогли протестировать эту идею, но будем признательны если вы отпишитесь здесь в комментариях если успешно ее протестируете.
Исходный код программы
Код программы для приемной части
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
const int trigPin = 9; const int echoPin = 10; // defines variables long duration; int distance, Pdistance; void setup() { pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output pinMode(echoPin, INPUT); // Sets the echoPin as an Input Serial.begin(9600); // Starts the serial communication } void loop() { Pdistance=distance; Calc(); distance= duration*0.034; if (Pdistance==distance || Pdistance==distance+1 || Pdistance==distance-1 ) { Serial.print("Measured Distance: "); Serial.println(distance/2); } //Serial.print("Distance: "); //Serial.println(distance/2); delay(500); } void Calc() { duration=0; Trigger_US(); while (digitalRead(echoPin)==HIGH); delay(2); Trigger_US(); duration = pulseIn(echoPin, HIGH); } void Trigger_US() { // Fake trigger the US sensor digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); } |
Код программы для передающей части
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// defines pins numbers const int trigPin = 9; const int echoPin = 10; // defines variables long duration; int distance; void setup() { pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output pinMode(echoPin, INPUT); // Sets the echoPin as an Input Serial.begin(9600); // Starts the serial communication } void loop() { // Sets the trigPin on HIGH state for 10 micro seconds digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); delay(2); } |
Забавно. Если требуется измерить расстояние до устройства, нужно задействовать радиоканал, дающий запрос, ответом будет ультразвуковой импульс а дальше просто математика.Но вот не хочется заклеивать дальномер, на базе это возможно а вот юниту он и для измерения расстояния, не лепить же два устройства, одно инвалид?
Игорь, эта статья весьма специфическая, конечно. Но, может быть, кому-нибудь пригодится
странная специфичность. Проблема поиска устройства и базы или понимание нахождения нескольких устройств относительно друг друга, если нет возможности задействовать GPS именно сводится к расчёту расстояния, ну а потом направления. Этот способ шаг к решению задачи расстояния, витиевато конечно. Конечно можно всё свалить на инерционные датчики но это совсем другое, по этому весьма интересно, жаль, что добрые китайские товарищи не создают отдельных модулей для этих целей...
Ну, может быть, у них все еще впереди ))