Программирование LEGO NXT роботов на языке NXC - Дополнительная информация о сенсорах

Материал из roboforum.ru Wiki
Версия от 06:29, 20 мая 2009; =DeaD= (обсуждение | вклад) (Подключение нескольких сенсоров к одному входу)
Перейти к: навигация, поиск

Автор: Daniele Benedettelli

Перевод: © Ботов Антон aka =DeaD=, 2009

Эксклюзивно для www.roboforum.ru
копирование на другие ресурсы и публикация перевода
без разрешения его автора запрещены

Дополнительная информация о сенсорах

В главе 5 мы обсудили простейшие приёмы использования сенсоров, но на самом деле с ними можно делать намного больше. В этой главе мы обсудим отличие между режимом и типом сенсора, увидим как использовать старые RCX-совместимые сенсоры и подключать их к блоку NXT используя кабели "Lego converter cable".

Режимы и типы сенсоров

Команда SetSensor(), которую мы видели ранее, реально делает две вещи: она устанавливает тип сенсора и режим, в котором этот сенсор будет работать. Путём установки режима и типа сенсора отдельными полями вы можете более точно контролировать поведение сенсора, что полезно в различных задачах.

Тип сенсора устанавливается командой SetSensorType(). Существует множество различных типов, но я опишу только основные:

  • SENSOR_TYPE_TOUCH, сенсор касания,
  • SENSOR_TYPE_LIGHT_ACTIVE, датчик освещенности (с включенным светодиодом, т.е. работающий по отраженному свету),
  • SENSOR_TYPE_SOUND_DB, датчик звука и
  • SENSOR_TYPE_LOWSPEED_9V - ультразвуковой дальномер.

Установка типа сенсора важна для определения нужно ли подавать питание (включает светодиод в датчике освещенности), или для указания модулю NXT, что сенсор цифровой и надо работать с ним по протоколу I2C. Кроме всего прочего допускается использование с NXT сенсоров из старого набора, поставляемого с модулем RCX:

  • SENSOR_TYPE_TEMPERATURE, датчик температуры,
  • SENSOR_TYPE_LIGHT - старый датчик освещенности,
  • SENSOR_TYPE_ROTATION - датчик положения вала (датчик вращения) - этот тип мы обсудим позже.

Режим датчика задаётся командой SetSensorMode(). Существует 8 различных режимов. Наиболее важный - это SENSOR_MODE_RAW. В этом режиме, значение, которое вы получаете от сенсора является числом и лежит в диапазоне 0..1023. Это исходное значение, которое выдаёт датчик. Что оно означает - зависит от того, какой датчик подключен. Например, для датчика касания, когда он не нажат, значение близко к 1023, а когда полностью нажат - близко к 50. При частичном нажатии значение варьируется между 50 и 1000. Так что если вы установите датчик касания в этот режим, вы сможете определять, когда датчик нажат частично. С датчиком освещенности значение варьируется между 300 (очень светло) и 800 (очень темно). Это даёт гораздо значение большей точности, чем при использовании команды SetSensor(). Для более подробной информации смотрите инструкцию по программированию к языку NXC.

Второй режим работы сенсоров - SENSOR_MODE_BOOL. В этом режиме возвращаемое значение 0 или 1. Оно получается из исходного значения 0..1023 сравнением, если меньше 565, возвращается 0, иначе 1. SENSOR_MODE_BOOL является режимом по умолчанию для датчика касания, но может быть быть применен к любому другому сенсору, чтобы убрать аналоговую информацию и оставить двоичный ответ. Режимы SENSOR_MODE_CELSIUS и SENSOR_MODE_FAHRENHEIT полезны только для датчиков температуры и дают ответ в соответствующих единицах измерения. SENSOR_MODE_PERCENT превращает исходное значение 0..1023 в значение между 0 и 100, просто деля его на 1023. SENSOR_MODE_PERCENT является режимом по умолчанию для датчика освещенности. SENSOR_MODE_ROTATION используется только для сенсора вращения (см. ниже).

