NXC: BT NXT to NXT msg from slave to master

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

NXC: BT NXT to NXT msg from slave to master

Post by HaWe »

hi,
if I send a string from a BT slave to the master via outbox to the corresponding master's inbox is there a way to get an acknowledgement checksum number (for error checking) from the master immediately back?

Sending from the master to a slave it's clear - but how about other way round?

(on each slave I have 1 inbox and 2 outboxes,
the master has for each slave 1 outbox and 2 inboxes).

Code: Select all

  int checksum(string s) {
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
  }

  //...
  string out="1234567890test";  
  int check;   

  check=checksum(out);
  do {
    SendResponseString(OUTBOX_1, out);
    GetResponseNumber(ack,INBOX); // <<<<<<<<<<<< ?
    while(ack!=check);
  }
  Wait(10);
or how else can I check if the master received all the slave's message correctly?
Last edited by HaWe on 04 Mar 2012, 16:16, edited 2 times in total.
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: NXC: BT send from slave to master

Post by mcsummation »

You need to receive the Ack back into the slave with code like this:

Code: Select all

        
until (ReceiveRemoteNumber(AckMailbox, false, AckValue) == NO_ERR)  Yield();
ReceiveRemoteNumber(AckMailbox, true, AckValue);
The Master would send it with code like this:

Code: Select all

            
until (RemoteConnectionIdle(SlaveConnectionNumber)) Yield();
SendRemoteNumber(SlaveConnectionNumber, AckMailbox, AckValue);
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC: BT send from slave to master

Post by HaWe »

thank you,
but well, I don't know quite sure if we understood each other correctly...

The procedure is the following:

the slave sends an out string to the master
the slave calculates a checksum for later BT control (check)

the master receives a string s by his inbox
the master calculates a checksum of the string s what he received (ack)
he sends his personal checksum (ack) back to the slave

the slave checks if the returned master's checksum (ack) is the same as the one which the slave calculated by himself (check).
if yes: clear all message boxes
if not: send out string again

is that what you understood?
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: NXC: BT send from slave to master

Post by afanofosc »

If you are using the standard mailbox system then there is no such thing as a bluetooth send from slave to master. Slaves only use MessageWrite (not BluetoothWrite) to put a message into a response mailbox. There is no initiation of a request/response from slave to master if you are using the standard mailbox system. All communication is initiated by and completely controlled by the master. The slaves only ever respond to requests by the master. They can certainly write to a mailbox without a request from the master but if they do that they will just fill up the mailbox queue and lose messages. There are 10 incoming mailboxes (MAILBOX1 through MAILBOX10). They all are for messages from a master to a slave. There are 10 response (outbound) mailboxes (MAILBOX1 through MailBOX10) which are all for messages from the slave to the master.

When you call SendResponseString you are calling MessageWrite with 10 added to the mailbox number so that the value is written to a response mailbox.

When the master calls ReceiveRemoteString for a particular mailbox number then since the mailbox will be empty (having removed the last and only message that was in it in a previous call to ReceiveRemoteString) it will send a MessageRead direct command to the next active bt connection, starting first with connection 1, and ask for the device to send back whatever happens to be in the response mailbox corresponding to the mailbox number that the master was trying to read from. The master will get back a STAT_COMM_PENDING response. The next call to ReceiveRemoteString will either find a message in the mailbox since there was something in the 1st connection's corresponding response mailbox or (more likely, if you have multiple slaves) it will find the mailbox is still empty and it will send a MessageRead direct command to the next active bt connection, number 2 if it last tried number 1. The function will return STAT_COMM_PENDING. The next call to ReceiveRemoteString will either find a message in the mailbox since there was something in the 2nd connection's corresponding response mailbox or (same as before) it will find the mailbox is still empty and it will repeat the process on connection 3.

When the slave calls ReceiveRemoteString for a particular mailbox number it will either return NO_ERR if there is a message in the mailbox or it will return STAT_MSG_EMPTY_MAILBOX.

