Hardware: Ввод-вывод и сенсоры
Hardware: Ввод-вывод и сенсоры

В этом разделе описываются классы, предназначенные для ввода вывода и использования стандартных сенсоров NXT. В NXT есть кнопки для ввода информации, жидко-кристаллический индикатор (ЖКИ, LCD) и маленький динамик для вывода звука. В leJOS NXJ есть необходимые компоненты для работы со всеми этими аппаратными блоками.

ЖКИ(LCD)

Класс LCD не имеет экземпляров(есть всего лишь один ЖКИ в нашем устройстве NXT), поэтому все методы - статические. ЖКИ может использоваться в текстовом или графическом режимах.

Методы класса LCD предназначенные для работы с текстом

В качестве текстового дисплея ЖК-индикатор NXT может отображать 16 символов в ширину и 8 символов в высоту. Позиция задаётся через указание координат (x, y) следующим образом:

x может изменяться от 0 до 15, и y от 0 до 7.

Методы для записи в ЖКИ в текстовом режиме следующие:-

  • void drawString(String str, int x, int y)

    Этот метод выводит строку текста на ЖКИ начиная с позиции (x, y).

  • void drawInt(int i, int x, int y)

    Этот метод печатает целое число начиная с позиции (x,y). Число будет выровнено по левому краю и будет занимать столько символов, сколько необходимо для его вывода (т.е. никаких нулей или пробелов спереди числа не будет).

  • void drawInt(int i, int places, int x, int y)

    Этот вариант метода drawInt выравнивает число по правому краю перед тем, как вывести и при этом число занимает заданное количество знакомест. Это означает, что этот метод всегда печатает фиксированное число символов (вне зависимости от реальной длины числа), поэтому, если, например, в цикле этот метод вызывается несколько раз, то каждый раз он полностью стирает предыдущий вывод и печатает число заново.

  • void clear()

    Очищает ЖКИ.

Пример:

import lejos.nxt.LCD;

public class LCDTest {
  public static void main(String[] args) throws Exception {
    LCD.drawString("Free RAM:", 0, 0);
    LCD.drawInt((int) System.getRuntime().freeMemory(), 6, 9, 0);
    Thread.sleep(2000);
  }
}

Обратите внимание: можно также печатать текст на ЖКИ с помощью метода System.out.println(String str). Он прокручивает выведенный на дисплее текст на одну строчку вверх и печатает в самой нижней строке экрана.

Также имейте в виду, что по умолчанию ЖКИ обновляется автоматически. Если вы хотите вручную контролировать момент, когда произойдёт обновление информации на ЖКИ, вы можете настроить такое поведение вызовом LCD.setAutoRefresh(0) и затем сами вызывать каждый раз метод LCD.refresh() когда вам нужно обновить содержимое дисплея.

Наверх страницы

Методы класса LCD для вывода графики

В качестве графического дисплея ЖКИ NXT имеет 100 пикселей (точек) в ширину и 64 пикселя в высоту. Он адресуется через указание координат (x, y) пикселя аналогично текстовым методам:

x меняется от 0 до 99, y - от 0 до 63.

Чтоб отобразить графику на ЖКИ, вы можете использовать класс Graphics из пакета javax.microedition.lcdui. Смотрите API класса Graphics (на английском). С помощью этого класса вы можете рисовать линии, прямоугольники, дуги и выводить строчки с возможностью указывать место вывода с точностью до пикселя.

Пример:

import javax.microedition.lcdui.Graphics;

public class GraphicsSample {
	
  public static void main(String [] options) throws Exception {
    Graphics g = new Graphics();
    g.drawLine(5,5,60,60);
    g.drawRect(62, 10, 25, 35);
    Thread.sleep(2000);
  }
}

Наверх страницы

Кнопки

У класса Button есть четыре эксемпляра (объекта), к которым можно получить доступ через статические поля:

  • Button.ENTER
  • Button.ESCAPE
  • Button.LEFT
  • Button.RIGHT

Чтоб проверить, нажата ли кнопка, используйте метод:

  • boolean isDown()

Пример:

import lejos.nxt.Button;
import lejos.nxt.LCD;

public class ButtonPresses {
  public static void main(String[] args) throws Exception {
    while (true) {
      LCD.clear();
      if (Button.ENTER.isDown()) LCD.drawString("ENTER", 0, 0);
      if (Button.ESCAPE.isDown()) LCD.drawString("ESCAPE", 0, 0);
      if (Button.LEFT.isDown()) LCD.drawString("LEFT", 0, 0);
      if (Button.RIGHT.isDown()) LCD.drawString("RIGHT", 0, 0);
    }
  }
}

Чтоб дождаться, когда какая-либо конкретная кнопка будет нажата или отпущена, используйте метод:

  • void waitForPressAndRelease() throws InterruptedException

Пример:

import lejos.nxt.Button;
import lejos.nxt.LCD;

