Программирование LEGO NXT роботов на языке NXC - Коммуникации между роботами — различия между версиями

Материал из roboforum.ru Wiki
Перейти к: навигация, поиск
(Создана новая страница размером =Коммуникации между роботами= If you own more than one NXT this chapter is for you (though you can still communic...)
 
(Отправка чисел с подтверждением)
 
(не показано 10 промежуточных версий этого же участника)
Строка 1: Строка 1:
 +
<p align=center><b>Автор: Daniele Benedettelli</b><br><br><i>Перевод: © Ботов Антон aka =DeaD=, 2009<br><br>Эксклюзивно для www.roboforum.ru<br> копирование на другие ресурсы и публикация перевода<br>без разрешения его автора запрещены</i></p>
 +
 
=Коммуникации между роботами=
 
=Коммуникации между роботами=
If you own more than one NXT this chapter is for you (though you can still communicate data to the PC, having
+
Если у вас есть больше чем один модуль NXT, тогда эта глава для вас (хотя вообще можно устанавливать связь не только между роботами, но и робота с ПК). Роботы могут связываться друг с другом через радиоканал Bluetooth: так что вы можете иметь нескольких роботов одновременно выполняющих общую задачу (или сражающихся друг с другом), кроме того вы можете построить большого сложного робота из двух NXT, так что можно будет использовать 6 сервомоторов и 8 сенсоров.
a single NXT). Robots can communicate with each other via Bluetooth radio technology: you can have multiple
+
 
robots collaborate (or fight with each other), and you can build a big complex robot using two NXTs, so that you
+
Для старого доброго RCX, это очень просто: он отправляет ИК-сообщение и все роботы вокруг принимают его.
can use six motors and eight sensors.
+
 
For good old RCX, it is simple: it sends an InfraRed message and all robots around receive it.
+
Но в NXT реализован совершенно другой подход! Во-первых вам нужно соединить два или более NXT (или NXT и ПК) с помощью меню "Bluetooth" на модуле NXT; только тогда вы сможете отправлять сообщения к подключенным устройствам.
For NXT it's a whole different thing! First, you must connect two or more NXTs (or NXT to PC) with the
+
 
onbrick Bluetooth menu; only then you can send messages to connected devices.
+
NXT который инициирует подключение называется Мастером, и может иметь до 3 подчиненных устройств, подключенных к линиям 1,2 и 3. Подчиненный модуль всегда видит мастера на линии 0. Вы можете отправлять сообщения в 10 доступных ячеек.
The NXT that starts the connection is called Master, and can have up to 3 Slave devices connected on lines 1,2,3;
+
 
Slaves always see the Master connected on line 0. You can send messages to 10 mailboxes available.
+
==Отправка сообщений мастер-подчиненный==
==Master – Slave messaging==
+
Ниже приведены 2 программы - одна для мастера, а вторая для подчиненного. Эти простые программы покажут вам, как быстрый непрерывный поток строковых сообщений может быть передан с помощью радиоканала между двумя модулями NXT.
Two programs will be shown, one for the master, one for the slave. These basic programs will teach you how a
+
 
fast continuous stream of string messages can be managed by a two-NXT wireless network.
+
Программа для мастера сначала убеждается, что подчиненный правильно подключен на 1 линию (константа BT_CONN) используя функцию
The master program first checks if the slave is correctly connected on line 1 (BT_CONN constant) using
+
BluetoothStatus(conn); после чего создает и отправляет сообщения состоящие из префикса "M" и возрастающих чисел с помощью функции
BluetoothStatus(conn) function; then builds and sends messages with a M prefix and a growing number
+
SendRemoteString(conn,queue,string), одновременно получая сообщения от подчиненного функцией ReceiveRemoteString(queue,clear,string) и отображая эту информацию.
with SendRemoteString(conn,queue,string), while receives messages from slave with
+
 
ReceiveRemoteString(queue,clear,string) and displays data.
+
//MASTER
//MASTER
+
#define BT_CONN 1
#define BT_CONN 1
+
#define INBOX 1
#define INBOX 1
+
#define OUTBOX 5
#define OUTBOX 5
+
sub BTCheck(int conn){
+
sub BTCheck(int conn){
if (!BluetoothStatus(conn)==NO_ERR){
+
  if (!BluetoothStatus(conn)==NO_ERR){
TextOut(5,LCD_LINE2,"Error");
+
    TextOut(5,LCD_LINE2,"Error");
Wait(1000);
+
    Wait(1000);
Stop(true);
+
    Stop(true);
}
+
  }
}
+
}
task main(){
+
string in, out, iStr;
+
task main(){
int i = 0;
+
  string in, out, iStr;
BTCheck(BT_CONN); //check slave connection
+
  int i = 0;
while(true){
+
  BTCheck(BT_CONN); //check slave connection
iStr = NumToStr(i);
+
  while(true){
out = StrCat("M",iStr);
+
    iStr = NumToStr(i);
TextOut(10,LCD_LINE1,"Master Test");
+
    out = StrCat("M",iStr);
TextOut(0,LCD_LINE2,"IN:");
+
    TextOut(10,LCD_LINE1,"Master Test");
TextOut(0,LCD_LINE4,"OUT:");
+
    TextOut(0,LCD_LINE2,"IN:");
ReceiveRemoteString(INBOX, true, in);
+
    TextOut(0,LCD_LINE4,"OUT:");
SendRemoteString(BT_CONN,OUTBOX,out);
+
    ReceiveRemoteString(INBOX, true, in);
TextOut(10,LCD_LINE3,in);
+
    SendRemoteString(BT_CONN,OUTBOX,out);
TextOut(10,LCD_LINE5,out);
+
    TextOut(10,LCD_LINE3,in);
Wait(100);
+
    TextOut(10,LCD_LINE5,out);
i++;
+
    Wait(100);
}
+
    i++;
}
+
  }
The slave program is very similar, but uses SendResponseString(queue,string) instead of
+
}
SendRemoteString because slave must can send messages only to its master, seen on line 0.
+
 
 +
Программа подчиненного модуля очень похожа, но использует функцию SendResponseString(queue,string) вместо
 +
SendRemoteString, потому что подчиненный может отправлять сообщения только мастеру, находящемуся на линии 0.
 +
 
 +
//SLAVE
 +
#define BT_CONN 1
 +
#define INBOX 5
 +
#define OUTBOX 1
 +
 +
sub BTCheck(int conn){
 +
  if (!BluetoothStatus(conn)==NO_ERR){
 +
    TextOut(5,LCD_LINE2,"Error");
 +
    Wait(1000);
 +
    Stop(true);
 +
  }
 +
}
 +
 +
task main(){
 +
  string in, out, iStr;
 +
  int i = 0;
 +
  BTCheck(0); //check master connection
 +
  while(true){
 +
    iStr = NumToStr(i);
 +
    out = StrCat("S",iStr);
 +
    TextOut(10,LCD_LINE1,"Slave Test");
 +
    TextOut(0,LCD_LINE2,"IN:");
 +
    TextOut(0,LCD_LINE4,"OUT:");
 +
    ReceiveRemoteString(INBOX, true, in);
 +
    SendResponseString(OUTBOX,out);
 +
    TextOut(10,LCD_LINE3,in);
 +
    TextOut(10,LCD_LINE5,out);
 +
    Wait(100);
 +
    i++;
 +
  }
 +
}
 +
 
 +
Как можно заметить, при отключении программы на одно из сторон, вторая сторона продолжит отправлять сообщения с возрастающими номерами, не зная, что все сообщения теряются, потому что на той стороне никто их не принимает.
 +
Чтобы избежать этой проблемы мы планируем улучшить протокол с помощью подтверждения доставки.
 +
 
 +
==Отправка чисел с подтверждением==
 +
Как мы видим в приведенной ниже паре программ: в этот раз мастер отправлять числа командой SendRemoteNumber(conn,queue,number) и останавливается, ожидая подтверждения получения от подчиненного (цикл until, внутри которого мы видим ReceiveRemoteString); только если на той стороне подчиненный работает и отправил нам подтверждение - мастер переходит к отправке следующего сообщения. Подчиненный просто получает числа фукнцией ReceiveRemoteNumber(queue,clear,number) и отправляет подтверждение командой SendResponseNumber. Обе программы должны иметь общий код для подтверждения. В нашем случае я принял 0xFF в качестве такого кода.
 +
 
 +
Мастер отправляет случайные числа и ждёт подтверждение подчиненного; каждый раз после этого переменная ack должна быть очищена, иначе мастер продолжит отправлять сообщения не ожидая больше никаких подтверждений, потому что мы забыли очистить эту переменну.
 +
 
 +
Подчиненный в бесконечном цикле проверяет ячейку и если она не пуста, показывает значение на экран и отправляет мастеру подтверждение о получении. В начале программы я отправил подтверждение без информации, которую подтверждаю, чтобы разблокировать мастера. Без этого, если бы мастер запустился раньше - первое его сообщение было бы отправлено в никуда и он бы начал ждать ответа, а подчиненный запустился бы и начал ждать первое сообщение, так что всё бы "зависло", даже если подчиненный нормально запущен. То как мы сделали сейчас - может привести к потере части сообщений, но хотя-бы нет риска зависания пары модулей.
 +
 
 +
//MASTER
 +
#define BT_CONN 1
 +
#define OUTBOX 5
 +
#define INBOX 1
 +
#define CLEARLINE(L) \
 +
TextOut(0,L," ");
 +
 +
sub BTCheck(int conn){
 +
  if (!BluetoothStatus(conn)==NO_ERR){
 +
    TextOut(5,LCD_LINE2,"Error");
 +
    Wait(1000);
 +
    Stop(true);
 +
  }
 +
}
 +
 +
task main(){
 +
  int ack;
 +
  int i;
 +
  BTCheck(BT_CONN);
 +
  TextOut(10,LCD_LINE1,"Master sending");
 +
  while(true){
 +
    i = Random(512);
 +
    CLEARLINE(LCD_LINE3);
 +
    NumOut(5,LCD_LINE3,i);
 +
    ack = 0;
 +
    SendRemoteNumber(BT_CONN,OUTBOX,i);
 +
    until(ack==0xFF) {
 +
      until(ReceiveRemoteNumber(INBOX,true,ack) == NO_ERR);
 +
    }
 +
    Wait(250);
 +
  }
 +
}
 +
 
 +
//SLAVE
 +
#define BT_CONN 1
 +
#define OUT_MBOX 1
 +
#define IN_MBOX 5
 +
 +
sub BTCheck(int conn){
 +
  if (!BluetoothStatus(conn)==NO_ERR){
 +
    TextOut(5,LCD_LINE2,"Error");
 +
    Wait(1000);
 +
    Stop(true);
 +
  }
 +
}
 +
 +
task main(){
 +
  int in;
 +
  BTCheck(0);
 +
  TextOut(5,LCD_LINE1,"Slave receiving");
 +
  SendResponseNumber(OUT_MBOX,0xFF); //unblock master
 +
  while(true){
 +
    if (ReceiveRemoteNumber(IN_MBOX,true,in) != STAT_MSG_EMPTY_MAILBOX) {
 +
      TextOut(0,LCD_LINE3," ");
 +
      NumOut(5,LCD_LINE3,in);
 +
      SendResponseNumber(OUT_MBOX,0xFF);
 +
    }
 +
    Wait(10); //take breath (optional)
 +
  }
 +
}
  
//SLAVE
+
==Прямые команды==
#define BT_CONN 1
+
Вот еще одна отличная возможность доступная при использовании Bluetooth: мастер может напрямую контролировать подчиненных.
#define INBOX 5
+
В этом примере мастер отправляет подчиненным прямые команды для проигрывания звуков, включения двигателей и для подчиненного модуля NXT даже не нужно писать никакой программы. Это всё реализуется встроенным в NXT программным обеспечением!
#define OUTBOX 1
 
sub BTCheck(int conn){
 
if (!BluetoothStatus(conn)==NO_ERR){
 
TextOut(5,LCD_LINE2,"Error");
 
Wait(1000);
 
Stop(true);
 
}
 
}
 
task main(){
 
string in, out, iStr;
 
int i = 0;
 
BTCheck(0); //check master connection
 
while(true){
 
iStr = NumToStr(i);
 
out = StrCat("S",iStr);
 
TextOut(10,LCD_LINE1,"Slave Test");
 
TextOut(0,LCD_LINE2,"IN:");
 
TextOut(0,LCD_LINE4,"OUT:");
 
ReceiveRemoteString(INBOX, true, in);
 
SendResponseString(OUTBOX,out);
 
TextOut(10,LCD_LINE3,in);
 
TextOut(10,LCD_LINE5,out);
 
Wait(100);
 
i++;
 
}
 
}
 
You will notice that aborting one of the programs, the other will continue to send messages with growing
 
numbers, without knowing that all the messages sent will be lost, because no one is listening on the other side.
 
To avoid this problem, we could plan a finer protocol, with delivery acknowledgement.
 
==Sending numbers with acknowledgement==
 
Here we see another couple of programs: this time master sends numbers with
 
SendRemoteNumber(conn,queue,number) and stops waiting for slave ack (until cycle, inside which we
 
find ReceiveRemoteString); only if slave is listening and sending acks, the master proceeds sending the next
 
message. Slave simply receives number with ReceiveRemoteNumber(queue,clear,number) and sends
 
the ack with SendResponseNumber. Your master-slave programs must agree on the common code for the
 
ack, in this case, I choose the hex value 0xFF.
 
The master sends random numbers and waits for slave ack; every time it receives an ack with the right code, the
 
ack variable must be cleared, otherwise the master will continue sending without new acks, because the variable
 
got dirty.
 
The slave checks continuously the mailbox and, if it is not empty, displays the read value and sends an ack to the
 
master. At the beginning of the program, I choose to send an ack without reading messages to unblock the
 
master; in fact, without this trick, if the master program is started for first, it would hang even if we start slave
 
later. This way the first few messages get lost, but you can start master and slave programs in different moments
 
without the risk of hanging.
 
  
//MASTER
+
//MASTER
#define BT_CONN 1
+
#define BT_CONN 1
#define OUTBOX 5
+
#define MOTOR(p,s) RemoteSetOutputState(BT_CONN, p, s, \
#define INBOX 1
+
OUT_MODE_MOTORON+OUT_MODE_BRAKE+OUT_MODE_REGULATED, \
#define CLEARLINE(L) \
+
OUT_REGMODE_SPEED, 0, OUT_RUNSTATE_RUNNING, 0)
TextOut(0,L," ");
+
sub BTCheck(int conn){
+
sub BTCheck(int conn){
if (!BluetoothStatus(conn)==NO_ERR){
+
  if (!BluetoothStatus(conn)==NO_ERR){
TextOut(5,LCD_LINE2,"Error");
+
    TextOut(5,LCD_LINE2,"Error");
Wait(1000);
+
    Wait(1000);
Stop(true);
+
    Stop(true);
}
+
  }
}
+
}
task main(){
+
int ack;
+
task main(){
int i;
+
  BTCheck(BT_CONN);
BTCheck(BT_CONN);
+
  RemotePlayTone(BT_CONN, 4000, 100);
TextOut(10,LCD_LINE1,"Master sending");
+
  until(BluetoothStatus(BT_CONN)==NO_ERR);
while(true){
+
  Wait(110);
i = Random(512);
+
  RemotePlaySoundFile(BT_CONN, "! Click.rso", false);
CLEARLINE(LCD_LINE3);
+
  until(BluetoothStatus(BT_CONN)==NO_ERR);
NumOut(5,LCD_LINE3,i);
+
  //Wait(500);
ack = 0;
+
  RemoteResetMotorPosition(BT_CONN,OUT_A,true);
SendRemoteNumber(BT_CONN,OUTBOX,i);
+
  until(BluetoothStatus(BT_CONN)==NO_ERR);
until(ack==0xFF) {
+
  MOTOR(OUT_A,100);
until(ReceiveRemoteNumber(INBOX,true,ack) == NO_ERR);
+
  Wait(1000);
}
+
  MOTOR(OUT_A,0);
Wait(250);
+
}
}
 
}
 
