При разработке собственных роботов часто встает проблема выбора датчиков для обнаружения препятствий на пути робота. Статей посвященных тому как собрать свой УЗ дальномер достаточно много и при желании и должном усердии вполне реально собрать его самостоятельно. Но зачастую личное время не резиновое, а изготовление и отладка всех датчиков и блоков требует уйму времени. Поэтому всегда в первую очередь рассматривается вариант прикрутить какую-нибудь готовую железяку и сэкономить кучу времени.
В нашем распоряжении оказалась достаточно хорошая вещь для мобильных роботов – ультразвуковая система парковки автомобиля. Задача таких систем измерение расстояния до объектов в зоне действия датчиков и информирование водителя об их положении. Основой являются 4 УЗ датчика с широким углом обзора + плата управления. Дальность измерений до 2.метров. Плата управляет всеми УЗ датчиками, а следовательно можно не бояться перекрестных помех между ними. Для отображения результатов измерения в комплектации предусмотрен выносной экран. В итоге за полторы тыс р. можно реализовать полноценную систему обнаружения препятствий с минимальными потерями времени.
Первичный осмотр показал, что базовая плата выполнена на микроконтроллере PIC, а выносной экран на малоизвестном 8-разрядном микроконтроллере.
Следующим этапом был анализ сигналов между этими двумя устройствами. Первичный анализ при помощи осциллографа позволил определить формат передаваемого на экран пакета (Рисунок 2). Обмен ведется однонаправлено каждые 0,5 сек, экран только принимает данные. Пакет состоит из стартового импульса, длинной в ~2.8 мс и последовательности из 33 импульсов, 1 или 0 в соответствующей длинны. Первый предназначен для измерения эталонной длительности нулевого импульса и далее 4 байта по 8 бит на каждый датчик. На рисунке зеленым цветом выделены биты, установленные в 1.

|
Рисунок 1 - Временная диаграмма пакета данных
|
Напоследок осталось связать ее с нашим микроконтроллером, который подключаем вместо штатного экрана (Рисунок 1). В результате мы должны получить копию того, что видим на экране парковщика.

Рисунок 2 - Структурная схема системы
Для перехвата пакетов была использована отладочная плата на базе контроллера Atmega16. Сигнальная линия была заведена на вход INT0 (PORTD2), плюс как положено были соединены общие линии плат. Любое изменение уровня на входе PD2 вызывает сооветствующее прерывание. Так же использован системный таймер 0 для измерения периодов времени. Таймер настроен на счет опорной частоты в 250КГц в случае переполнения (примерно 1 мс после старта) устанавливаеся флаг f. В штатном режиме переполнение будет происходить только за интервал времени между фронтами стартового импульса, т.к. при регистрации переднего фронта выполняется обнуление счетчика, а период информационных импульсов около 0,33 мс.
На практике старшие 2 бита не изменяются и они были использованы для определения длительности информационных импульсов. Начало пакета определяется по длинному импульсу.
Подпрограмма обработчика прерывания для сканирование пакета:
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
if (PIND.2) // прерывание вызвал передний фронт
{
TCCR0 = 0x03; //Если передний фронт
TCNT0 = 0x00; //Обнуляем таймер
f = 0; //Обнуляем флаг переполнения таймера
count++; //Прибавляем счетчик передних импульсов
}
else
{
if (f) // за время ожидания произошло переполнение счетчика
{
bits = 0; // Прерывание означает начало пакета, обнуляем все переменные
first[0] = 0;
first[1] = 0;
count = 1; // ставим счетчик принятых импульсов равным 1
}
if (count == 1 && !f) //задний фронт пришел первым –
count = 0; // попали на середину пакета сбрасываем счетчик,
if (count>1)
{
if (count<=3)
{
first[count-2] = TCNT0; //Записываем длины двух первых импульсов
min_len =((first[0] + first[1]) >> 1)+((first[0] + first[1]) >> 3); //Ищем среднее значение между первым и вторым импульсами после прерывания + ~10%
}
else
{ // все импульсы начиная с четвертого считаем информационными
bits <<= 1;// Сдвинуть на один разряд
if (TCNT0 > min_len) //Если длинна текущего импульса больше минимума
bits++; //Установить последний бит в единицу
if (count == 34) //Когда достигли конца пакета
{
out = bits; // Отправляем накопленный набор бит в буфер вывода(см. главный цикл)
count = 0; // Обнуляем счетчик фронтов
}
}
}
f = 0; //Обнуляем флаг прерывания
}
}
Так как в пакете содержится информация обо всех четырех дальномерах то нам необходимо выделить информацию о каждом из них.
Разделение пакета на четыре части
//Разделение двойного слова на четыре байта
x = (unsigned char *) & out; //адрестекущегобайта
for (i = 0; i < 4; i++){
lcd_gotoxy(i << 2, 0); //устанавливаем курсор на позицию (i*4,0)
lcd_putint_distance(*x); //Вызов функции для вывода на экранчик в текущей позиции
x ++; //Берем следующий байт
}
Таблица преобразования расстояний
| X | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 |
| L,м | 0 | 1.6 | 1.5 | 1.4 | 1.3 | 1.2 | 1.1 | 1.0 | 0.9 | 0.8 | 0.7 | 0.6 | 0.5 | 0.4 | 0.3 |
Вывод на экран удалось реализовать не использую операции с плавающей точкой что позволило значительно сократить объем HEX файла и повысить быстродействие кода.
Процедура вывода на экран:
// Integer to LCD
void lcd_putint_distance (unsigned char distance)
{
char out_str[4] = (unsigned char)"00\0\0"; //Выходнаястрока
if (distance != 0){
distance = (signed char) 23 - distance + 3; //Конвертируемдистанциювметры
itoa((int)distance,out_str); // Переводимвстрокудистанцию
if (distance >= 10) //Если дистанция больше десяти то целая часть не равна нулю
out_str[2] = out_str[1]; // Переносим вторую цифру на позицию после точки
else
{
out_str[2] = out_str[0]; // Переносим первую цифру за точку
out_str[0] = '0'; // заменяем ее нулем
}
out_str[1] = '.'; // Ставим на вторую позицию точку
lcd_puts(out_str);
}
else //Если дистанция равна нулю то расстояние в метрах определить не удалось
{
lcd_puts("--");
}
}
Рисунок 3 - Экспериментальный стенд для отладки программы и осцилограмма пакета.
Рисунок 4 - Дублирование показаний штатного экрана
В результате получаем систему измерения расстояний по 4 азимутам с разрешением 0,1 м и частотой обновления 2 Гц. Характеристики системы конечно же далеки от идеала, но в итоге за 1500 р мы получаем полноценную систему обнаружения препятствий для своего мобильного робота в дальней зоне, например домашнего робота пылесоса.
Авторы: Гонноченко Алексей, Здоровцов Денис