public class ButtonTest
{
	public static void main (String[] args)
	throws Exception
	{
		Button.ENTER.waitForPressAndRelease();		
		LCD.drawString("Finished", 3, 4);
		Thread.sleep(2000);
	}
}

Чтобы дождаться нажатия любой кнопки, используйте:

  • static int waitForPress()

    Этот метод возвращает код кнопки, которая была нажата.

button           ENTER     LEFT        RIGHT     ESCAPE

Code             1                 2               4                 8

Чтоб указать слушателя для обработки событий какой-либо конкретной кнопки используйте метод:

  • void addButtonListener (ButtonListener aListener)

    Смотрите раздел “Слушатели и события” если вам не понятно, как использовать механизм событий.

Чтоб прочитать текущее состояние всех кнопок, используйте метод:

  • static int readButtons()

    Возвращаемое значение - это сумма кодов всех кнопок, нажатых в данный момент.

Наверх страницы

Класс Sound (Звук)

Этот класс управляет единственным динамиком, поэтому у него нет экземпляров (объектов) и все его методы статические.

Чтоб проиграть единичный тон, используйте

  • void playTone(int aFrequency, int aDuration)

Пример:

import lejos.nxt.Sound;

public class PlayTones {

	private static final short[] note = {2349,115, 0,5, 1760,165, 0,35};

	public static void main(String [] args) throws Exception {
		for(int i=0;i <note.length; i+=2) {
			short w = note[i+1];
			int n = note[i];
			if (n != 0) {
				Sound.playTone(n, w*10);
			}
			Thread.sleep(w*10);
		}
	}
}

Есть два способа проиграть системный звук, первый:

  • void systemSound (boolean aQueued, int aCode)

    Параметр aQueued игнорируется в NXT, он нужен только для обратной совместимости с RXC.

Смыслы кодов такие:

code = 0            Короткий гудок
code = 1            Двойной гудок
code = 2            Descending arpeggio (убывающий арпеджио (наверно это музыкальный термин такой))
code = 3            Ascending arpeggio (возрастающий арпеджио)
code = 4            Длинный, низкий тон

Отдельные методы для проигрывания конкретных системных звуков (если вы не помните кодов):

  • void beep()

  • void twoBeeps()

  • void beepSequence()

  • void beepSequenceUp()

  • void buzz();int playSample(File aWAVfile)

  • int playSample(File aWAVfile, int volume)

Так же есть метод для того, чтоб воспроизвести отсутствие звука (период задаётся в милисекундах):

  • void pause(int time)

    Вы можете использовать этот метод в любой момент, когда вашей программе нужно подождать и вы не хотите возиться с оформлением блока try/catch, необходимого для вызова Thread.sleep().

В leJOS NXJ также есть методы, которые могут проигрывать 8-битные WAV-файлы:

  • int playSample(File aWAVfile)

  • int playSample(File aWAVfile, int volume)

Возвращаемое значение - это время проигрывания файла в милисекундах или значение< 0 в случае ошибки.

Чтоб проиграть музыкальную ноту, используйте метод:

  • void playNote(int[] inst,int freq, int len)

    Массив inst содержит значения параметров ноты: нарастания(attack), спада(decay), затягивания(sustain) и отпускания(release) - эти параметры характеризуют разные музыкальные инструменты. Статические константы для некоторых предопределённых инструментов называются: FLUTE, PIANO и XYLOPHONE. Вы можете экспериментировать с определением своих собственных значений.

Наверх страницы

класс Battery

Есть два статических метода для того, чтоб узнать напряжение на батарее:

  • int getVoltageMilliVolt()

  • float getVoltage()

Пример:

import lejos.nxt.Battery;
import lejos.nxt.LCD;

public class BatteryTest {
  public static void main(String[] args) throws Exception {
    LCD.drawString("Battery: " + Battery.getVoltage(), 0, 0);
    Thread.sleep(2000);
  }
}

Наверх страницы

Сенсоры

В комплекте конструктора Lego Mindstorms вместе с "кирпичом" NXT идут четыре типа сенсоров: сенсоры касания, сенсор звука, сенсор света и ультразвуковой сенсор. В leJOS NXJ есть классы, позволяющие эффективно использовать все эти типы сенсоров и многие другие, поставляемыми отдельно от конструктора. Дальше по тексту сами устройства будут называться датчиками, а абстракции, связанные с ними (классы) - сенсорами

Датчик должен быть подключен к порту и объект sensor должен знать, к какому порту подключен его датчик. Чтоб указать порт, передайте информацию о номере порта в конструктор сенсора при его создании. Возможные варианты: SensorPort.S1, S2, S3 или S4.

Датчик касания

Чтоб использовать сенсор касания, создайте его экземпляр, используя конструктор:

  • TouchSensor(SensorPort port)

Чтоб узнать, находится ли сенсор в состоянии срабатывания, используйте метод isPressed():

  • boolean isPressed()

