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

NXC: работаем с датчиками вращения мотора

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

На самом деле, чаще всего, все ограничится использованием двух из них:
  • MotorRotationCount - позволяет получить текущее значение с датчика вращения соответствующего мотора.
  • ResetRotationCount - сбрасывает текущее значение датчика вращения соответствующего мотора в 0.
Имеет смысл пояснить использование этих двух функций примером.
sub MoveHeadBack()
{
    OnRev(HEAD, HEAD_SPEED_REV);
    int Start;
    do {
        Start = MotorRotationCount(HEAD);
        Wait(100);
    } while (abs(MotorRotationCount(HEAD) - Start) > 5)
    Coast(HEAD);
    Wait(200);
    ResetRotationCount(HEAD);
    Wait(1);
}
Эта функция предназначена для того, чтобы сдвинуть выбрасывающий механизм робота для игры в крестики-нолики назад.
Поскольку до запуска этой подпрограммы неизвестно, где находися механизм, он должен двигаться наза до тех пор пока не упрется в соответствующие ограничители движения.
Именно это происходит в цикле - через каждые 100 милисекунд проверяется на сколько повернулась ось двигателя со времени последнего измерения, и если поворот произошел меньше чем на 5 градусов, то значит выбрасывающий механизм уперся в ограничитель, и его нужно останавливать.

В конце функции происходит сброс счетчика поворотов мотора (просто для примера, на самом деле он здесь не обязателен).
Заметьте, что после сброса стоит пауза в 1 милисекунду, наличие которой может вызвать обоснованные вопросы.

Дело в том, что подобно функциям OnFwd() и OnRev(), сброс счетчика имеет асинхронную природу. Функция не дожидается реального сброса показаний сенсора, а просто модифицирует нужную область памяти, подразумевая, что модуль Output, запущенный виртуальной машиной блока NXT, обработает изменение памяти соответствующим образом, что приведет к реальному сбросу счетчиков.
Так вот, по своей природе, виртуальная машина NXT блока позволяет запускаться всем модулям не чаще, чем один раз в 1 мс. И если ResetRotationCount() вызывается в самом конце милисекундного интервала, то Output модуль вызовется практически сразу же после этой функции, что приведет почти к мгновенному сбросу счетчиков. А если ResetRotationCount() вызывается в начале этого интервала, то последующий вызов, например, MotorRotationCount() будет показывать старые значения и будет казаться, что ResetRotationCount() как будто бы не работает (англоязычное объяснение, описанного выше, можно найти на багртрекере BricxCC).
Те, кто привык все понимать через анализ рабочего кода, могут рассмотреть два примера:
  • Внешне выглядит, что показания счетчика не сбрасываются
    OnRev(OUT_A, 50);
    Wait(1000);
    TextOut(0, LCD_LINE1, MotorRotationCount(OUT_A));
    ResetRotationCount(OUT_A);
    TextOut(0, LCD_LINE2, MotorRotationCount(OUT_A));
  • Добавление паузы решает проблему
    OnRev(OUT_A, 50);
    Wait(1000);
    TextOut(0, LCD_LINE1, MotorRotationCount(OUT_A));
    ResetRotationCount(OUT_A);
    Wait(1);
    TextOut(0, LCD_LINE2, MotorRotationCount(OUT_A));

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

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

Related Posts Plugin for WordPress, Blogger...