Глава 8. Задачи для робота Управление без обратной связи В задачах управления обычно существуют два объекта: управляю- щий и управляемый. В простейшем варианте от управляющего объекта поступает команда и управляемый выполняет ее, ничего не сообщая о результате или об изменившихся условиях работы. В этом суть прямой связи (рис. 8.1). Рис. 8.1. Прямая связь в управлении. С точки зрения мобильного робота управляющий объект — это его контроллер с запущенной программой, объект управления — это его колеса и корпус (шасси). Управляющие команды контроллер подает на моторы, при прямой связи руководствуясь показаниями своих внутрен- них часов — таймера. Первый класс задач, с которых начинается программирование, — это управление перемещениями робота. Рассмотрим их по порядку. В качестве сред программирования используем Robolab 2.9.4 для начи- нающих и RobotC для подготовленных программистов. В качестве мо- дели робота — любую двухмоторную тележку. Движение в течение заданного времени вперед и назад Для движения вперед используются команды управления мотора- ми. Эти команды просто включают моторы. Особенность NXT заклю- чается в том, что после окончания выполнения программы сохраняются все установки в поведении робота, но на моторы перестает подаваться напряжение. Таким образом, просходит пуск и сразу плавное торможе- ние (рис. 8.2). Рис. 8.2. Включение моторов. 205 task main() { motor[motorB] = 100; // моторы вперед с motor[motorC] = 100; // максимальной мощностью } Обе команды выполняются практически мгновенно. Если сразу следом за ними выключить моторы, то тележка просто дернется и оста- нется стоять на месте (рис. 8.3): Рис. 8.3. Остановка при попытке начать движение. task main() { motor[motorB] = 100; motor[motorC] = 100; motor[motorB] = 0; // стоп мотор motor[motorC] = 0; } Таким образом, для осуществления движения требуется некоторая задержка перед выключением моторов. Команды ожидания не произво- дят никаких конкретных действий, зато дают возможность моторам вы- полнить свою часть работы (рис. 8.4): Рис. 8.4. Правильный порядок управления моторами. task main() { motor[motorB] = 100; motor[motorC] = 100; wait1Msec(1000); // Ждать 1000 мс motor[motorB] = 0; motor[motorC] = 0; } Движение вперед или назад, очевидно, определяется направлением вращения моторов (рис. 8.5). Для смены направления не требуется ос- тановка: Рис. 8.5. Проехать секунду вперед, секунду назад и остановиться.
206 task main() { motor[motorB] = 100; motor[motorC] = 100; wait1Msec(1000); motor[motorB] = -100; // «Полныйназад» motor[motorC] = -100; wait1Msec(1000); motor[motorB] = 0; motor[motorC] = 0; } В момент смены направления на высокой скорости возможен за- нос. Плавное торможение возможно. Для этого перед подачей команды «назад» с моторов снимается напряжение и робот некоторое время едет по инерции (рис. 8.6). Рис. 8.6. Перед сменой направления полсекунды ехать по инерции. Более краткий промежуток, чем 1 секунда, задается с помощью ко- манды «N/100» и модификатора. В Robolab 2.9.4 можно задавать время в миллисекундах командой «N/1000»: task main() { motor[motorB] = 100; motor[motorC] = 100; wait1Msec(1000); // ВключитьплавающийрежимуправлениямоторамиbFloatDuringInactiveMotorPWM = true; motor[motorB] = 0; motor[motorC] = 0; wait1Msec(500); motor[motorB] = -100; motor[motorC] = -100; wait1Msec(1000); // Включитьрежим «торможения» bFloatDuringInactiveMotorPWM = false; motor[motorB] = 0; motor[motorC] = 0; } В Robolab обычными командами моторы включаются в плавающем режиме, а в RobotC по умолчанию используется режим «торможения», 207 который позволяет достичь более точного управления. Но и в Robolab существуют «продвинутые» команды управления моторами в режиме торможения да еще с диапазоном мощностей –100...100. Повороты Для выполнения поворота на месте достаточно включить моторы в разные стороны. Тогда робот будет вращаться приблизительно вокруг центра оси ведущих колес со смещением в сторону центра тяжести. Для более точного поворота надо подбирать время в сотых долях секунды (рис. 8.7). Однако при изменении заряда батареек придется вводить но- вые параметры поворота: Рис. 8.7. Поворот на месте. task main() { motor[motorB] = 100; // Моторы в разные motor[motorC] = -100; // стороны wait1Msec(300); motor[motorB] = 0; motor[motorC] = 0; } Существует другой тип поворотов. Если один из моторов остано- вить, а другой включить, то вращение будет происходить вокруг стоя- щего мотора. Поворот получится более плавным (рис. 8.8): Рис. 8.8. Плавный поворот. task main() { motor[motorB] = 100; motor[motorC] = 0; wait1Msec(1000); // вращается только мотор B motor[motorB] = 0; }
208 Движение по квадрату Используя полученные знания управления моторами, можно запро- граммировать движение по квадрату или другому многоугольнику с помощью цикла или безусловного перехода (рис. 8.9): Рис. 8.9. Движение по многоугольнику с плавными поворотами. task main() { while (true){ motor[motorB] = 100; motor[motorC] = 100; wait1Msec(1000); motor[motorC] = 0; wait1Msec(1000); motor[motorB] = 0; } } Уточнив длительность поворотов и число повторений, научим те- лежку объезжать квадрат по периметру 1 раз (рис. 8.10). Для точности поворотов снизим мощность моторов примерно вдвое. Задержки при- дется подобрать самостоятельно: Рис. 8.10. Для поворота на 90 градусов длительность придется подобрать са- мостоятельно. task main() { for(int i=0;i<4;i++){ // Цикл выполняется 4 раза motor[motorB] = 50; motor[motorC] = 50; wait1Msec(1000); motor[motorC] = -50; wait1Msec(400); motor[motorB] = 0; } }
209 Управление с обратной связью Обратная связь Появление обратной связи в системе означает то, что управляющий объект начинает получать информацию об объекте управления (рис. 8.11). Рис. 8.11. Управление с обратной связью. Обратная связь осуществляется с помощью датчиков, прикреплен- ных, например, на корпус робота. Данные поступают в контроллер, ко- торый является управляющим объектом. Точные перемещения Чтобы поворот не зависел от заряда батареек, можно воспользо- ваться встроенным в двигатели датчиком оборотов, «энкодером», кото- рый позволяет делать измерения с точностью до 1 градуса. Для более эффективного управления задействуем в Robolab «продвинутые» ко- манды, считая что при повороте тележки на 90 градусов левое колесо поворачивается на 250 градусов вокруг своей оси (рис. 8.12): Рис. 8.12. Точный поворот на месте. task main() { nMotorEncoder[motorB]=0; // Инициализация энкодера motor[motorB] = 100; motor[motorC] = -100; // Пустой цикл ожидания показаний энкодера while(nMotorEncoder[motorB]<250); motor[motorB] = 0; motor[motorC] = 0; }
224 ДвижениевдольлинииОдин датчик Для первого опыта подойдут робот, созданный для задания «Танец в круге», и то же поле — черная окружность на белом фоне. Если уже все готово для изготовления полноценного поля для траектории, можно обратиться к разделу «Поле» в конце этой части. Единственная поправ- ка: датчик освещенности следует выдвинуть немного вперед, чтобы он образовывал вместе с ведущими колесами равносторонний или хотя бы равнобедренный прямоугольный треугольник (рис. 8.32). Рис. 8.32. Варианты расположения датчика освещенности относительно ве-дущих колес. Задача такова: двигаться вдоль окружности по границе черного и белого. Решается элементарно применением релейного (или пропор- ционального) регулятора, который рассмотрен в главе «Алгоритмы управления». Только алгоритм будет записан не в виде ветвления, а с использованием блоков «Жди темнее» и «Жди светлее». Базовая конст- рукиця приведена на рис. 8.33—8.35, а простейшая программа для на- чинающих — на рис. 8.36. Без модификаторов предполагается, что дат- чик освещенности подключен к первому порту, а на моторы подается максимальная мощность. Рис. 8.33. Крепление датчика освещенности к трехколесной тележке. 225 Рис. 8.34. Ось для регулировки высоты датчика может быть любой длины. Рис. 8.35. Высота датчика над поверхностью поля — от 5 до 10 мм. Рис. 8.36. Алгоритм движения по линии с одним датчиком освещенности. Перед стартом ставим робота на линию так, чтобы датчик был чуть слева. По алгоритму робот плавно поворачивает направо, пока осве- щенность не понизится на 5 пунктов (по умолчанию). Затем поворачи- вает налево, пока освещенность не повысится на 5 пунктов. Движение получается похожим на «змейку». Возможные проблемы Перечислим трудности, которые могут возникнуть: — робот крутится на месте, не заезжая на линию. В этом случае сле- дует либо стартовать с другой стороны линии, либо поменять подключения моторов к контроллеру местами; — робот проскакивает линию, не успевая среагировать. Следует пони- зить мощность моторов; — робот реагирует на мелкие помехи на белом, не доезжая до черно- го. Надо увеличить порог чувствительности датчика (например, не на 5, а 226 на 8 пунктов). Вообще говоря, это число можно рассчитать. Для этого сле- дует снять показания датчика на белом, затем на черном, вычесть одно из другого и поделить пополам. Например, (56 – 40) / 2 = 8. Усовершенствованная программа показана на рис. 8.37. Рис. 8.37. Алгоритм движения по линии с одним датчиком освещенности: понижена скорость, увеличена разность между черным и белым. Более устойчиво алгоритм работает, если использовать моторы с управлением скоростью –100...100. В этом случае есть возможность от- регулировать плавность поворота в соответствии с кривизной линии (рис. 8.38). Рис. 8.38. Алгоритм движения по линии с одним датчиком освещенности: улучшено управление моторами. В этом алгоритме притормаживающие моторы на повороте не ос- танавливаются полностью, а лишь понижают скорость до 20 пунктов. Это делает поворот более плавным, но может привести и к потере ли- нии на резком повороте. Поэтому числа 80 и 20 поставлены условно, их стоит подобрать самостоятельно. П-регулятор И, наконец, для сравнения надо посмотреть, как будет работать П-регулятор для одного датчика. Этот пример уже приводился в гла- ве 7. Но его стоит повторить с некоторыми дополнениями (рис. 8.39). Рис. 8.39. Алгоритм движения по линии с одним датчиком освещенности на пропорциональном регуляторе.
227 Число 48, использованное в формуле управления u, — это среднее арифметическое показаний датчика освещенности на черном и на бе- лом, например (40 + 56) / 2 = 48. Однако показания датчиков часто ме- няются по разным причинам: другая поверхность, изменение общей ос- вещенности в помещении, небольшая модификация конструкции и т.п. Поэтому имеет смысл научить робота самостоятельно вычислять сред- нее арифметическое, т. е. значение границы белого и черного. Есть несколько способов выполнить калибровку датчика. В про- стейшем случае вместо вычисления среднего арифметического просто понижается значение белого. Смысл способа в том, что робот снимает показания на белом, вычитает из него некоторое предполагаемое значе- ние и полученное число считает границей белого и черного. Например, 56 – 7 = 49 можно считать значением серого (рис. 8.40). Рис. 8.40. Алгоритм движения по линии с одним датчиком освещенности на пропорциональном регуляторе с предварительной калибровкой (определени-ем значения серого). task main() { int u, v=50; float k=2; int red=SensorValue[S1]-7; while(true) { u=k*(SensorValue[s1]-red); motor[motorB]=v+u; motor[motorC]=v-u; wait1Msec(1); } } По умолчанию значение освещенности с датчика на порту 1 считы- вается в красный контейнер, после чего оно уменьшается на число 7, и в формуле управления u используется уже измененное значение красного контейнера red. Если указывать все модификаторы, программа будет выглядеть так, как показано на рис. 8.41. 228 Рис. 8.41. Алгоритм движения по линии с одним датчиком освещенности на пропорциональном регуляторе — с модификаторами. Надо иметь ввиду, что такой способ калибровки не учитывает все возможные варианты, а только экономит время на программирование и отладку. Если же времени достаточно, есть другой способ, при котором действительно производится расчет среднего арифметического показа- ний датчика освещенности на черном и на белом (рис. 8.42). Рис. 8.42. Алгоритм движения по линии с одним датчиком освещенности на пропорциональном регуляторе с расчетом значения серого. task main() { int u, v=50; float k=2; int c4=SensorValue[S1]; PlaySound(soundBeepBeep); wait1Msec(2000); int c5=SensorValue[S1]; PlaySound(soundBeepBeep); int grey=(c4+c5)/2; while(true) { u=k*(SensorValue[S1]-grey); motor[motorB]=v+u; motor[motorC]=v-u; wait1Msec(1); } } Предложенный алгоритм обладает некоторым неудобством: при запуске потребуется быть внимательным и не пропустить звукового сигнала, после которого робота надо переместить так, чтобы датчик ос- вещенности оказался над белым полем. Понятно, что в начале следует 229 поместить робота точно над черной линией. В контейнере с номером 4 (обозначается c4) будет сохранено значение черного, в контейнере с номером 5 (c5) — значение белого. В переменную grey помещается зна- чение серого, которое используется в регуляторе. Сразу после второго звукового сигнала робот начнет движение. Калибровку можно сделать более управляемой. Для этого после каждого считывания данных необходимо вставить ожидание какого- либо внешнего события, например нажатия на датчик касания, умень- шения расстояния на ультразвуковом датчике или просто нажатия на кнопку NXT. Рассмотрим простейший пример с дополнительным датчиком ка- сания, подсоединенным ко второму порту. Запустить программу имеет смысл, аккуратно установив тележку датчиком освещенности над чер- ной линией (рис. 8.43). Рис. 8.43. Калибровка датчика освещенности с ожиданием касания. task main() { int u, v=50; float k=2; int c4=SensorValue[S1]; PlaySound(soundBeepBeep); while(SensorValue[S2]==0); // Жди , пока не нажато wait1Msec(100); // Защита от залипаний while(SensorValue[S2]==1); // Жди , пока нажато wait1Msec(100); int c5=SensorValue[S1]; PlaySound(soundBeepBeep); int grey=(c4+c5)/2; while(SensorValue[S2]==0); wait1Msec(100); while(SensorValue[S2]==1); while(true) {
230 u=k*(SensorValue[S1]-grey); motor[motorB]=v+u; motor[motorC]=v-u; wait1Msec(1); } } После первого звукового сигнала нужно переставить тележку так, чтобы датчик освещенности оказался над белым. После второго сигнала подготовиться к старту (датчик освещенности на границе между чер- ным и белым) и по нажатию кнопки стартовать. Аналогичный опыт можно провести, используя датчик расстояния вместо датчика нажатия. Преимущество здесь в том, что старт робота будет осуществляться бесконтактно. Это поможет стартовать в точно выбранном положении. Только надо быть внимательным и несвоевре- менно не провести рукой возле датчика расстояния (рис. 8.44). Рис. 8.44. Калибровка датчика освещенности с ожиданием объекта (руки). В примере использованы именованные контейнеры (black и white), которые по сути являются переменными, как в обычном языке про- граммирования. Обратите внимание, что звуковой сигнал между двумя ожиданиями изменения расстояния способствует тому, чтобы робот не среагировал дважды подряд на одно приближение руки. Полученный опыт стоит применить для окончательного выталки- вания кеглей из круга, если таковые еще остались на границе. Дорабо- тайте самостоятельно алгоритм, приведенный на рис. 8.31. Поле для следования по линии Более интересную траекторию, чем окружность, стоит сделать са- мостоятельно на светлой поверхности достаточно большой площади с помощью той же черной изоленты. В качестве поверхности подойдет лист фанеры или оргалита, обратная сторона листа линолеума, белая 231 клеенка и многое другое. Размеры поля желательно делать не меньше, чем 100 ´ 150 см. При разметке траектории следует учесть отступ от линии до края поля не менее 20 см, чтобы колеса робота не съезжали с трассы во время движения. Имея определенный навык, можно наклеить изоленту так, что по- лучится замкнутая кривая. Если не получается с одним куском изолен- ты, смело пользуйтесь ножницами, чтобы изгибы с малым радиусом кривизны составить из нескольких кусочков. Для начала не стоит рисо- вать слишком резких поворотов. Линию можно составить как из одной, так и из двух и даже трех полос изоленты. Тогда роботу будет легче ориентироваться и не съехать с курса. Помимо изоленты может быть использована матовая черная самоклеющаяся пленка. И, наконец, оп- тимальное решение ¾ печать графического файла на баннерной ткани. Стоимость такой печати обычно не превосходит 400 руб. за 1 м 2 . Не- большое поле для движения по линии приведено на рис. 8.45. перейти в каталог файлов |