//SLAVE
 
#define BT_CONN 1
 
#define OUT_MBOX 1
 
#define IN_MBOX 5
 
sub BTCheck(int conn){
 
if (!BluetoothStatus(conn)==NO_ERR){
 
TextOut(5,LCD_LINE2,"Error");
 
Wait(1000);
 
Stop(true);
 
}
 
}
 
task main(){
 
int in;
 
BTCheck(0);
 
TextOut(5,LCD_LINE1,"Slave receiving");
 
SendResponseNumber(OUT_MBOX,0xFF); //unblock master
 
while(true){
 
if (ReceiveRemoteNumber(IN_MBOX,true,in) != STAT_MSG_EMPTY_MAILBOX) {
 
TextOut(0,LCD_LINE3," ");
 
NumOut(5,LCD_LINE3,in);
 
SendResponseNumber(OUT_MBOX,0xFF);
 
}
 
Wait(10); //take breath (optional)
 
}
 
}
 
  
==Direct commands==
 
There's another cool feature about Bluetooth communication: master can directly control its slaves.
 
In the next example, the master sends the slave direct commands to play sounds and move a motor; there is no
 
need for a slave program, since it is the firmware of the slave NXT to receive and manage messages!
 
//MASTER
 
#define BT_CONN 1
 
#define MOTOR(p,s) RemoteSetOutputState(BT_CONN, p, s, \
 