Есть еще два интересных режима: SENSOR_MODE_EDGE и SENSOR_MODE_PULSE. Они считают переходы между высоким и низким уровнем сигнала с датчика или наоборот. Например, когда мы нажимаете на датчик касания это вызывает переход с высокого к низкому уровню сигнала. Когда вы отпускаете его это вызывает обратный переход. Когда вы устанавливаете сенсор в режим SENSOR_MODE_PULSE, только переходы с низкого на высокий уровень считаются. Так что каждое нажатие и отпускание сенсора касания считается за 1. А когда вы устанавливаете режим датчика в SENSOR_MODE_EDGE, оба перехода засчитываются, т.е. когда вы нажимаете и отпускаете датчик - счетчик увеличивается на 2. Вы можете использовать этот режим для подсчета того, сколько раз нажимали на датчик касания. Или с датчиком освещенности вы можете посчитать как часто включали/выключали освещение. Разумеется, когда вы считаете количество срабатываний или переходов, у вас должна быть возможность сбросить счетчик в ноль. Для этого используйте команду ClearSensor(), которая сбрасывает счетчик для указанного датчика.

Давайте разберем пример. Следующая программа использует датчик касания для управления роботом. Соедините датчик касания длинным проводом со входом 1. Если быстро нажать датчик касания 2 раза - робот поедет вперед, если нажать 1 раз - остановится.

task main()
{
  SetSensorType(IN_1, SENSOR_TYPE_TOUCH);
  SetSensorMode(IN_1, SENSOR_MODE_PULSE);
  while(true)
  {
    ClearSensor(IN_1);
    until (SENSOR_1 > 0);
    Wait(500);
    if (SENSOR_1 == 1) {Off(OUT_AC);}
    if (SENSOR_1 == 2) {OnFwd(OUT_AC, 75);}
  }
}

Обратите внимание, что мы сначала установили тип, а только потом - режим работы датчика. Это важно, так как установка типа датчика автоматически сбрасывает режим в значение по умолчанию для этого типа датчика.

Сенсор вращения

Сенсор вращения это очень полезный вид датчика, представляющий из себя оптический энкодер, практический такой же, как встроенный в сервомоторы набора NXT. Датчик вращения имеет отверстие, в которое вы можете вставить вал, относительное угловое положение которого он может измеряет. Один полный оборот вала соответствует 16 шагам (или -16, если вращать в другую сторону), т.е. угловое разрешение датчика - 22.5 градуса, достаточно грубо, если сравнивать с разрешением энкодеров сервомоторов в 1 градус. Этот старый датчик вращения можно использовать для отслеживания положения вала без необходимости задействовать для этого сервомотор; кроме того не забывайте, что старый датчик ввиду отсутствия двигателя внутри гораздо легче вращается.

Если вам нужно большее разрешение, чем 16 шагов на оборот - вы всегда можете использовать шестерни, чтобы механически увеличить его.

Следующий пример унаследован из старого курса для RCX.

Одной из типичных ситуаций является размещение двух датчиков вращения на двух колёсах, которыми вы вращаете с помощью установленных на них же двигателей. Для прямолинейного движения вам нужно, чтобы колёса вращались с одинаково быстро. К сожалению, обычно моторы не вращаются одинаково. Используя датчики вращения вы можете отследить ситуацию, когда один мотор обгоняет другой. Вы можете временно приостановить этот мотор (лучше всего - используя команду Float()), пока оба датчика вращения не выдадут одинаковое значение. Следующая программа реализует этот подход к управлению двигателями. Она просто позволяет роботу ехать строго по прямой. Чтобы проверить её на роботе - подключите датчики вращения к моторам. Подцепите сенсоры на входы 1 и 3.

task main()
{
  SetSensor(IN_1, SENSOR_ROTATION); ClearSensor(IN_1);
  SetSensor(IN_3, SENSOR_ROTATION); ClearSensor(IN_3);
  while (true)
  {
    if (SENSOR_1 < SENSOR_3)
      {OnFwd(OUT_A, 75); Float(OUT_C);}
    else if (SENSOR_1 > SENSOR_3)
      {OnFwd(OUT_C, 75); Float(OUT_A);}
    else
      {OnFwd(OUT_AC, 75);}
  }
}

Программа сначала определяет, что оба датчика являются датчиками вращения, после чего сбрасывает их значения в 0. Потом запускается бесконечный цикл. В цикле мы проверяем, если значения датчиков совпадают - просто едем вперед. Если же один больше, чем другой - мы приостанавливаем соответствующий двигатель, пока другой не догонит его и датчики снова не покажут равные значения.

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

