воскресенье, 8 мая 2011 г.

NXT-G: программа повисла?

При программировании какого-то поведения робота, когда вы используете блок движения на заданное расстояния, вы, наверняка, сталкивались с ситуацией, когда программа как бы зависала на этом блоке, если во время выполнения этого блока робот застревал.
Например, такая ситуация может возникнуть, когда роботу нужно проехать расстояние 50 см., а на пути у него возникает препятствие.

В таком случае, робот, застряв на препятствии, будет все также пытаться повернуть колеса до нужного количества поворотов или градусов. Но сделать этого не сможет, поэтому программа никогда не передаст управление следующему блоку – со стороны будет казаться, что робот повис.

Другой, более яркий пример – робот с манипулятором, пытающийся захватить какой-то предмет. Пусть в программе предусмотрен блок для закрытия манипулятора, для того чтобы произвести захват. Блок – просто вращение двигателя манипулятора на 90 градусов. Двигатель приводит захваты манипулятора в движение, а те смыкаются на нужном предмете.

А что произойдет, если в области захвата окажется предмет больший?

Мотор, провернувшись на 40 градусов, не сможет продолжить движение. Соответствующий блок в программе будет ожидать поворота до 90 градусов, но наступление этого события никогда не случиться – программа опять подвиснет на этом действии.

Чтобы понять как данную проблему можно решить, давайте рассмотрим как устроен блок Move (или Motor).

Данный блок, работающий в ожидании поворота на нужное количество градусов или оборотов, можно описать следующим образом:
  1. Определить текущее значение показаний на счетчике поворотов двигателя
  2. Запустить мотор
  3. Ждать до тех пор, пока новое значение показаний на счетчике поворотов двигателя не будет отличаться от замеренного на шаге 1 на нужное количество градусов
  4. Остановить мотор
На языке NXT-G это выглядит следующим образом:

На самом деле реальный кусок программы будет немножко сложнее из-за того, что необходимо учитывать направление движения. Но сейчас, будет использоваться вот такая форма – поскольку, важно понять сам принцип.

Итак, для того, чтобы определить поворот на нужное количество градусов, используется цикл, выход из которого осуществиться когда операция сравнения не вернет положительный результат сравнения (иными словами пока результат сравнения не вернет Истину - True).

Если по какой-то причине значение на счетчике поворотов изменяться не будет (движение мотора неожиданно заблокировано), то цикл будет крутиться вечно и никогда не завершиться, поскольку результат сравнения всегда будет отрицателен (False).

Следовательно, неплохо было бы предусмотреть какой-то дополнительный вариант выхода из цикла. Например, разумным вариантом выглядит использование дополнительного ожидания по времени – таймаута (timeout), как это было описано в заметке, посвещенной тонкостям использования блоков Move и Motor. Суть этого таймаута состоит в том, что в программе как бы резервируется максимально возможное время на выполнение операции (в данном случае операции поворота двигателя), и если операция занимает больше этого зарезервированного времени, то завершать ее до наступления основного события (повота на нужное количество градусов). Словами это можно описать, как "двигаться до тех пор, пока не повернемся на 90 градусов ИЛИ пока не пройдет 2 секунды".

Реализация такого подхода приводит к усложнению условия выхода из цикла. Теперь помимо поворота на нужное количество градусов, происходит сравнение на истечение заданного промежутка времени. Для этого используется возможность NXT-G работать с внутреннми таймерам NXT блока.



Теперь даже если движение мотора зблокируется и первый блок сравнения будет все время выдавать Ложь (False), итерации цикла прервуться, когда второе условие выдаст Истину (True) через заданное время.

Если данная программа кажется черезчер длинной, то ее можно оптимизировать используя внутреннюю возможность сравнения в блоках работы с сенсорами/таймерами.
Основная оптимизация тогда коснется той части цикла, которая ожидает поворота на опеределенное количество градусов – вместо вычисления разницы между двумя замерами показаний счетчика внутри цикла будет единовременное вычисление ожидаемых показаний счетчика до начала цикла.


Имеет смысл создать из данного фрагмента отдельный блок, чтобы потом использовать его в нужных местах программы.


Следует обратить внимание на то, что в данном блоке есть один выходящий параметр – Error. Он содержит признак того, что движение блока закончилось не по достижению определенного количества градусов, а из-за сработавшего таймаута. В основной программе это возвращаемое значение можно проверить и соответствующим образом обработать. Например, при застрявшем манипуляторе – разжать захваты, и попытаться найти более подходящий предмет, а при роботе двигающемуся прямо и наталкнувшемуся на препятствие, попытаться это препятствие как-то объехать.

Также важно помнить, что таймаут нужно устанавливать учитывая несколько факторов, таких как скорость движения, в том числе возможное изменение скорости в результате изменения зарада батареек, быстрота распознования возникновения препятствия движению. Слишком маленький таймаут может приводить к ситуациям, когда он будет срабатывать даже когда препятствия нет. Слишком большой будет реагировать на возникшую помеху слишком поздно.

Кстати, ситуации описанные выше могут произойти не только при движении на определенное количество градусов. Подобные ситуации могут возникнуть при ожидании события от сенсора. Например, сенсора касания – робот двигается прямо, пока не коснется сенсором касания стены, и препятствие возникшее на пути у робота, опять сделает невозможным наступление этого события.



Используя подход, предложенный выше, можно достичь адекватного поведения робота даже в этом случае.

Комментариев нет:

Отправить комментарий

Related Posts Plugin for WordPress, Blogger...