OUT_MODE_MOTORON+OUT_MODE_BRAKE+OUT_MODE_REGULATED, \
 
OUT_REGMODE_SPEED, 0, OUT_RUNSTATE_RUNNING, 0)
 
sub BTCheck(int conn){
 
if (!BluetoothStatus(conn)==NO_ERR){
 
TextOut(5,LCD_LINE2,"Error");
 
Wait(1000);
 
Stop(true);
 
}
 
}
 
task main(){
 
BTCheck(BT_CONN);
 
RemotePlayTone(BT_CONN, 4000, 100);
 
until(BluetoothStatus(BT_CONN)==NO_ERR);
 
Wait(110);
 
RemotePlaySoundFile(BT_CONN, "! Click.rso", false);
 
until(BluetoothStatus(BT_CONN)==NO_ERR);
 
//Wait(500);
 
RemoteResetMotorPosition(BT_CONN,OUT_A,true);
 
until(BluetoothStatus(BT_CONN)==NO_ERR);
 
MOTOR(OUT_A,100);
 
Wait(1000);
 
MOTOR(OUT_A,0);
 
}
 
 
==Подводим итоги==
 
==Подводим итоги==
In this chapter we studied some of the basic aspects of Bluetooth communication between robots: connecting
+
В этой главе вы изучили некоторые простые аспекты использования Bluetooth для связи между роботами. Мы соединили по радиоканалу 2 модуля NXT, отправляли и принимали строки и числа, ожидали подтверждение получения. Последнее очень важно в случае необходимости в надежном канале передачи информации.
two NXTs, sending and receiving strings, numbers and waiting for delivery ackowledgments. This last aspect is
+
 
