И прежде, чем поставить датчики на робота, давайте снова вернемся к нашей схеме, где зафиксируем, что у нас теперь в качестве устройства восприятия есть датчик линии, который отличает белое, черное и все промежуточные оттенки, которые он воспринимает серыми, который считывается как обычный аналоговый сигнал. И у нас будет функция, которая будет сообщать, черное или белое сейчас находится под данным датчиком. И тот алгоритм, который мы представили когда рассуждали о езде по линии, мы реализуем: свяжем вот эту и вот эту функции. Итак, мы снова в студии, и мы знаем все, что нужно для того чтобы робот поехал. Теперь нам нужно доработать робота, нам нужна трасса и нам нужен код. Что касается робота. Я просто установил 2 датчика линии таким образом, чтобы они были как можно ближе к краям линии, потому что если мы их разнесем далеко, вспомните, как он будет ехать: он будет ехать пока не упрется одним из датчиков в линию, да, он вот так вот перекосится. Зачем нам это? Потом он перекосится обратно, и так вот он зигзагами будет ехать. Не надо. Поэтому они располагаются рядом с линией. Что касается трассы. Я нарисовал вот такую вот трассу в обычном графическом редакторе. Мне хотелось, чтобы она была похожа на гоночную трассу с прямым отрезком, с плавными поворотами, с крутыми поворотами и так далее. Вы можете взять этот макет в дополнительных материалах или нарисовать свою трассу, а затем забить в поисковике «широкоформатная печать», найти типографию, позвонить им, спросить, печатают ли они на баннерной ткани. Они напечатают, и у вас будет трасса. Теперь давайте разберемся с кодом. За основу я взял один из скетчей, где мы экспериментировали с ездой, и стал редактировать. Во-первых, добавил макроопределения для пинов датчиков и несколько еще макроопределений, которые сделают код более читаемым. Вот эти мы будем передавать в качестве параметров в функцию чтения датчиков, это у нас обозначает границу между черным и белым, а вот это — заданные скорости, возможные скорости для моторов вперед и назад. Помните, как у нас было на схеме? Затем я определил функцию для чтения датчиков. Конечно, могли бы обойтись и без нее, но при дальнейшем развитии программы, код стал бы нечитаемым, поэтому я решил вынести это в отдельную функцию. Вот она. Она будет возвращать "булево" значение, истину или ложь, в зависимости от того, черное или белое сейчас находится под датчиком. В качестве параметра она принимает те самые left и right для определения того, какой датчик сейчас нужно считывать. Что, собственно, и происходит: если пришло left — будем считывать значение с того пина, куда подключен левый датчик, и, если оно больше порогового значения, возвращать «ложь», а в противном случае — «истину». И ровно то же самое происходит, если пришло right, только для правого датчика. Теперь, у нас есть функция для управления моторами, функция для чтения датчиков, у нас есть представление о том, как их связать, и мы реализуем это в коде. Согласно нашей табличке, если оба датчика показывают «белое», то есть функция lineSensor возвращает «истину», мы просто едем вперед. В противном случае, если под правым датчиком «черное», то есть lineSensor (right) возвращает «ложь», мы будем поворачивать направо, крутить правое колесо назад, а левое — вперед. И третий случай, который мы рассмотрели: когда правый датчик показывает «белое», а левый — «черное». В этом случае мы поворачиваем влево. Ну, и если каким-то чудесным образом под обоими датчиками оказалось «черное», или случилась еще какая-то непредвиденная ситуация, то мы просто останавливаемся. Вот и все. Давайте смотреть, как это работает, только прежде почитаем еще раз датчик чтобы определить ту самую границу между черным и белым. Посмотрим, что мы видим. В моей программке для визуализации есть удобные поля «минимум» и «максимум», поэтому я вижу, что здесь значения изменяются от 37 до 485. Я даже не буду работать с подстроечными резисторами, а просто буду считать, что переход между белым и черным случается в районе 200, собственно, как в коде и было написано. Если бы у меня получилось 400, я бы заменил одно из макроопределений. Теперь давайте посмотрим, действительно ли робот поедет, как мы задумывали. Перед загрузкой программы с ездой не забудьте закрыть монитор порта или визуализатор монитора порта, потому что иначе у вас будут проблемы с загрузкой. [МУЗЫКА] Посмотрим, что получилось. [МУЗЫКА] [МУЗЫКА] [МУЗЫКА] [МУЗЫКА] [МУЗЫКА] Итак, задача езды по линии в первом приближении решена. Однако, мы у данного способа видим ряд недостатков. Во-первых, на поворотах робот совершает порывистые движения. Во-вторых, очевидно, что при разном уровне заряда батарей одни и те же жестко заданные значения будут приводить к различному результату, то есть придется постоянно менять константы, определяющие скорости, к примеру. Ну, а кроме этого, у другого способа, о котором мы будем говорить далее, есть свои отдельные преимущества. [КОНЕЦ] [КОНЕЦ] [КОНЕЦ]