Пример:

import lejos.nxt.LCD;
import lejos.nxt.SensorPort;
import lejos.nxt.TouchSensor;

public class TouchTest {
  public static void main(String[] args) throws Exception {
    TouchSensor touch = new TouchSensor(SensorPort.S1);
    while (!touch.isPressed()) {
    	// try again
    }
    LCD.drawString("Finished", 3, 4);
  }
}

Наверх страницы

Сенсор освещённости

Чтоб использовать сенсор света, создайте его экземпляр, используя конструктор:

  • public LightSensor(SensorPort port)

Пример:

import lejos.nxt.LCD;
import lejos.nxt.LightSensor;
import lejos.nxt.SensorPort;

public class LightTest {
  public static void main(String[] args) throws Exception {
    LightSensor light = new LightSensor(SensorPort.S1);

    while (true) {
      LCD.drawInt(light.getLightValue(), 4, 0, 0);
      LCD.drawInt(light.getNormalizedLightValue(), 4, 0, 1);
      LCD.drawInt(SensorPort.S1.readRawValue(), 4, 0, 2);
      LCD.drawInt(SensorPort.S1.readValue(), 4, 0, 3);
    }
  }
}

Наверх страницы

Датчик звука

Звуковой сенсор поддерживает два режима: DB и DBA. Эти режимы имеют разную АЧХ (амплитудно-частотную характеристику), поэтому, если вы хотите сделать какое-нибудь предположение о частоте слышимого звука, может иметь смысл задействовать оба режима (переключаясь между ними).

У этого класса есть два конструктора:

  • SoundSensor(SensorPort port)

    создаёт звуковой сенсор, работающий в режиме DB.

  • SoundSensor(SensorPort port, dba)

    создаёт звуковой сенсор, работающий в режиме DBA если второй параметр равен true.

Можно переключаться между режимами:

  • void setDBA(boolean dba)

Пример использования только режима DB:

Этот пример графически показывает, как меняется звук в течение двухсекундного периода.

import lejos.nxt.*;

public class SoundScope {
  public static void main(String[] args) throws Exception {
    SoundSensor sound = new SoundSensor(SensorPort.S1);

    while (!Button.ESCAPE.isDown()) {
      LCD.clear();
      for (int i = 0; i < 100; i++) {
        LCD.setPixel(1, i, 60 - (sound.readValue() / 2));
        Thread.sleep(20);
      }
    }
  }
}

Наверх страницы

Датчик ультразвука

Чтоб создать экземпляр, используйте этот конструктор:

  • UltrasonicSensor( Port aSensorPort)

Сенсор может работать в двух режимах: непрерывном (обычно работает в этом режиме) и в режиме пинга. В непрерывном режиме сенсор посылает пинги (зондирующие сигналы) так часто, как это возможно, и самый последний результат измерения можно прочитать используя метод:

  • int getDistance()

    Возвращаемое значение - в сантиметрах. Если эхо не пришло, возвращается значение 255. Максимальная дальность обнаружения объектов этим сенсором около 170 см.

Пример:

import lejos.nxt.*;

public class SonicTest {
  public static void main(String[] args) throws Exception {
    UltrasonicSensor sonic = new UltrasonicSensor(SensorPort.S1);

    while (!Button.ESCAPE.isDown()) {
      LCD.clear();
      LCD.drawString(sonic.getVendorID(), 0, 0);
      LCD.drawString(sonic.getProductID(), 0, 1);
      LCD.drawString(sonic.getVersion(), 0, 2);
      LCD.drawInt(sonic.getDistance(), 0, 3);
    }
  }
}

В режиме "пинга" зондирующий сигнал посылается только при вызове метода:

  • void ping()

    Этот метод переводит сенсор в режим "пинга" (посылки зондирующего импульса), посылает единичный импульс и затем пытается поймать до 8 эхо-сигналов. Это может быть сделано путём вызова

  • int readDistances(int [] distances)

    Вы передаёте массив целых чисел, в котором после возврата из метода будут результаты измерения. Необходима задержка около 20 милисекунд между вызовоми ping и getDistances. Эта задержка не включена ни в один из указанных методов. Вызов метода getDistances до того, как истечёт 20 мс может привести к ошибке либо данные не будут возвращены. Метод getDistance также может быть использован вместе с методом ping без использования данных массива, метод getDistance возвращает в качестве результата функции информацию о первом отражении.
    Вызов метода ping() отключает непрерывный режим зондирования, в котором система находится по умолчанию. Чтоб переключиться обратно в режим непрерывного зондирования, вызовите метод

  • int continuous()

Программа: множественные отражения

Напишите программу, которая показывает расстояния от нескольких отражений в колонку. Программа должна сделать четыре вызова ping(), и показать четыре колонки с результатами, затем дождаться нажатия кнопки и выйти, если была нажата кнопка ESCAPE.

Решение

Наверх страницы

Hosted by uCoz