Занятие 5 Робот, проходящий лабиринт
.docКурс «Основы робототехники. Продвинутый уровень». Занятие 5. Робот, проходящий лабиринт
Добавим роботу возможность объезжать препятствия. Для этого используем ультразвуковой датчик расстояния HC-SR04
Примечание: рекомендуется взять распечатку Занятия 9. Цифровые датчики с информацией об используемом датчике
Практическое занятие 1. Установка и тестирование
Установите датчик расстояния на робота, использовав держатель. Подключите контакты датчика к Arduino (VCC – к 5V). Протестируйте датчик, загрузив в контроллер программу Файл / Примеры / Ultrasonic / Ultrasonic2serial, исправив при необходимости номера контактов.
Практическое занятие 2. Остановка у стены
Запрограммируем робота на езду вперед и остановку у препятствия. Скопируйте в программу разработанные в домашнем задании функции: forward, backward, left, right с передачей значения, сколько времени работать моторам. Если таких функций нет в наличии, шаблон функции дан в конце прошлого занятия
float distance; int min_distance = 20; // переменные, setup и опрос датчика расстояния в переменную distance if (distance > min_distance) { // если расстояние впереди больше заданного forward (50); // едем вперед } else { // иначе, если расстояние впереди меньше заданного stop_motors (); // тормозим } // функции |
Примечание: возможна ситуация, когда на датчик не приходит ответный сигнал, в этом случае distance может приравняться к нулю. Чтобы избежать некорректного поведения робота в этом случае, можно после опроса датчика добавить строку if (distance = 0) { distance = 2000; }
Практическое занятие 3. Объезд препятствия
Реализуйте следующий алгоритм:
-
Ехать вперед до тех пор, пока дистанция до препятствия впереди не будет меньше заданной (аналогично прошлой программе)
-
Если дистанция меньше – остановиться, отъехать назад, повернуть на определенный угол
-
Вернуться к пункту 1
Практическое занятие 4. Случайный объезд
Возможны ситуации, например, лабиринты, которые в случае езды робота вдоль одной стены являются непроходимыми. Простым решением проблемы является добавление элемента случайности в движения робота. Добавьте в предыдущую программу при обнаружении препятствия случайное направление поворота, используя логическую (boolean) переменную povorot для хранения направления
boolean povorot = false; … if (distance > min_distance){ // если расстояние впереди больше заданного forward (50); // едем вперед } else { // если расстояние впереди меньше заданного stop_motors (); // тормозим delay(100); backward (200); // едем назад
if (random(0, 2) == 0) {povorot = false;} // кидаем монетку на направление поворота 0 - false, else {povorot = true;} // 1 - true if (povorot == false){ // если выпал 0 left (turn_time); // едем налево } else { // если выпала 1 right (turn_time); // едем направо } } |
Также можно добавить и случайное время поворота (в заданных пределах), соответственно, будет случайным угол поворота:
turn_time = random (min, max+1)
Практическое занятие 4. Объезд с выбором направления поворота
Попробуем ускорить движение робота по объезду препятствия, убрав отъезд назад и добавив осмысленный выбор направления объезда препятствия. Например, при подъезжании робота к стене под углом (см. рисунок справа) имеет смысл выбрать соответствующее направление поворота, обеспечивающее минимальное время поворота.
Алгоритм работы в этом случае:
-
Ехать вперед до тех пор, пока дистанция до препятствия впереди не будет меньше заданной (аналогично прошлой программе)
-
Сохранить измеренную дистанцию, случайно выбрать направление поворота
-
Повернуть на небольшое расстояние
-
Измерить расстояние впереди
-
Сравнить измеренное расстояние с сохраненным в начале. Если расстояние стало меньше - направление выбрано неправильно и его надо сменить
-
Продолжать повороты до тех пор, пока расстояние впереди не станет больше заданного
Приведен код для данного алгоритма, его нужно проверить, провести подбор параметров (speed, turn_time и т.д.) для решения задачи оптимального прохождения лабиринта (за минимальное время) и продемонстрировать работу. Значение turn_time в коде небольшое (порядка 50 мс), так как для отворачивания от препятствия выполняется несколько мелких поворотов, а не один большой
distance = ultrasonic.Ranging(CM); if (distance > min_distance){ // если расстояние впереди больше заданного forward (50); // едем вперед } else { // если расстояние впереди меньше заданного if (random(0, 2) == 0) {povorot = false;} // кидаем монетку на направление поворота 0 - false, else {povorot = true;} // 1 - true
// поворачиваем до тех пор, пока расстояние впереди не станет допустимым, при этом проводим проверку, правильно ли мы повернули while (ultrasonic.Ranging(CM) < min_distance){ if (povorot == false){ // если выпал 0 left (turn_time); // едем налево } else { // если выпала 1 right (turn_time); // едем направо } // если дистанция впереди стала меньше исходной – поворот выполняется в неправильном направлении, меняем направление на противоположное if (ultrasonic.Ranging(CM) < distance) {povorot = !povorot;} } } |
Примечание 1: сохраните к себе получившийся код программы, он будет использован на соревновании по прохождению лабиринта на аттестационном занятии 8
Примечание 2: теоретически, при определенной конфигурации препятствия, возможно, что в обоих направлениях поворотов расстояние впереди станет меньше, чем было до поворота. В этом случае робот будет дергаться вправо-влево бесконечно. Чтобы избежать этого, можно добавить счетчик смены направлений и при превышении счетчика дать команду роботу выполнить, например, поворот на случайный большой угол.