very important when a secure communication protocol is needed.
+
В качестве дополнительной возможности вы также научились отдавать мастером прямые команды для подчиненного модуля NXT.
As extra feature, you also learned how to send direct commands to a slave brick.
 

Текущая версия на 09:15, 20 мая 2009

Автор: Daniele Benedettelli

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

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

Коммуникации между роботами

Если у вас есть больше чем один модуль NXT, тогда эта глава для вас (хотя вообще можно устанавливать связь не только между роботами, но и робота с ПК). Роботы могут связываться друг с другом через радиоканал Bluetooth: так что вы можете иметь нескольких роботов одновременно выполняющих общую задачу (или сражающихся друг с другом), кроме того вы можете построить большого сложного робота из двух NXT, так что можно будет использовать 6 сервомоторов и 8 сенсоров.

Для старого доброго RCX, это очень просто: он отправляет ИК-сообщение и все роботы вокруг принимают его.

Но в NXT реализован совершенно другой подход! Во-первых вам нужно соединить два или более NXT (или NXT и ПК) с помощью меню "Bluetooth" на модуле NXT; только тогда вы сможете отправлять сообщения к подключенным устройствам.

NXT который инициирует подключение называется Мастером, и может иметь до 3 подчиненных устройств, подключенных к линиям 1,2 и 3. Подчиненный модуль всегда видит мастера на линии 0. Вы можете отправлять сообщения в 10 доступных ячеек.

Отправка сообщений мастер-подчиненный

Ниже приведены 2 программы - одна для мастера, а вторая для подчиненного. Эти простые программы покажут вам, как быстрый непрерывный поток строковых сообщений может быть передан с помощью радиоканала между двумя модулями NXT.

Программа для мастера сначала убеждается, что подчиненный правильно подключен на 1 линию (константа BT_CONN) используя функцию BluetoothStatus(conn); после чего создает и отправляет сообщения состоящие из префикса "M" и возрастающих чисел с помощью функции SendRemoteString(conn,queue,string), одновременно получая сообщения от подчиненного функцией ReceiveRemoteString(queue,clear,string) и отображая эту информацию.

//MASTER
#define BT_CONN 1
#define INBOX 1
#define OUTBOX 5

sub BTCheck(int conn){
  if (!BluetoothStatus(conn)==NO_ERR){
    TextOut(5,LCD_LINE2,"Error");
    Wait(1000);
    Stop(true);
  }
}

task main(){
  string in, out, iStr;
  int i = 0;
  BTCheck(BT_CONN); //check slave connection
  while(true){
    iStr = NumToStr(i);
    out = StrCat("M",iStr);
    TextOut(10,LCD_LINE1,"Master Test");
    TextOut(0,LCD_LINE2,"IN:");
    TextOut(0,LCD_LINE4,"OUT:");
    ReceiveRemoteString(INBOX, true, in);
    SendRemoteString(BT_CONN,OUTBOX,out);
    TextOut(10,LCD_LINE3,in);
    TextOut(10,LCD_LINE5,out);
    Wait(100);
    i++;
  }
}