Подключение нескольких сенсоров к одному входу

Есть смысл сделать небольшое предупреждение перед тем, как вы приступите к чтению этого раздела! Из-за новой структуры улучшенных датчиков платформы NXT и кабелей на 6 линий, эта возможность стала сложнее, чем с RCX-набором подключать больше чем 1 датчик на порт модуля. По моему мнению единственное имеющее смысл и более менее простое применение указанной ниже информации - сборка разветвителя датчика касания с помощью кабеля конвертера. Альтернатива которому - полноценный цифровой мультиплексор, который может работать по протоколу I2C с модулем NXT, но это однозначно не лучшее решение для начинающих.

Модуль NXT имеет 4 входя для подключения датчиков. Когда вы хотите собрать более сложного робота (и купили несколько дополнительных датчиков) этого может оказаться недостаточно для вас. К счастью есть несколько трюков, с помощью которых вы можете подключить два (или даже больше) датчиков к одному входу.

Проще всего подключить два датчика касания к одному входу. Когда один (любой) из них нажат (или оба) - значение датчика будет 1, иначе 0. Вы не можете отличить какой датчик сработал, но иногда это и не нужно. Например, когда вы размещаете один датчик спереди, а второй сзади, вы можете понять каким стукнулись о препятствие по тому, куда вы сейчас ехали - вперед или назад. Еще вы можете установить режим сенсора RAW (см. выше). Теперь вы сможете получать больше информации. Если вам повезёт - значения нажатого и не нажатого сенсора будет разным для обоих сенсоров. Тогда вы сможете отличать какой из них нажат. А если нажаты сразу оба - вы получите намного меньшее значение (около 30) и тоже сможете это обнаружить.

Вы можете так же соединить датчик касания и датчик освещенности с одним входом (только для датчиков из набора RCX). Установите при этом тип сенсора "датчик света" (иначе датчик света не будет работать). Установите режим RAW. В этом случае, если нажат датчик касания - вы получите значение ниже 100. Если же он не нажат - вы получите значение датчика освещенности, которое никогда не бывает ниже 100. The following program uses this idea. The robot must be equipped with a light sensor pointing down, and a bumper at the front connected to a touch sensor. Connect both of them to input 1. The robot will drive around randomly within a light area. When the light sensor sees a dark line (raw value > 750) it goes back a bit. When the touch sensor touches something (raw value below 100) it does the same. Here is the program:

mutex moveMutex;
int ttt,tt2;

task moverandom()
{
  while (true)
  {
    ttt = Random(500) + 40;
    tt2 = Random();
    Acquire(moveMutex);
    if (tt2 > 0)
      { OnRev(OUT_A, 75); OnFwd(OUT_C, 75); Wait(ttt); }
    else
      { OnRev(OUT_C, 75); OnFwd(OUT_A, 75); Wait(ttt); }
    ttt = Random(1500) + 50;
    OnFwd(OUT_AC, 75); Wait(ttt);
    Release(moveMutex);
  }
}

task submain()
{
  SetSensorType(IN_1, SENSOR_TYPE_LIGHT);
  SetSensorMode(IN_1, SENSOR_MODE_RAW);
  while (true)
  {
    if ((SENSOR_1 < 100) || (SENSOR_1 > 750))
    {
      Acquire(moveMutex);
      OnRev(OUT_AC, 75); Wait(300);
      Release(moveMutex);
    }
  }
}

task main()
{
  Precedes(moverandom, submain);
}

I hope the program is clear. There are two tasks. Task moverandom makes the robot move around in a random way. The main task first starts moverandom, sets the sensor and then waits for something to happen. If the sensor reading gets too low (touching) or too high (out of the white area) it stops the random moves, backs up a little, and start the random moves again.

Подводим итоги

In this chapter we have seen a number of additional issues about sensors. We saw how to separately set the type and mode of a sensor and how this could be used to get additions information. We learned how to use the rotation sensor. And we saw how multiple sensors can be connected to one input of the NXT. All these tricks are extremely useful when constructing more complicated robots. Sensors always play a crucial role there.