понедельник, 15 ноября 2010 г.

NXT-G: какая кнопка на NXT блоке нажата?

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




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




Но иногда возникает необходимость узнать, а нажата вообще какая-нибудь кнопка, если да, то какая? Например, когда с помошью одного NXT блока, посредством Bluetooth, выполняется управление роботом, оснащенным другим NXT блоком: нажатие на левую кнопку вызывает поворот налево, а на правую - поворо направо.
Базовый блок "NXT Buttons" не позволяет это сделать за один запрос. Следовательно, необходимо такую функциональность реализовать.

Если попытаться составить алгоритм выяснения состояния кнопок, то он может выглядеть следующим образом:
1. Опросить состояние левой кнопки, если она нажата перейти к пункту 5
2. Опросить состояние правой кнопки, если она нажата перейти к пункту 5
3. Опросить состояние средней кнопки, если она нажата перейти к пункту 5
4. Если ни одна из кнопок не нажата, вернуть это состояние в основную программу
5. Вернуть в основную программу какая кнопка нажата.

Как видно, данная реализация после опроса состояния всех кнопок, возвращает извещение о том, какая нажата. Каким образом лучше закодировать это извещенение?

Дело в том, что NXT-G уже оперирует цифрами 1, 2 и 3 для того, чтобы обозначить кнопки на NXT блоке.
1 - Right
2 - Left
3 - Select
Поэтому, удобно, чтобы реализация алгоритма описанного выше, тоже использовала эти значения. Тогда, пусть она возвращает
1 - если нажата правая кнопка,
2 - если нажата левая кнопка,
3 - если нажата средняя кнопка.
В дополнение, необходим число, которым можно было бы закодировать состояние, что никакая кнопка не нажата. Пусть таким числом будет "0".

Теперь, для последовательного опроса кнопок, можно воспользоваться фактом, что при программировании блока "NXT Buttons" через канал данных передается код кнопки, состояние которой необходимо узнать. Поскольку кнопок всего три, можно опрашивать их в цикле: сначал кнопку с кодом 1 (правую), затем кнопку с кодом 2 (левую) и т.д. Как только найдено, что какая-то кнопка нажата, дальнейший обход по циклу не имеет смысла, поэтому он завершается.
Также нужно помнить, что счетчик цикла начинается с нуля, в то время как для опроса необходимо работать с номерами от "1".

Итак, опрос состояния кнопок:


Поскольку, цикл завершается по любому из условий: "нажатая кнопка обнаружена" или "все три кнопки опрошены", то такое составное условие будет выглядеть так:


Хотя каждая итерация цикла и выполняется довольно быстро, вполне вероятно событие, что конкретная кнопка была нажата только между двумя соседними опросами ее состояния, т.е. на момент самого опроса она не зажата. Это поведение совпадает с шаблоном состояния Bumped. Следовательно, каждую кнопку нужно проверять на два состояния - номер кнопки возвращается если кнопка зажата (Pressed) или нажата (Bumped).


Теперь нужно получить номер нажатой кнопки или "0", если ни одна кнопка не нажата. Очевидно, что нужно выяснить по какому условию произошел выход из цикла: по достижению конца всех допустимых итерация (выполнено все три итерации цикла) или же по выявлению нажатой кнопки. Поскольку на момент завершения цикла одно из этих условий уже Истина (True), можно это использовать для определения, что возвращается как результат алгоритма: "0" или номер кнопки.


Если оформлять данную реализацию как процедуру (через MyBlock), то необходимо, чтобы в качестве выхода из нее шел один (в данном конкретном случае) канал данных. Т.е. он должен выходить из условия, рассмотренного выше. Чтобы не заводить ненужные сущности, такие как переменные, внутри этого условия, можно использовать прием преобразования счетчика цикла в выходные данные: для получения нуля - счетчик умножается на ноль, для получения номера клавиши - к счетчику прибавляется единица, точнее берется уже инкрементированное значение и увеличивается на ноль. Тогда из условия выходит только один канал данных с нужным числом.


