Thursday, December 22, 2011

Первое чувство или ультразвуковой дальномер HC-SR04

Очень часто самым первым сенсором с которого начинают многие является инфракрасный датчик. Он очень прост в исполнении и может быть сделан буквально на нескольких элементах. Инфракрасный диод (как в пульте от телевиз), какой-либо приемник для этого диода (например серии TSOP), пара резисторов и у вас в руках мог бы быть простейший датчик расстояния.
Я решил пойти другим путем и первым "органом чувств" для будущего робота был выбран ультразвуковой дальномер HC-SR04.
Описание HC-SR04
HC-SR04  - это помещенные на одну плату приемник и передатчик ультразвукового сигнала. Динамик и микрофон, по сути, только для неслышного человеческому уху ультразвука. Кроме самих приемника и передатчика на плате находится еще и необходимая обвязка, чтобы сделать работу с этим датчиком простой и непренуждченной. 
Датчик обладает низким энергопотреблением, что также является немаловажным параметром в случае с мобильными роботами не привязаных  к розетке. Питается HC-SR04 от 5V, что тоже удобно в случае, когда вы подключаете его к arduino.

Принцип работы датчика очень простой: когда микроконтроллер сообщает ему (как это делать опишу дальше), что надо бы получить данные, датчик генерирует ультразвуковой сигнал и начинает "слушать". Когда сигнал, отраженный от какого-либо объекта, возвращается к датчику - HC-SR04 посылает логическую единицу микроконтролеру и дальше это уже дело контроллера. Смысл в том, что можно измерить время, за которое сигнал вернулся, и потом при помощи несложных вычислений получить расстояние.
У HC-SR04 есть четыре контакта. Два из них (находятся по краям) - это питание микросхемы (обозначены VCC и GND). По середине: один контакт триггера (обозначен trig), а второй контакт Echo (так и обозначен Echo, вы уж простите но я не знал как его обозвать).

Где купить?
Лично я заказывал на ebay, обошлись два таких датчика (две платы) в 9$ с доставкой. Брал два - так как была идея их объединить.

Как использовать HC-SR04?
Переходим к более интересным вопросам, а именно "как эту штуку прикрутить к arduino?".
Как и все, что я умею делать - очень просто. Единственное, для демонстрации я еще использовал светодиод - он часть вовсе не обязательная, но, если все же решитесь повторять все точь-в-точь, тогда хватайте светодиод и резистор на 470 Ом (я использовал 510Ом, на самом деле не такая большая разница, результат будет тот же). Светодиод будет гореть ярче и ярче по мере того, как мы подносим что-то к сенсору. Схема у меня выглядит вот так:

Что тут сделано?

  1. Подведено питание к макетной плате (красный и черный провода). Питание подведено к  сенсору. Кроме того катод (короткий вывод диода) подключен к земле.
  2. Желтым проводом диод подключен к PWM (ШИМ) выводу номер 9, по этому проводу мы будем подавать напряжение на наш диод. В зависимости от величины этого напряжения диод будет менять интенсивность этого освещения. Диод должен быть подключен через резистор обязательно. Иначе мы рискуем испортить не только диод но и нашу Arduino. Резистор нужен для того, чтобы ограничить ток на диоде до приемлемой величины. Дело в том, что внутреннее сопротивление диода очень низкое и если не использовать резистор, то через диод ломанется такой ток, который попросту нафиг спалит и диод и контроллер.
  3. Белый провод подключен к триггеру нашего сенсора с одной стороны и к 10-му выводу Arduino Mega (можно использовать любой цифровой выход). Через него будет отправляться "запрос" от нашего контроллера к HC-SR04. 
  4. Зеленым проводом соединены 11-й вывод нашей Arduino (может быть использован любой цифровой вход) и ножка echo сенсора. По этому входу наш микроконтроллер будет ожидать сигнала от сенсора.

Схема как всегда проста до нельзя. Но в последствии я планирую описывать все более сложные схемы, по мере того, как буду в них разбираться сам. Перейдем к программной части:

Прошивка контроллера
Логика будет очень простой - измеряем расстояние до препятствия с помощью сенсора и чем меньше это расстояние - тем выше уровень выставляем на светодиоде. От слов в делу, код:
int ledPin = 9;
int trigPin = 10;
int echoPin = 11;

long distance;
int ledLevel; 

void setup()  {
  pinMode(trigPin,OUTPUT);
  pinMode(echoPin,INPUT);
}

void loop()  { 
  distance = getDistance();
  ledLevel = (int) (distance*10)<=255?255-distance*10:0;
  analogWrite(ledPin, ledLevel);
  delay(50);
} 

long getEchoTiming() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin,HIGH);
  return duration;
} 

long getDistance() {
  long distacne_cm = getEchoTiming()/29/2;
  return distacne_cm;
}

Я решил не использовать сторонних библиотек, которые на самом деле есть, пусть и не в стандартном пакете Arduino IDE. Сделал я это специально - таким образом можно лучше понять как работает сам датчик.
Опишем функции:


  • setup() - тут все очень просто, мы просто показываем контроллеру то, что ножка номер 10 будет использована как выход, а ножка номер 11 - как вход. Указывать ножку номер 9-ть не надо, так как она подразумевает изначально использование в таком режиме (ШИМ выход). Про ШИМ (или PWM) расскажу как-нибудь отдельно, если будут силы. Сейчас примите это просто за выход, на котором можно выставлять напряжение в промежутке от 0 до 5 вольт.
  • getEchoTiming() - это самая интересная функция в которой твориться вся магия. В начале мы выставляем на нашем триггере логический ноль (digitalWrite(trigPin, LOW);). Делается это для того, чтобы можно было быть уверенным, что никакая другая часть программы не установила (быть может по случайности) на этот вывод логическую единицу. После этого мы ждем две микросекунды (очень-очень мало) delayMicroseconds(2); но этого более чем достаточно, чтобы "начать с нуля", так сказать. После этого, мы устанавливаем логическую единицу на 10 микросекунд (digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW);). Включаем, ждем 10 микросекунд, выключаем. Согласно спецификации сенсора это именно та минимальная продолжительность импульса на триггере, после которой генерируется ультразвуковой сигнал. После этого мы начинаем "слушать эфир" long duration = pulseIn(echoPin,HIGH);. Функция pulseIn(...) возвращает long значение в микросекундах через то время, когда на указанном входе появится логическая единица (в нашем случае это вход номер 11). Как только на входе 11 появляется логическая единица - этот метод возвращает количество микросекунд за которое сигнал вернулся.
  • getDistance() - достаточно простая функция. Она возвращает расстояние в сантиметрах до объекта перед сенсором. Для этого, она получает значение от только что описанного  getEchoTiming()и делит его на скорость звука. Стоит отметить, что скорость звука в воздухе зависит от температуры, но так как у меня нету датчика температуры я пренебрег этой погрешностью. Помимо деления на скорость звука значение еще делится на 2, потому что ультразвук от сенсора преодолевает расстояние до препятствия и обратно.
  • loop() - это стандартный и обязательный метод при программировании под Arduino. Он циклически запускается (после окончания всегда начинает с начала). В нем тоже все просто у нас. Берется расстояние distance = getDistance();, после чего вычисляется уровень который подать на светодиод ledLevel = (int) (distance*10)<=255?255-distance*10:0;. Стоит сразу оговориться, аналоговый уровень в arduino задается как значение в промежутке между 0 и 255. Как можно увидеть я умножаю расстояние на 10 чтобы перевести его в миллиметры. Сделано это для большей наглядности, не более того. После того как мы получаем уровень для светодиода, мы сразу же выставляем его на выход номер 9-ть analogWrite(ledPin, ledLevel); и ожидаем 50 миллисекунд до следующего старта функции loop().
Вот собственно и все, программа готова.

Запускаем
Собственно все, что нам осталось сделать - это подключить USB провод к Arduino, залить вышеупомянутую прошивку в контроллер и начинать экспериментировать.