Программа подчиненного модуля очень похожа, но использует функцию SendResponseString(queue,string) вместо SendRemoteString, потому что подчиненный может отправлять сообщения только мастеру, находящемуся на линии 0.

//SLAVE
#define BT_CONN 1
#define INBOX 5
#define OUTBOX 1

sub BTCheck(int conn){
  if (!BluetoothStatus(conn)==NO_ERR){
    TextOut(5,LCD_LINE2,"Error");
    Wait(1000);
    Stop(true);
  }
}

task main(){
  string in, out, iStr;
  int i = 0;
  BTCheck(0); //check master connection
  while(true){
    iStr = NumToStr(i);
    out = StrCat("S",iStr);
    TextOut(10,LCD_LINE1,"Slave Test");
    TextOut(0,LCD_LINE2,"IN:");
    TextOut(0,LCD_LINE4,"OUT:");
    ReceiveRemoteString(INBOX, true, in);
    SendResponseString(OUTBOX,out);
    TextOut(10,LCD_LINE3,in);
    TextOut(10,LCD_LINE5,out);
    Wait(100);
    i++;
  }
}

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

Отправка чисел с подтверждением

Как мы видим в приведенной ниже паре программ: в этот раз мастер отправлять числа командой SendRemoteNumber(conn,queue,number) и останавливается, ожидая подтверждения получения от подчиненного (цикл until, внутри которого мы видим ReceiveRemoteString); только если на той стороне подчиненный работает и отправил нам подтверждение - мастер переходит к отправке следующего сообщения. Подчиненный просто получает числа фукнцией ReceiveRemoteNumber(queue,clear,number) и отправляет подтверждение командой SendResponseNumber. Обе программы должны иметь общий код для подтверждения. В нашем случае я принял 0xFF в качестве такого кода.

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

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