Целиком содержимое нового блока будет выглядеть следующим образом:


В таком виде его можно использовать, например, чтобы перемещать фигурку по экрану:

- В цикле опрашивается не была ли нажата какая-то кнопка.
- Если нажата левая кнопка (третья вкладка), уменьшаем Xcoord, ответственный за координату Х, перемещаемой фигуры

- Если нажата правая кнопка (вторая вкладка), увеличиваем Xcoord
- Возрващаемые значения "0" (первая вкладка) и "3" (четвертая вкладка) игнорируются - значение Xcoord не изменяется.
Важно также отметить, что Xcoord изменяется только тогда, когда фигура находится все еще в зоне видимости на экране. Т.е. координата Х не должна принимать слишком маленьких и слишком больших значений.

7 комментариев:

  1. Интересно! А почему левая кнопка имеет высший приоритет, средняя высокий, а правая низкий? Что если нажато две или три кнопки?
    Мне кажется опрос лучше (если это возможно) проводить не последовательно, а параллельно и выдавать одно из значений 2³.

    ОтветитьУдалить
  2. Извиняюсь, попутал правую и среднюю кнопки, но смысл вопроса остаётся прежним.

    ОтветитьУдалить
  3. Спасибо за интересный комментарий! В настоящей жизни скорее всего именно так и пришлось бы делать. Но...
    Во-первых, приведенная выше реализация - одна из возможных. Это просто пример, никак не финальная реализация. С него могут начать те, кто желает разобраться в теме.
    Во-вторых, не известно будет ли вообще NXT блок обрабатывать корректно две нажатых кнопки одновременно. Кто-нибудь вполне может проверить это!
    В-третьих, дешифратор обработки выходных данных в приведенном Вами пример, это отдельная история, и что-то мне подсказывает, что на NXT-G она ничуть не проще, чем сам опрос кнопок.

    ОтветитьУдалить
  4. Как раз о дешифраторе я не беспокоюсь. На выходе будет число от 0 до 8 и думаю довольно просто догадаться об информации, которую несёт каждое из чисел.
    А вот на счёт возможности параллельного опроса я сомневаюсь, поэтому пояснил в скобках.
    Кстати клёвый сайт у Вас.

    ОтветитьУдалить
  5. ну скажем пришло число "2". Ясно, что оно значит, к примеру, нажата средняя и левая кнопка. В программе-то что делать? Нужно ведь отдельно обрабатывать и среднюю, и левую. Например и направление движения изменить и скорость прибавить. Как в программе это описать? Простой казалось бы switch превращается в непростой. Либо битовую арифметику вводить, а ее реализации в стандартной поставке NXT-G нет.

    ОтветитьУдалить
  6. Нет нет, я не в коем случае не намекаю на какой либо спор, тем более я впервые вижу код NXT-G, хотя могу себе представить, как он устроен.
    Дело в том, что я пытаюсь для себя определить возможности программирования на этом языке. Да, может быть битовую арифметику осуществить и не так просто, об этом я не подумал.
    Ну а нажатие нескольких кнопок можно интерпретировать как душе угодно, да хоть и никак не интерпретировать (то есть просто игнорировать), главное, что я предложил - это не приоритезировать кнопки.

    А вообще я размышляю над тем, чтобы подарить такой комплектик например своему сыну. Щупаю.

    ОтветитьУдалить
  7. Я понимаю...
    Приоритет имеет значение, только если имеет значение одновременная обработка нескольких клавишь или мгновенная обработка нажатой клавиши.
    В более простых случаях приоритет не важен.

    Эх! кто бы мне подарил такое чудо лет 15 назад. Сам тоже для сына засматриваюсь на такое. Но пока рано - мы с более простых Lego конструкторов начинаем. Был бы Lego WeDo в свободной продаже - может уже и сейчас для него приобрел.

    ОтветитьУдалить

Related Posts Plugin for WordPress, Blogger...