Продолжение. Начало здесь и здесь. В прошлой заметке было разработана программа для движения тележки вдоль стены на определенном расстоянии. А измениться ли программа, если вместо тележки, собранной по танковой схеме, использовать тележку с управляющими колесами? |
Отличие этой конструкции в том, что выполнение поворотов происходит не изменением мощности на одном из колес тележки, а поворотом управляющих колес в нужную сторону.
Давайте, снова взглянем на диаграмму переходов для простого движения вдоль стены:
Движение робота состоит из поворотов, относительно стены, на крайних позициях и движения прямо в других случаях.
Программу, было решено, строить по следующей структурной схеме:
Т.е. все действия программы выполняются в цикле.
Для тележки, собранной по танковой схеме, можно использовать блок выполнения поворота в каждой итерации цикла, робот будет продолжать движение по абсолютно такой же траектории, как и на предыдущем шаге. Для перемещения прямо, в нужной точке выполнения поворота, начинает выполняться блок движения прямо. Движение прямо – это оба мотора двигаются с одинаковой скоростью.
Движение же тележки с управляющими колесами немного отличается тем, что, после выполнения поворота, для того чтобы начать ехать прямо, нужно изменить положение управляющих колес, так чтобы они встали в нейтральную позицию. Но как узнать в какую сторону их изменять из положение, ведь если до этого поворот был в правую сторону, изменение положения колес должно происходить влево, а если поворот – левый, колеса надо перемещать вправо?
Существует еще одно отличие. Допустим, что на очередной итерации цикла было обнаружено, что расстояние до стены меньше 14 см, т.е. необходимо выполнить поворот вправо и для этого происходит изменение положения колес. Что происходит на следующей итерации цикла? Значение с сенсора расстояния все еще меньше 14 см., но нужно ли изменять положение колес? Нет. Они уже стоят в нужном положении. Следовательно, необходимо отличать состояния, когда с сенсора приходят сигналы о повороте, но колеса стояли в нейтральном положении или уже повернуты.
Очевидно, что для решения обеих проблем, надо запомнить предыдущее состояние. Для первого случая нужно запомнить в в какую сторону до этого поворачивали, так чтобы выравнять колеса соответствующим образом. Для второго случая, нужно запомнить, что изменения положения управляющих колес уже происходило, и таким образом, не выполнять его, если робот все еще находится в «зоне поворота».
Иными словами, сейчас структура основного цикла программы немного меняется - действие, которое необходимо выполнить при смене состояния, будет зависеть от того, какое состояние было для этого.
От предыдущей диаграммы ее отличает
- Появление новой сущности – состояние. Состояние, определенное после одной итерации, используется как входные данные для определения нового действия и нового состояния.
- Отдельные блоки для выбора действия и его выполнения. Почему? Потому что в некоторых случаях при переходе в различное состояние, будут выполняться одни и те же действия. Например, при изменении положения управляющих колес для выполнения поворота направо и при изменении положения колес из позиции для левого поворота в нейтральную, необходимо повернуть их вправо на один и тот же градус. Поэтому неплохо было бы оптимизировать этот блок, включив в него только "уникальные" действия. Но тогда для того, чтобы передавать действие, необходимое для выполнения в этом блоке, необходимо для него тоже завести код, подобные тем, что заводились для кодирование событий.
Где,
- Event = 0 – показания на сенсоре меньше 14 см.
- Event = 1 – показания на сенсоре больше 14 см., но меньше 16 см.
- Event = 2 – показания на сенсоре больше 16 см.
- Action = 0 – положение управляющих колес не изменяется
- Action = 1 – повернуть управляющие колеса вправо
- Action = 2 – повернуть управляющие колеса влево
- S0 – состояние движения прямо
- S1 – состояние выполнения поворота направо
- S1 – состояние выполнения поворота налево
Измененная диаграмма переходов, теперь может быть прочитана следующим образом:
Когда робот находится в состоянии S0, при наступлении события 0, робот переходит в состояние S1 и выполняет действие 1. Когда робот находится в состоянии S2, при наступлении события 0, робот переходит в состояние S1 и выполняет действие 3.
Как видно из диаграммы переходов, у каждого состояния-вершины есть стрелка-петля, сообщающая, что при определенном событии, робот продолжает находиться в данном состоянии. При этом все еще генерируется "управляющее" действие, которая правда в нашем конкретном случае можно охарактеризовать как бездействие – не изменять положение управлющих колес: при движении прямо колеса будут оставаться прямо, при повороте, колеса будут оставаться направленными в нужную сторону.
Прежде, чем писать программу, диаграмму переходов удбно в начале представить в виде следующих таблиц:
Какое будет новое состояние в зависимости от поступившего сигнала и предыдущего состояния: | Какое будет управляющее действие в зависимости от поступившего сигнала и предыдущего состояния: |
К сожалению, в NXT-G нет поддержки массивов, иначе бы программа выглядела еще компактнее. Вместо условий, которые позволяют оперировать таблицами описанными выше, в программе было бы просто извлечение соответствующих значений из массивов.
Например, двумерный массив States описывал бы как новое состояние зависит от пришедшего события и старого состояния, а двумерный массив Actions содержал бы в себе логику выбора действия для соответствующего события и состояния.
Тогда определение нужного действия и нового состояния выглядела бы следующим образом:
Action = Actions[Event][OldState]
NewState = States[Event][OldState]
Вывод: иногда, при поступлении одного и того же события, действия, выполняемые программой, должны быть разные, в зависимости от того, какие действия уже были выполнены (в каком состоянии программа находится) к текущему моменту работы программы, в каком . В таких случаях, схема работы программы должна учитывать предыдущее состояние программы для выбора "управляющего" действия и нового состояния. С другой стороны, действия при переходе из разных состояний могут быть одними и теми же, поэтому имеет смысл закодировать "уникальные" действия и использовать этот код в блоке определения действия. Расшифровка кода и выполнение действий, в таком случае, выносится в отдельный блок. Поскольку кодирование теперь используется как для событий, таки и для действий и состояний, то выбор действия и нового состояния выгодно описать двумя таблицами, которые позволяют существенно упростить логику программы, особенно, при возможности использовать массивы.
Комментариев нет:
Отправить комментарий