//MASTER
#define BT_CONN 1
#define OUTBOX 5
#define INBOX 1
#define CLEARLINE(L) \
TextOut(0,L," ");

sub BTCheck(int conn){
  if (!BluetoothStatus(conn)==NO_ERR){
    TextOut(5,LCD_LINE2,"Error");
    Wait(1000);
    Stop(true);
  }
}

task main(){
  int ack;
  int i;
  BTCheck(BT_CONN);
  TextOut(10,LCD_LINE1,"Master sending");
  while(true){
    i = Random(512);
    CLEARLINE(LCD_LINE3);
    NumOut(5,LCD_LINE3,i);
    ack = 0;
    SendRemoteNumber(BT_CONN,OUTBOX,i);
    until(ack==0xFF) {
      until(ReceiveRemoteNumber(INBOX,true,ack) == NO_ERR);
    }
    Wait(250);
  }
}
//SLAVE
#define BT_CONN 1
#define OUT_MBOX 1
#define IN_MBOX 5

sub BTCheck(int conn){
  if (!BluetoothStatus(conn)==NO_ERR){
    TextOut(5,LCD_LINE2,"Error");
    Wait(1000);
    Stop(true);
  }
}

task main(){
  int in;
  BTCheck(0);
  TextOut(5,LCD_LINE1,"Slave receiving");
  SendResponseNumber(OUT_MBOX,0xFF); //unblock master
  while(true){
    if (ReceiveRemoteNumber(IN_MBOX,true,in) != STAT_MSG_EMPTY_MAILBOX) {
      TextOut(0,LCD_LINE3," ");
      NumOut(5,LCD_LINE3,in);
      SendResponseNumber(OUT_MBOX,0xFF);
    }
    Wait(10); //take breath (optional)
  }
}

Прямые команды

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

//MASTER
#define BT_CONN 1
#define MOTOR(p,s) RemoteSetOutputState(BT_CONN, p, s, \
OUT_MODE_MOTORON+OUT_MODE_BRAKE+OUT_MODE_REGULATED, \
OUT_REGMODE_SPEED, 0, OUT_RUNSTATE_RUNNING, 0)

sub BTCheck(int conn){
  if (!BluetoothStatus(conn)==NO_ERR){
    TextOut(5,LCD_LINE2,"Error");
    Wait(1000);
    Stop(true);
  }
}

task main(){
  BTCheck(BT_CONN);
  RemotePlayTone(BT_CONN, 4000, 100);
  until(BluetoothStatus(BT_CONN)==NO_ERR);
  Wait(110);
  RemotePlaySoundFile(BT_CONN, "! Click.rso", false);
  until(BluetoothStatus(BT_CONN)==NO_ERR);
  //Wait(500);
  RemoteResetMotorPosition(BT_CONN,OUT_A,true);
  until(BluetoothStatus(BT_CONN)==NO_ERR);
  MOTOR(OUT_A,100);
  Wait(1000);
  MOTOR(OUT_A,0);
}

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

В этой главе вы изучили некоторые простые аспекты использования Bluetooth для связи между роботами. Мы соединили по радиоканалу 2 модуля NXT, отправляли и принимали строки и числа, ожидали подтверждение получения. Последнее очень важно в случае необходимости в надежном канале передачи информации.

В качестве дополнительной возможности вы также научились отдавать мастером прямые команды для подчиненного модуля NXT.