Такой робот сам едет по чёрной линии на белом полу и проходит её изгибы. Два инфракрасных (ИК) датчика линии под передней частью машины смотрят на пол, по одному с каждой стороны от линии. Когда линия смещается под один из датчиков, робот поворачивает в эту сторону. Вы узнаете, как ИК-датчик отличает чёрное от белого, как его компаратор выдаёт чёткий сигнал HIGH или LOW и как четыре простых случая управляют роботом. Это проект средней сложности, на него уйдёт около 90 минут.
Что понадобится
Arduino Uno R3Есть в симуляторе× 1Цену смотрите в магазине
Модуль драйвера моторов L298NЕсть в симуляторе× 1Цену смотрите в магазине
Мотор-редуктор TT 1:48 с колесом 65 ммЕсть в симуляторе× 2Цену смотрите в магазине
Батарейный отсек 4 × AAЕсть в симуляторе× 1Цену смотрите в магазинеШаровая опора 20 ммЕсть в симуляторе× 1Цену смотрите в магазине
Модуль ИК-датчика линииЕсть в симуляторе× 2Цену смотрите в магазине
Набор проводов-перемычек× 1Цену смотрите в магазине
Это машина из проекта «Первый заезд» без HC-SR04, но с двумя модулями ИК-датчиков линии. Посмотрите в Маркете дополнительный набор для езды по линии. Для трассы нужны белая поверхность и чёрная лента шириной около 2 см, например чёрная изолента. Хорошо подойдёт большой лист белого картона или гладкий светлый пол. Ещё понадобится маленькая отвёртка, чтобы настроить датчики.
Как это работает
Как датчик видит линию
На каждом модуле рядом стоят инфракрасный светодиод и ИК-приёмник, и оба смотрят вниз. Светодиод светит на пол инфракрасным светом. Вы этот свет не видите, а приёмник видит. Белый пол отражает большую его часть обратно в приёмник. Чёрная линия поглощает большую часть света, поэтому назад его возвращается мало.
Приёмник превращает свет в напряжение, которое зависит от того, сколько света вернулось. Микросхема-компаратор на модуле (часто это LM393) сравнивает это напряжение с порогом. Порог задаёт маленький потенциометр на модуле. В результате на пине OUT получается чёткий цифровой сигнал:
| Под датчиком | Сколько ИК-света возвращается | OUT |
|---|---|---|
| Белый пол | много | LOW |
| Чёрная линия | мало | HIGH |
Поворот потенциометра сдвигает точку, в которой переключается OUT. Так датчик настраивают под ваш пол, вашу линию и высоту, на которой он стоит. На большинстве модулей есть ещё маленький светодиод, который показывает состояние OUT, поэтому настраивать их можно без компьютера.
Где стоят датчики
Два датчика стоят под передней частью машины, примерно в 5 мм над полом (TCRT5000 видит пол на расстоянии примерно от 0,2 до 15 мм), по одному с каждой стороны от линии. Промежуток между ними чуть шире линии. Поэтому, когда линия проходит точно посередине под роботом, оба датчика видят белое. Левый и правый — это левая и правая стороны самого робота, если смотреть на него сзади. OUT левого датчика подключается к D2, а OUT правого — к D3.
Четыре случая
| Левый (D2) | Правый (D3) | Что это значит | Моторы | Робот |
|---|---|---|---|---|
| LOW: белое | LOW: белое | линия между датчиками | drive(170, 170) |
едет прямо |
| HIGH: чёрное | LOW: белое | линия ушла влево | drive(-70, 170) |
поворачивает налево |
| LOW: белое | HIGH: чёрное | линия ушла вправо | drive(170, -70) |
поворачивает направо |
| HIGH: чёрное | HIGH: чёрное | поперечная линия или конец трассы | drive(0, 0) |
останавливается |
Почему робот поворачивает к тому датчику, который видит чёрное? Если линия под левым датчиком, значит, робот сместился вправо от линии или линия поворачивает влево. Поворот налево возвращает линию в промежуток между датчиками. В повороте внешнее колесо крутится вперёд со скоростью 170, а внутреннее медленно крутится назад со скоростью 70. Поэтому робот поворачивает круто.
В loop() нет delay(). Функция опрашивает оба датчика тысячи раз в секунду, поэтому робот реагирует, как только линия сдвигается.
Сборка
1. Начните с машины
Начните с Obstacle avoider, машины, которая есть в игре с самого начала, или со своей машины из проекта «Первый заезд». В «Сборке» снимите HC-SR04 и добавьте два модуля ИК-датчика линии; следующие шаги показывают, куда их поставить и как подключить. Потом вставьте скетч LineFollower в «Код» и нажмите «Загрузить». На трассе по линии A робот стартует прямо на линии.
В реальной сборке: возьмите свою машину из проекта «Первый заезд». HC-SR04 этому роботу не нужен.
2. Установите датчики
Закрепите оба модуля под передней частью машины так, чтобы датчики смотрели вниз и находились примерно в 5 мм над полом.
В реальной сборке: нижняя пластина (ярус) находится примерно в 4 см над полом, поэтому модулям нужны проставки или небольшой кронштейн, чтобы опуститься примерно до 5 мм. Сделайте промежуток между датчиками чуть шире линии: для линии шириной 2 см — примерно 3–4 см. На машине в симуляторе датчики стоят в 3,6 см друг от друга, по одному с каждой стороны от шаровой опоры. Если датчики стоят слишком близко друг к другу, на прямых участках оба видят чёрное. Если слишком далеко, робот успевает сильно отклониться от линии, прежде чем её заметит один из датчиков.
3. Подключите датчики
| Откуда | Куда | Зачем |
|---|---|---|
| Батарея + | L298N +12V | Питание моторов: около 6 В от четырёх батареек AA |
| Батарея - | L298N GND | Минус батареи |
| L298N +5V | Uno 5V | Стабилизатор драйвера питает Uno: около 4,4 В |
| L298N GND | Uno GND | Общая земля: сигналам нужен общий 0 В |
| Uno D5 | L298N ENA | Скорость левого мотора (ШИМ); перемычка ENA снята |
| Uno D4 | L298N IN1 | Направление левого мотора |
| Uno D7 | L298N IN2 | Направление левого мотора |
| Uno D8 | L298N IN3 | Направление правого мотора |
| Uno D12 | L298N IN4 | Направление правого мотора |
| Uno D6 | L298N ENB | Скорость правого мотора (ШИМ); перемычка ENB снята |
| Левый мотор M+ | L298N OUT1 | |
| Левый мотор M- | L298N OUT2 | |
| Правый мотор M+ | L298N OUT4 | Переставлено специально: этот мотор стоит зеркально |
| Правый мотор M- | L298N OUT3 | Переставлено специально: этот мотор стоит зеркально |
| Левый датчик линии VCC | L298N +5V | 5 В для датчика |
| Левый датчик линии GND | Uno GND | Земля |
| Левый датчик линии OUT | Uno D2 | LOW над белым, HIGH над чёрной линией |
| Правый датчик линии VCC | Uno 3V3 | В клемме +5V уже два провода; модулю хватает 3,3 В |
| Правый датчик линии GND | Uno GND | Земля |
| Правый датчик линии OUT | Uno D3 | Как у левого датчика |
У каждого модуля три пина: VCC подключается к 5 В (или к 3,3 В), GND — к GND, а OUT — к Uno. OUT левого датчика идёт на D2, а OUT правого — на D3. Подключение моторов остаётся таким же, как в проекте «Первый заезд».
В реальной сборке: на некоторых модулях OUT подписан как DO. Если на вашем модуле есть ещё пин AO, оставьте его свободным: в этом проекте используется только цифровой выход. В таблице подключения показано, от каких точек 5 В и GND питается каждый датчик: в клемме +5V драйвера L298N уже два провода, поэтому правый датчик питается от пина 3.3V платы Uno. Модуль работает от 3,3 до 5 В.
4. Сделайте трассу
Наклейте чёрную ленту шириной около 2 см на белую поверхность. Начните с большого овала: плавные повороты проходить легче, чем острые углы. Прижмите ленту ровно, без складок и зазоров. Там, где робот должен останавливаться, наклейте короткую поперечную линию.
5. Настройте датчики
В реальной сборке: выньте батарейки, чтобы колёса не могли крутиться. Подключите USB-кабель: теперь Uno и датчики питаются от компьютера. Поставьте машину на трассу и настраивайте датчики по одному:
- Наведите датчик на белый пол и посмотрите на его светодиод.
- Сдвиньте машину так, чтобы датчик оказался над чёрной линией. Светодиод должен переключиться.
- Если он не переключается, немного поверните потенциометр отвёрткой и попробуйте снова.
- Проверьте датчик в нескольких местах трассы и добейтесь, чтобы светодиод переключался каждый раз.
6. Загрузите и запустите
Загрузите скетч. Затем отключите USB-кабель, вставьте батарейки, придерживая машину, и поставьте её так, чтобы линия оказалась между двумя датчиками. Робот сразу поедет. Понаблюдайте за первым поворотом. Если робот его проходит, попробуйте поворот покруче. Если он съезжает с линии, загляните в советы ниже.
Код
// Line follower: two IR sensors look down at the floor, one each side of a black line.
// Each sensor's OUT is LOW over the white floor and HIGH over the black line.
// L298N: ENA -> D5, IN1 -> D4, IN2 -> D7 (left), ENB -> D6, IN3 -> D8, IN4 -> D12 (right)
// IR sensors: left OUT -> D2, right OUT -> D3
const byte ENA = 5, IN1 = 4, IN2 = 7;
const byte ENB = 6, IN3 = 8, IN4 = 12;
const byte LEFT_EYE = 2, RIGHT_EYE = 3;
const int FAST = 170; // speed on a straight line
const int SLOW = 70; // the inner wheel in a turn, driven backwards
void setMotor(byte enablePin, byte inA, byte inB, int speed) {
speed = constrain(speed, -255, 255);
digitalWrite(inA, speed > 0);
digitalWrite(inB, speed < 0);
analogWrite(enablePin, abs(speed));
}
void drive(int left, int right) {
setMotor(ENA, IN1, IN2, left);
setMotor(ENB, IN3, IN4, right);
}
void setup() {
const byte pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
for (byte pin : pins) pinMode(pin, OUTPUT);
pinMode(LEFT_EYE, INPUT);
pinMode(RIGHT_EYE, INPUT);
}
void loop() {
bool leftOnLine = digitalRead(LEFT_EYE) == HIGH;
bool rightOnLine = digitalRead(RIGHT_EYE) == HIGH;
if (!leftOnLine && !rightOnLine) {
drive(FAST, FAST); // the line is between the sensors: straight on
} else if (leftOnLine && !rightOnLine) {
drive(-SLOW, FAST); // the line went left: turn left
} else if (!leftOnLine && rightOnLine) {
drive(FAST, -SLOW); // the line went right: turn right
} else {
drive(0, 0); // both see black: a cross line or the end, stop
}
}Пины и скорости
const byte LEFT_EYE = 2, RIGHT_EYE = 3;
const int FAST = 170; // speed on a straight line
const int SLOW = 70; // the inner wheel in a turn, driven backwardsВ скетче датчики названы «глазами» (EYE). FAST — скорость на прямой линии. SLOW — скорость внутреннего колеса в повороте; это колесо крутится назад.
setup()
Шесть пинов моторов становятся выходами, как в любом скетче для машины. Два пина датчиков становятся входами с помощью pinMode(LEFT_EYE, INPUT) и pinMode(RIGHT_EYE, INPUT). Модули сами выставляют на OUT уровень HIGH или LOW, поэтому подтягивающий резистор не нужен.
Опрос датчиков
bool leftOnLine = digitalRead(LEFT_EYE) == HIGH;
bool rightOnLine = digitalRead(RIGHT_EYE) == HIGH;digitalRead() возвращает HIGH или LOW. Если сравнить результат с HIGH, получится bool — true (истина) или false (ложь). Поэтому leftOnLine равно true, когда левый датчик видит чёрное. С такими понятными именами остальной код loop() легко читать.
Четыре случая
if (!leftOnLine && !rightOnLine) {
drive(FAST, FAST); // the line is between the sensors: straight on
} else if (leftOnLine && !rightOnLine) {
drive(-SLOW, FAST); // the line went left: turn left
} else if (!leftOnLine && rightOnLine) {
drive(FAST, -SLOW); // the line went right: turn right
} else {
drive(0, 0); // both see black: a cross line or the end, stop
}! означает «не», а && — «и». Четыре ветки соответствуют четырём строкам таблицы выше. Последняя, else, срабатывает в единственном оставшемся случае: когда оба датчика над чёрным. setMotor() и drive() такие же, как в проекте «Первый заезд»: положительная скорость крутит колесо вперёд, а отрицательная — назад.
Если что-то не работает
- Робот проезжает прямо через линию. Датчики её не видят. Проверьте, что светодиод каждого модуля переключается между белым и чёрным, и подстройте потенциометр. Проверьте высоту (около 5 мм, не больше 1 см) и то, что OUT подключены к D2 и D3.
- Робот поворачивает от линии, а не к ней. Левый и правый датчики перепутаны. Поменяйте местами два провода OUT на D2 и D3.
- Робот всё время останавливается. Оба датчика видят «чёрное». Возможно, для вашей линии они стоят слишком близко друг к другу или слишком высоко над полом: с большой высоты возвращается слишком мало света, и это выглядит как чёрное. Или порог настроен так, что белое тоже читается как чёрное. Заново настройте потенциометры.
- На крутых поворотах робот съезжает с линии. Он едет слишком быстро и не успевает среагировать. Уменьшите FAST или увеличьте SLOW, чтобы робот поворачивал круче.
- На прямых участках робот сильно виляет. Повороты слишком резкие. Немного уменьшите SLOW или уменьшите FAST.
- В одной комнате робот работает, а в другой — нет. Солнце и некоторые лампы тоже дают инфракрасный свет, и он может ослепить датчики. Проверяйте робота вдали от прямых солнечных лучей и заново настраивайте потенциометры на каждом новом полу.
- Датчик не видит вашу чёрную линию. Некоторые чёрные ленты и чернила отражают инфракрасный свет, хотя нам они кажутся чёрными. Блестящая лента тоже может отражать свет прямо назад. Попробуйте матовую чёрную ленту или линию, напечатанную на бумаге лазерным принтером.
- Колесо крутится не в ту сторону или робот перезагружается. Посмотрите советы в проекте «Первый заезд» и в статье о том, почему роботы перезагружаются.
Что дальше
Дайте роботу вторую задачу: верните на место HC-SR04 и научите робота останавливаться, когда что-то перегораживает линию. Датчики линии занимают D2 и D3, а HC-SR04 — D9 и D10, так что пины друг другу не мешают. Проект «Робот, объезжающий препятствия» показывает, как измерять расстояние, не останавливая loop(). А урок про millis() и состояния поможет совместить несколько задач в одном скетче.
Этот робот знает только «на линии» или «вне линии». Датчики с аналоговым выходом, которые читают через analogRead(), могут показать ещё и то, насколько далеко робот от линии. Тогда П-регулятор, как в проекте «Робот, который держит дистанцию», сможет рулить плавно.
Сделайте лучше
- Найдите самое большое значение FAST, при котором робот ещё проходит вашу трассу, а затем попробуйте другое значение SLOW.
- Пусть светодиод L платы Uno на D13 горит всякий раз, когда робот поворачивает.
- Научите робота у поперечной линии ждать две секунды, затем переезжать её и снова ехать по линии.