If you are using the mailbox system then your slave code should only ever call one of the SendResponse* functions and one of the ReceiveRemote* functions. It can call any of the SendResponse* functions as often as it wants to but, as mentioned, it will probably lead to a lot of dropped messages. It will also lead to the master always getting stale data since every time it polls the slave for data it will get a 5 message old response.

If you are using the mailbox system then the master can write to a slave using one of the SendRemote* functions. This directly writes to a slave's inbound mailbox using a Bluetooth MessageWrite direct command that does not request a direct command status response. The master should read the slave's response to its message using one of the ReceiveRemote* functions which will, as described above, poll in sequential order the active bluetooth connections (one connection for each call to the ReceiveRemote* function).

One option you can use to avoid the firmware's round-robin approach to polling the active connections (which only applies if you have more than 1 slave) would be to use RemoteMessageRead before calling one of the ReceiveRemote* functions. Using RemoteMessageRead you can specify which connection you want to send the MessageRead direct command to. This can help you avoid having the firmware ask the wrong slave for a message which will happen more often than not if you just call one of the ReceiveRemote* functions.

If you have the slaves all use the same mailbox for the response but include their ID or some sort of unique value in the response then the master will be able to tell which slave responded to the last call to one of the ReceiveRemote* functions.

I would urge you to consider using a structure rather than an array since you are dealing with multiple data types of varying lengths. I think it would be a huge benefit to you but you are free to choose to stick with your current approach.

The bottom line is if you are using the mailbox system then you should never ever have a slave call a function that initiates an actual Bluetooth send operation. Never call SendRemote* or any of the Remote* API functions on a slave if you are using the mailbox system. And you would get fresh data on the master if you only write to a response mailbox using one of the SendResponse* functions after receiving a command from the master that indicates that it expects to get back a response.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: NXC: BT send from slave to master

Post by afanofosc »

P.S., there should be no need whatsoever for a complicated checksum scheme like you describe if you use Bluetooth and the mailbox system correctly. The master should initiate and control all actual communication between devices. If you do that you will not get any data corruption or dropped messages.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC: BT send from slave to master

Post by HaWe »

well, fact is, that often messages are dropped (or get corrupted).

e.g., the master tells the slave to start a motor and during this action the master *should* wait until a touch sensor on the slave is pressed by a motorized arm (e.g., claw completely down).
if the touch sensor on the slave is pressed, the slave *should* send this "button pressed message" back to the master.
the master *should* get this message and *should* proceed with the following program comands
(e.g., tell the slave to close the claw&grab piece, then move claw up (until other sensor pressed), then move arms to a certain square (until certain encoders are reached), then lower the claw (until sensor pressed), then open the claw&release piece, then claw up (until other sensor pressed) and wait for next move cmd... ).

it sounds easy, and (spoken for the chess progam), 3 or 4 or 5 plys are executed correctly, sometimes more, sometimes less.
But suddenly e.g. the claw moves down and grabs the piece, but then the slave doesn't react any more, it doesn't move up or anything, although the sensor states of the slave can be monitored correctly on the master's display. But the master seems to wait for any slaves's reaction, and as he don't get it (completely), he freezes, too (except the "DisplayValues task").

The only explanation I have is, some special BT command was not transmitted correctly or hasn't been read correctly.
So I intended to check by sort of "in-process-control" and a "feed-back" what was sent and what has been received.

Anything is definetly going wrong in this BT thing.
In case the master sends a cmd to the slave the error check is working well.
So the mistake must happen to the BT cmds sent from the slave to the master:

Now what should I do?

Code: Select all

#define BT_CONN   0
#define INBOX     1 // requests (motor ctrl, variables) 
#define OUTBOX_1  2 // sensors (out string sending continuously)
#define OUTBOX_2  3 // return ack

  int checksum(string s) {
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
  }

  //...
  string out="1234567890test"; 
  int check;   

  check=checksum(out);
  do {
    SendResponseString(OUTBOX_1, out);
    // <<<<<<<<<<<< ?
    // <<<<<<<<<<<< ?
    // how to check if the out string 
    // was transmitted correctly to the master,
    // has been received completely by the master,
    // and has been read correctly by the master ?
    // (feed-back ?)
    // <<<<<<<<<<<< ?
    // <<<<<<<<<<<< ?
  }
  Wait(10);
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: NXC: BT send from slave to master

