Связь
Связь

leJOS NXJ поддерживает связь с использованием Bluetooth и USB. Классы для осуществления связи в NXJ разработаны таким образом, что большая часть вашего кода не будет зависеть от того, какой тип связи используется Bluetooth или USB. Вы можете написать приложения, которые будут работать с обоими типами связи (см. пример ниже). Вы можете использовать потоки Java, они очень гибкие и ими легко пользоваться.

USB даёт преимущество в скорости связи, но через него можно соединить только NXT с PC. Bluetooth медленнее, но значительно гибче. Он поддерживает множество методов для коммуникации NXT с NXT, PC с NXT, мобильных телефонов с NXT, NXT с удалённым устройством, поддерживающим Bluetooth, и т.д.

Первый шаг - это установление соединения. У сое=динения всегда есть тот, кто устанавливает соединение - инициатор и тот, кто ожидает входящее соединение - ресивер (приёмник). Ресивер всегда ожидает когда инициатор запустит соединение. Инициатор соединяется с нужным ему устройством, при этом оно должно находиться в состоянии ожидания соединения. После того, как соединение установится, обе стороны соединения (и ресивер и инициатор) могут использовать его чтоб открыть потоки для ввода и вывода (чтения и записи данных, соответственно). В этом руководстве мы не рассматриваем случай, когда инициатор связи NXT, а PC - ресивер (хотя такое и возможно для соединений через Bluetooth). В большинстве случаев связи PC с NXT или мобильного телефона с NXT удобнее, когда NXT - ресивер, а PC или мобильный телефон - инициатор.

Программа инициатора может работать на PC (и должна работать на PC, если связь предполагается осуществлять через USB), также она может работать на другом NXT, на мобильном телефоне или другом устройстве, поддерживающем профиль Bluetooth Serial Port Profile (SPP). Некоторые внешние устройства, такие как GPS Bluetooth устройства могут работать только в качестве ресивера, так что при коммуникации с этими устройствами NXT должен всегда действовать как инициатор. Обратите внимание, что такие внешние устройства должны поддерживать профиль SPP - это единственный профиль, поддерживаемый "кирпичом" NXT.

NXT в роли ресивера (ответчика)

Программа ресивера на NXT переходит в режим ожидания соединения путём вызова метода waitForConnection() класса Bluetooth или USB. Вот сигнатуры этих методов:

  • BTConnection waitForConnection();

  • USBConnection waitForConnection();

Несмотря на то, что метод класса Bluetooth возвращает объект типа BTconnection, а метод класса USB возвращает объект типа USBConnection, оба этих возвращаемых типа (BTconnection и USBConnection) реализуют интерфейс NXTConnectiion. Таким образом, экземпляр любого из этих классов может быть назначен переменной, которая реализует этот интерфейс.

Пример для связи через Bluetooth:

NXTConnection connection = Bluetooth.waitForConnection();

Вам необходимо гарантировать, что питание Bluetooth включено и он находится в режиме "видимости" для других устройств, перед тем, как вызывать этот метод. Эти настройки вы можете найти в главном меню leJOS NXJ (подраздел start-up)

Пример для связи через USB:

NXTConnection connection = USB.waitForConnection();

Необходимо гарантировать, что кабель USB подключен перед тем, как вызывать этот метод.

Это пример программы, которая предлагает выбор соединения через USB либо Bluetooth во время работы:

import java.io.*;
import lejos.nxt.*;
import lejos.nxt.comm.*;

/**
 * sample of selecting channel at run time
 */
public class CommTest 
{
  public static void main(String[] args) { 
    LCD.drawString("right BT",0, 0);
    NXTConnection connection = null;

    if(Button.waitForAnyPress() == Button.ID_RIGHT){
      LCD.drawString("waiting for BT", 0,1 );
      connection = Bluetooth.waitForConnection();
    } else {
      LCD.drawString("waiting for USB", 0,1 );
      connection = USB.waitForConnection();
    }

    DataOutputStream dataOut = connection.openDataOutputStream();
    try {
      dataOut.writeInt(1234);
    } catch (IOException e ) {
      System.out.println(" write error "+e); 
    }
  }   
}

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

Потоки (Streams)

Как только соединение установлено, можно открыть потоки, путём вызова следующих методов интерфейса NXTConnection:

  • InputStream openInputStream() throws IOException;

  • OutputStream openOutputStream() throws IOException;

  • DataInputStream openDataInputStream() throws IOException; (the example above did this)

  • DataOutputStream openDataOutputStream() throws IOException;

Теперь можно читать данные из DataInputStream с помощью:

  • int read(byte b[]) throws IOException

  • int read(byte b[], int off, int len)throws IOException

  • boolean readBoolean() throws IOException

  • byte readByte() throws IOException

  • short readShort() throws IOException

  • readInt() throws IOException

  • char readChar() throws IOException

  • float readFloat() throws IOException

  • String readLine() throws IOException

Имейте в виду: Методы чтения из потока ввода-вывода (stream) являются блокирующими, то есть они не возвращают управление до тех пор, пока данные не будут считаны. Если у вашей программы есть другие задачи, требующие обработки во время ожидания данных, тогда вызов метода для чтения должен быть вызван в отдельном потоке выполнения (thread).

Данные можно записать в DataOutputStream с помощью следующих методов:

  • void write(byte b[], int off, int len) throws IOException

  • void writeBoolean(boolean v) throws IOException

  • void writeByte(int v) throws IOException

  • void writeShort(int v) throws IOException

  • void writeChar(int v) throws IOException

  • void writeInt(int v) throws IOException

  • void writeFloat(float v) throws IOException;

  • void writeChars (String value) throws IOException

Пример чтения и записи целых с использованием потоков ввода-вывода данных(предполагается, что dis и dos - это DataInputStream и DataOutputStream открытые заранее, до выполнения этого кода):

for(int i=0;i <100;i++) {
  int n = dis.readInt();
  LCD.drawInt(n,7,0,1);
  dos.writeInt(-n); 
  dos.flush();
}

Имейте в виду: чтоб действительно передать данные, записанные в поток вывода, необходимо вызвать метод flush (который освобождает буфер потока вывода путём вывода даных в канал связи). Таким образом, передача может не состояться без выдачи каких-либо исключений.

DataInputStream, DataOutputstream и NXTConnection могут быть закрыты вызовом метода close().

Полный пример организации связи с использованием Bluetooth:

import java.io.*;
import lejos.nxt.*;
import lejos.nxt.comm.*;

public class BTReceive {
  public static void main(String [] args) throws Exception {
    String connected = "Connected";
    String waiting = "Waiting...";
    String closing = "Closing...";

    while (true) {
      LCD.drawString(waiting,0,0);
      NXTConnection connection = Bluetooth.waitForConnection(); 
      LCD.clear();
      LCD.drawString(connected,0,0);

      DataInputStream dis = connection.openDataInputStream();
      DataOutputStream dos = connection.openDataOutputStream();

      for(int i=0;i<100;i++) {
        int n = dis.readInt();
        LCD.drawInt(n,7,0,1);
        dos.writeInt(-n);
        dos.flush();
      }
      dis.close();
      dos.close();

      LCD.clear();
      LCD.drawString(closing,0,0);

      connection.close();
      LCD.clear();
    }
  }
}

Чтоб изменить код этого примера для работы через USB, всё, что вам нужно, это изменить вызов Bluetooth.waitForConnection() на USB.waitForconnection()

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

NXT в роли инициатора

Чтоб инициировать Bluetooth-соединение с одного NXT на другой NXT, вам нужно в первую очередь добавить добавить NXT, работающий в роли ресивера (ответчика) в список Bluetooth устройств, "знакомых" NXT-кирпичу, работающему в роли инициатора.

Чтоб это сделать, надо зайти в меню, выбрать Bluetooth, затем выбрать "Search". На ответчике Bluetooth должен быть включен и видимость тоже должна быть включена. После того, как устройство будет найдено, можно будет выбрать "Add" чтоб добавить его в список Bluetooth-устройств инициатора.

Чтоб убедиться, что устройство добавилось в список, выберите Devices в меню Bluetooth (на инициаторе) и посмотрите появилось ли оно в списке.

Теперь можно создать экземпляр класса RemoteDevice на NXT-инициаторе:

Пример:

RemoteDevice btrd = Bluetooth.getKnownDevice(name);

Можно соединиться с удалённым устройством по его адресу, который можно получить вызвав:

  • public byte[] getDeviceAddr()

Можно соединиться с удалённым устройством путём вызова одного из методов connect() класса Bluetooth:

  • BTConnection connect(RemoteDevice remoteDevice)

  • BTConnection connect(byte[] device_addr)

  • BTConnection connect(byte[] device_addr, byte[] pin)

Пример:

RemoteDevice btrd = Bluetooth.getKnownDevice(name);

if (btrd == null) {
  LCD.clear();
  LCD.drawString("No such device", 0, 0);
  Button.waitForAnyPress();
  System.exit(1);
}

BTConnection btc = Bluetooth.connect(btrd);

if (btc == null) {
  LCD.clear();
  LCD.drawString("Connect fail", 0, 0);
  Button.waitForAnyPress();
  System.exit(1);
}

Получив объект BTconnection вы можете открыть потоки ввода-вывода данных как в вышеприведённом примере кода для ресивера (ответчика).

Полный код примера BTConnectTest, для выполнения на стороне-инициаторе ( совместимый с приведённым выше кодом ресивера) выглядит так:

import java.io.*;
import javax.bluetooth.*;
import lejos.nxt.*;
import lejos.nxt.comm.*;

public class BTConnectTest {
  public static void main(String[] args) throws Exception {
    String name = "NXT";
    LCD.drawString("Connecting...", 0, 0);
    RemoteDevice btrd = Bluetooth.getKnownDevice(name);

    if (btrd == null) {
      LCD.clear();
      LCD.drawString("No such device", 0, 0);
      Button.waitForAnyPress();
      System.exit(1);
    }

    BTConnection btc = Bluetooth.connect(btrd);

    if (btc == null) {
      LCD.clear();
      LCD.drawString("Connect fail", 0, 0);
      Button.waitForAnyPress();
      System.exit(1);
    }
  
    LCD.clear();
    LCD.drawString("Connected", 0, 0);

    DataInputStream dis = btc.openDataInputStream();
    DataOutputStream dos = btc.openDataOutputStream();

    for(int i=0;i<100;i++) {
      try { 
        LCD.drawInt(i*30000, 8, 0, 2);
        dos.writeInt(i*30000);
        dos.flush(); 
      } catch (IOException ioe) {
        LCD.drawString("Write Exception", 0, 0);
      }
    
      try {
        LCD.drawInt(dis.readInt(),8, 0,3);
      } catch (IOException ioe) {
        LCD.drawString("Read Exception ", 0, 0);
      }
    }
  
    try {
      LCD.drawString("Closing... ", 0, 0);
      dis.close();
      dos.close();
      btc.close();
    } catch (IOException ioe) {
      LCD.drawString("Close Exception", 0, 0);
    }
  
    LCD.drawString("Finished",3, 4);
    Button.waitForAnyPress();
  }
}

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

PC в роли инициатора

Программа для PC может иницииорвать соединение с NXT и открыть Java data stream.

API для PC отличается от API для NXT. Для уточнения смотрите pcapidocs и как компилировать и запускать PC API Programs

Чтоб соединиться с NXT, вам понадобится объект типа NXTComm который можно получить используя класс NXTCommFactory:

  • static NXTComm createNXTComm(int protocol)

Bluetooth инициатор

Объект класса NXTComm для соединения по Bluetooth можно получить путём вызова:

NXTComm nxtComm = NXTCommFactory.createNXTComm(NXTCommFactory.BLUETOOTH);

Причина использования здесь паттерна фабричный метод в том, что на PC существует несколько реализаций коммуникационного драйвера через Bluetooth и USB и то, какой драйвер будет выбран, зависит от того, какая используется операционная система и от содержимого файла nxj.properties.

Соединиться с NXT можно по адресу или путём выполнения запроса Bluetooth:

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

  • public NXTInfo(int protocol, String name, String address)

Пример:

NXTInfo nxtInfo = new NXTInfo(NXTCommFactory.BLUETOOTH, "NXT", "00:16:53:00:78:48");

Чтоб найти доступные для связи "кирпичи" NXT используя Bluetooth-запрос, надо сделать следующее:

NXTInfo[] nxtInfo = nxtComm.search("NXT");

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

USB-инициатор

Последовательность для инициатора через USB почти такая же, как для Bluetooth; просто вам нужно использовать USB вместо Bluetooth в вашем коде. Т.к. USB не может обращаться к устройствам по адресу, вы можете использовать имя "кирпича" NXT.

NXTComm nxtComm = NXTCommFactory.createNXTComm(NXTCommFactory.USB);

Чтоб найти доступные для связи NXT:

nxtComm.search("MYNXT");

Если в данный момент к компьютеру подключен только один "кирпич" NXT, тогда можно не передавать имя ("MYNXT"), а передать вместо него null.

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

Использование объекта NXTInfo

Как только вы получили объект класса NXTInfo, вы можете передать его в метод open() объекта класса NXTComm чтоб установить соединение с NXT:

  • public boolean open(NXTInfo nxt) throws NXTCommException;

Как только вы установили соединение, вы можете получить InputStream и OutputSttream, путём вызова методов getInputStream() и getOutputStream() объекта типа NXTComm.

  • public OutputStream getOutputStream();

  • public InputStream getInputStream();

Из этих потоков ввода-вывода вы можете создавать DataInputStream и DataOutputStream и посылать данные принимающему NXT.

Законченный пример BTSend находится в директории samples (пока что не понял где это прим. переводчика).

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

Более детально о связи

В этом разделе вы научитесь::

  • Управлять с одного NXT другим NXT посредством Bluetooth
  • Управлять внешним Bluetooth-устройством наподобие GPS-приёмника
  • Устанавливать связь между NXT-"кирпичом" и более старым RCX-"кирпичом"
Управление удалённым NXT

Класс RemoteNXT позволяет одному NXT, работающему под управлением leJOS NXJ управлять другим, удалённым NXT, работающим как под управлением leJOS, так и под управлением стандартной прошивки LEGO. Он использует LEGO Communications Protocol (LCP) поверх Bluetooth для управления удалённым NXT.

В настоящий момент, этот класс обладает ограниченной функциональностью: датчики, подключаемые по шине I2C, датчики от RCX не поддерживаются, двигатели должны использоваться самым простым способом, т.к. поток управления вращением двигателей там не используется.

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

  • public RemoteNXT(String name) throws IOException

Пример:

try {
  LCD.drawString("Connecting...", 0, 0);
  NXTCommConnector connector = Bluetooth.getConnector();
  RemoteNXT nxt = new RemoteNXT("NXT", connector);
  LCD.clear();
  LCD.drawString("Connected", 0, 0);
} catch (IOException ioe) {
  LCD.clear();
  LCD.drawString("Conn Failed", 0, 0);
  Button.waitForAnyPress();
  System.exit(1);
}

Имя удалённого NXT должно быть добавлено в список "знакомых" устройств NXT, инициирующего связь, путём выполнения поиска Bluetooth и добавления в список из подменю Bluetooth.

Конструктор открывает соединение и создаёт экземпляры удалённых моторов и портов датчиков.

Затем можно получить доступ к информации об удалённом NXT используя следующие методы:

  • public String getBrickName()

  • public String getBluetoothAddress()

  • public int getFlashMemory()

  • public String getFirmwareVersion()

  • public String getProtocolVersion()

Пример:

LCD.drawString(nxt.getBrickName(), 0, 6);
LCD.drawString(nxt.getFirmwareVersion(), 0, 7);
LCD.drawString(nxt.getProtocolVersion(), 4, 7);
LCD.drawInt(nxt.getFlashMemory(), 6, 8, 7);

Также есть методы, работающие на удалённом NXT:

  • public byte deleteFlashMemory()

Объект remote Battery позволяет узнать напряжение на батарее удалённого устройства, используя обычные методы "нормальной" батареи.

Пример:

LCD.drawString("Battery: " + nxt.Battery.getVoltageMilliVolt(), 0, 4);

Также создаются объекты для портов датчиков удалённого NXT. К ним можно обратиться как к S1, S2, S3 и S4.

Объекты ЛОКАЛЬНЫХ датчиков могут быть созданы на основе этих [удалённых] портов и использоваться в точности так же, как если бы они создавались на основе локальных портов.

Пример:

LightSensor light = new LightSensor(nxt.S1);
LCD.drawString("Light: " + light.readValue(),0,5);

Для удалённых моторов создаются объекты типа Motor. Они называются A, B и C.

Их можно использовать обычным способом:

nxt.A.setSpeed(360);
nxt.A.forward();
nxt.A.stop();
nxt.A.backward();

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

Внешние устройства Bluetooth

NXT может соединяться с внешними устройствами Bluetooth, которые поддерживают Serial Port Profile (SPP).

Такие устройства можно найти и добавить в список известных через меню Bluetooth.

Пример таких устройств - внешние Bluetooth GPS-приёмники. Они могут использоваться чтоб получить географическое местоположение робота.

leJOS поддерживает внешние Bluetooth GPS-приёмники, которые поддерживают протокол NMEA через классы GPS и NMEASentence. NMEASentence - это вспомогательный класс, используемый классом GPS и не доступный непосредственно.

Одно из таких устройств, которое было протестировано с leJOS NXJ - это Holux M-1200.

У большинства подобных устройств есть PIN-код, который надо ввести, чтоб соединиться с ними, но, возможно, что там установлено значение по умолчанию, например как 0000.

Чтоб соединиться с GPS устройством, сделайте следующее:

final byte[] pin = {(byte) '0', (byte) '0', (byte) '0', (byte) '0'};
RemoteDevice btGPS = Bluetooth.getKnownDevice(name); 

if (btGPS == null) {
  LCD.drawString("No such device", 0, 0);
  Button.waitForAnyPress();
  System.exit(1);
}

BTConnection btCon = Bluetooth.connect(btGPS.getDeviceAddr(), NXTConnection.RAW, pin);

if(btCon == null) {
  LCD.drawString("No Connection", 0, 1);
  Button.waitForAnyPress();
  System.exit(1);
}

LCD.drawString("Connected!", 0, 1);

GPS gps = null;
InputStream in;

try {
  in = btCon.openInputStream();
  gps = new GPS(in);
  LCD.drawString("GPS Online", 0, 6);
} catch(Exception e) {
  LCD.drawString("GPS Connect Fail", 0, 6);
  Button.waitForAnyPress();
  System.exit(1);
}

Как вы видите из этого примера, конструктор класса GPS принимает input stream Bluetooth-соединения как параметр:

  • public GPS(InputStream in)

Класс GPS начинает свой поток выполнения и использует класс NMEASentence чтоб обработать сообщения (известные как sentences) от устройства Bluetooth.Обрабатываются такие сообщения как $GPGGA sentence, которые дают текущую широту, долготу и высоту.

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

  • public float getLatitude()

  • public float getLongitude()

  • public float getAltitude()

Можно также получить метку времени, соответствующую этим считанным значениям путём вызова метода:

  • public int getTime()

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

Связь с RCX

ИК связь с RCX может быть осуществлена с использованием адаптера Mindsensors NRLink RCX IR adapter. Программная абстракция этого устройства - класс RCXLink class. Его конструктора таков:

  • public RCXLink(I2CPort port)

Например:

RCXLink link = new RCXLink(SensorPort.S1);

NRLink-Nx поддерживает набор макросов в ROM и EEPROM которые могут быть использованы чтоб отправлять сообщения на RCX используя протокол LEGO RCX IR. Макросы EEPROM могут быть перезаписаны, что позволяет пользователю определить свои собственные макросы.

Макросы можно запускать путём:

  • public void runMacro(int addr)

Есть удобные методы для запуска ROM-макросов:

  • public void beep()

  • public void runProgram(int programNumber)

  • public void forwardStep(int id)

  • public void backwardStep(int id)

  • public void setRCXRangeShort()

  • public void setRCXRangeLong()

  • public void powerOff()

  • public void stopAllPrograms()

Новый макрос в диапазоне адресов EEPROM может быть определён так:

  • public void defineMacro(int addr, byte[] macro)

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

Hosted by uCoz