Post by afanofosc »

Doc, if you send me your complete code I will try to sort it all out for you.

Slaves never, ever send messages to the master when you are using the mailbox system. They just plop it down in response mailbox on their own device. It goes nowhere and does nothing unless and until the master polls for the response.

You should not need any sort of system for validating that messages do not get corrupted. If you read Sivan Toledo's article you saw that he did not mention anything about message corruption. His concern was with dropped messages. And dropped messages only occur because of the 5 message limit in the mailbox queues. You can put messages in a response mailbox so fast that the master who is polling for the messages will miss some of them. That's why a slave should not ever write to the mailbox unless he is asked to do so by the master. If the slave only wrote to the response mailbox in response to a message received from the master then it would not overflow its outbound mailbox and not only would no messages get corrupted but no messages would get dropped either.

It isn't like your chess playing robot has to handle the communication between NXTs in the fastest possible way.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC: BT send from slave to master

Post by HaWe »

I'll gladly load up the code.
But reading through your last 2 posts I observed something that might have been critical so far:
for calculating a checksum (msg check when sending from master to slave) I used so far

Code: Select all

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline int checksum(string s) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
}
I now changed it into

Code: Select all

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
safecall int checksum(string s) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
}
function call:

Code: Select all

  //string cmd= ....
  ID = 1;
  INBOX = 3;
  OUTBOX = 1;
  int ack=0;
  while (ack!=checksum(cmd))  {
    SendRemoteString(ID, OUTBOX, cmd);
    Wait(10);
    ReceiveRemoteNumber(INBOX, true, ack);
    Wait(10);
  }
The checksum is important because several different tasks may try to send different BT strings at almost the same time, each single one waiting for an acknowledgement, and so I have to get a specfic acknowledgement as a feed-back for each single, specific BT cmd for each single BT sending task.

I'm not sure and I have no idea why but I suspect it now works better. I'm already running 8 plys without hang-up.
Maybe indeed this sending direction master->slave was faulty although I didn't expect it.
I keep on testing.

edit:
it now had worked automatically for more than 20 plys, just in one case it hung but that was because of a different bug.
That sounds promising for the moment, but I do not want to celebrate too early.
Attachments
chess 431RoBot.zip
intermediate test version
(22.16 KiB) Downloaded 222 times
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: NXC: BT send from slave to master

Post by afanofosc »

I would recommend that you never have multiple tasks using the Bluetooth subsystem. There's no reason at all to do that. Have one task responsible for all messaging. Other tasks simply make information available to that one central task and use any information that the central communication task provides back.

If you can do what needs to be done in a single task then use a single task. Only use multiple tasks when it is simply impossible to do what needs to be done with just one task - and this is rare, usually involves turning multiple motors simultaneously, though that can often be done in a single task too. Reading multiple sensors never requires multiple tasks.

Keep it super simple (KISS).

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: NXC: BT send from slave to master

Post by HaWe »

I would recommend that you never have multiple tasks using the Bluetooth subsystem. There's no reason at all to do that... If you can do what needs to be done in a single task then use a single task.
Honestly: I would have bet that you'll say this, but Lord, forgive me, I will do it nevertheless multithreaded as I did, it's just the way my program is designed. ;)
I could try to explain it to you why I'm doing it this way, but most probably I won't find the correct idioms and explanations in English, and Google translate would probably muddle up all and anything.

I'll surly will have a look over my code and maybe try to redesign one thing or the other, but please don't be angry if I will keep on doing it my way :)

ps:
I meanwhile have got it playing without any error (except maybe once missing a target piece with my claw once or twice) for more than 50 plys of my robot automatically playing against himself. It still sounds promising...
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests