As part of my porting of my devices to the latest version of the Arduino IDE, I decided to move the devices to using the XBee library. Back in part 1 I described why I suddenly took an interest to it, and since I was going into the code, I might as well start using it for real at the same time. The changes to make my XBees receive packets using the library went without a hitch. It just worked fine and reduced the code I had to write by a lot. However, when I looked at transmitting data, I was appalled. All the examples show something like:
XBee Tx Example
void loop() {
// break down 10-bit reading into two bytes and place in payload
pin5 = analogRead(5);
payload[0] = pin5 >> 8 & 0xff;
payload[1] = pin5 & 0xff;
xbee.send(zbTx);
// flash TX indicator
flashLed(statusLed, 1, 100);
// break down 10-bit reading into two bytes and place in payload
pin5 = analogRead(5);
payload[0] = pin5 >> 8 & 0xff;
payload[1] = pin5 & 0xff;
xbee.send(zbTx);
// flash TX indicator
flashLed(statusLed, 1, 100);
I mean REALLY?? Setting the bytes into an array one at a time? Well, I went searching the web to see what else could be done and found dozens of examples of this kind of thing. Here's one from the New SoftSerial example:
Another Example
void loop() {
payload[0] = 'H';
payload[1] = 0x7E;
payload[2] = 0x11;
payload[3] = 0x13;
payload[4] = 0x7D;
xbee.send(zbTx);
My Tx Example
/*
XBee TX test for a Arduino Mega2560 using Serial3 as the XBee serial
input for a Series 2 XBee. This is NOT based on the examples that come with
the Arduino XBee library.
See, the examples there and most other places on the web SUCK. Andrew's
library is much easier to use than the illustrations would lead you to believe.
This is a HEAVILY commented example of how send a text packet using series 2
XBees. Series 1 XBees are left as an exercise for the student.
*/
#include <XBee.h>
XBee xbee = XBee();
// This is the XBee broadcast address. You can use the address
// of any device you have also.
XBeeAddress64 Broadcast = XBeeAddress64(0x00000000, 0x0000ffff);
char Hello[] = "Hello World\r";
char Buffer[128]; // this needs to be longer than your longest packet.
void setup() {
// start serial
Serial.begin(9600);
// and the software serial port
Serial3.begin(9600);
// now that they are started, hook the XBee into
// Software Serial
xbee.setSerial(Serial3);
Serial.println("Initialization all done!");
}
void loop() {
ZBTxRequest zbtx = ZBTxRequest(Broadcast, (uint8_t *)Hello, strlen(Hello));
xbee.send(zbtx);
delay(30000);
strcpy(Buffer,"I saw what you did last night.\r");
zbtx = ZBTxRequest(Broadcast, (uint8_t *)Buffer, strlen(Buffer));
xbee.send(zbtx);
delay(30000);
}
XBee TX test for a Arduino Mega2560 using Serial3 as the XBee serial
input for a Series 2 XBee. This is NOT based on the examples that come with
the Arduino XBee library.
See, the examples there and most other places on the web SUCK. Andrew's
library is much easier to use than the illustrations would lead you to believe.
This is a HEAVILY commented example of how send a text packet using series 2
XBees. Series 1 XBees are left as an exercise for the student.
*/
#include <XBee.h>
XBee xbee = XBee();
// This is the XBee broadcast address. You can use the address
// of any device you have also.
XBeeAddress64 Broadcast = XBeeAddress64(0x00000000, 0x0000ffff);
char Hello[] = "Hello World\r";
char Buffer[128]; // this needs to be longer than your longest packet.
void setup() {
// start serial
Serial.begin(9600);
// and the software serial port
Serial3.begin(9600);
// now that they are started, hook the XBee into
// Software Serial
xbee.setSerial(Serial3);
Serial.println("Initialization all done!");
}
void loop() {
ZBTxRequest zbtx = ZBTxRequest(Broadcast, (uint8_t *)Hello, strlen(Hello));
xbee.send(zbtx);
delay(30000);
strcpy(Buffer,"I saw what you did last night.\r");
zbtx = ZBTxRequest(Broadcast, (uint8_t *)Buffer, strlen(Buffer));
xbee.send(zbtx);
delay(30000);
}
Yes, that's all there is to it; this example will compile and run using IDE 1.0.3 on a Mega2560. Andrew made the library quite capable, but most people don't seem to want to look deeply enough into it to use it to advantage. Notice that you fill in the Tx request with an address and then send the string pointer and its length to the XBee. It's just that simple. You can use a buffer and format it to be exactly what you want, then hand it off to the xbee.send() for transmission. Really, really nice.
Remember though this example is for a mega2560 with four serial ports. To do exactly the same thing on a UNO, just use SoftwareSerial as I described in part 1. It will work equally well and you still have the Serial to output status and debugging information so you can see what is going on.
Suppose you want to send the packet to a specific XBee on your network, avoiding the problems that can happen with broadcast <link> it's actually really easy. Just create another address like the one for Broadcast in the example above and use it instead.
Using this technique, I reduced a fifty or so line transmit routine down to:
How Simple It Can Be
XBeeAddress64 Broadcast = XBeeAddress64(0x00000000, 0x0000ffff);
void sendXbee(const char* command){
ZBTxRequest zbtx = ZBTxRequest(Broadcast, (uint8_t *)command, strlen(command));
xbee.send(zbtx);
}
void sendXbee(const char* command){
ZBTxRequest zbtx = ZBTxRequest(Broadcast, (uint8_t *)command, strlen(command));
xbee.send(zbtx);
}
Yes, I can compose the commands for my various devices and then just call sendXbee() with the string. Simple, easy to read, and it works.
I like my little XBees more and more each day.
Hi, great posts about using the Xbee library!
ReplyDeleteI am using your codes for Tx/Rx, but it seems that my router xbee is sending the message with a frame type = 0x92 instead of 0x90. I've tried restoring its settings, but it is still sending the message as 0x92. Why would you think it is? Since is not the correct frame type, it is giving me errors 3 and 1.
Frame type 92 is an I/O sample frame. It looks like the transmitting XBee (not the receiver) is sending an i/o sample. So, take a look at the configuration of the I/O pins, you probably have one of them set up to measure some kind of I/O either digital or analog by accident.
ReplyDeleteOr, if that's what you're actually trying to do. Suppose you have a temperature sensor hooked to one of the pins, then you'll have to decode the type 92 frame. I have a code example for that as well on this blog at http://www.desert-home.com/2012/11/using-xbee-library-part-2.html.
You can get to all my XBee stuff by going to the tab up top labeled "World of XBee" and then looking around.
Thanks for the reply. Yeah, I was using I/O at first, and the settings on the router probably got stuck or something. I'll take a look around your blog! Thanks again.
DeleteOne more question.... Is it necessary to set xbee to Serial3 (software serial)? I noticed that you start Serial and Serial3... would it work by setting xbee to Serial instead of Serial3?
ReplyDeleteI use Serial3 because I want Serial free for debugging. You can use Serial, and just hook the XBEE to the first serial port.
DeleteDave- I just want to say you rock!! I have learned so much from your examples, I've been trying to do what you have done for months!! Still can't wrap my head around some things though... I want to use API mode so I can talk to individual addresses when I want to talk to them, not having them constantly sending. Is this even doable? i.e. Coordinator sends request to address #1(on an Arduino) - #1 ACKs then Coordinator sends a command (ascii string) to make it do something. I've done this in AT mode- works but waaaay too slow. Got your Mega example to receive from Xbee sending I/O ADC, but when I send the "hello world" gets "****** error code:3"
ReplyDeleteI assume because I'm not reading the frame correctly? If you could tell me what examples would work together, or that I'm on the right track? Thanks, Great site!!
Yes, it's absolutely doable. You can use the first example as something that receives a text string and just use the transmit code from example three modified for the ports that you're going to use. I do something sorta like that for my garage door. I send a text string saying open the door and it responds back that the door is open. You don't really need the ack, unless you want to be sure the remote XBee is alive before you send. You can just send the command and see if it gets there by looking for the response.
DeleteThe trick to remember is not to hang up waiting for a response that might never come back. Send something, then go back to the loop() code and circle around checking for available from the XBee receive code. This is where you can set a timer to remind you that you might not have gotten a response. If speed is critical like flying a helicopter or a race car, there are different techniques that have to be used.
Hi Dave,
DeleteI really appreciate all the posts you have made on Xbee's, they have been very helpful. I am trying to get your example 3 to work. I have a router Xbee with an arduino uno using Software serial. This router/arduino is running the example 3 code. Then I have a coordinator in API mode 2 which has a Mega attached and I am running your example 1 code on this. It seems to be that I am doing something wrong though. Do you notice any errors in my set up? Or have any recommendations for what I need to check?
Thanks
You didn't give me much to work with. What's not working? But, I've helped a couple of people recently that had the transmit and receive wires backwards.
DeleteThanks! I apologize for the slow reply. I must have missed seeing this when I checked the last few days.
DeleteFunny enough. It was an issue with my Tx/Rx lines. I was using a Arduino shield on my Arduino Uno. The Problem with this is that I couldnt use the software serial because it automatically plugs into the tx and rx line when attaching it to my Arduino Uno. Thus I attached the shield to my Mega and bent the tx/rx lines coming from the shield so I could attach wires to them and put them into the Serial3 tx/rx pins. Now I have my switch enabled to micro on my shield and still have my usb tx/rx pins available on my Arduino Mega. All in all it was a simple fix and the code you gave does work! Thank you once again for your help.
Best,
Hey, your BLOG is really helpful for my project.
ReplyDeleteCan I ask you a question? I used your broadcast method, and I made it. However, when I tried to use a specific address(0x0013a200, 0x408b45ad in my case), I cannot send the message to the end device. Could you please tell me why?
Thanks a lot.
Gee, I'm not sure; it worked first time for me. Make sure you have the XBees in API mode 2; if you have them in API mode 1, this kind of thing can happen and drive you nuts.
ReplyDeleteOH! That is the reason, and I change the coordinator to Mode 2 and it works now! Thank you very much! You are so kind.
DeleteUsing Andrew's XBee library the RemoteAtCommand example shows on line 54, how to creat the remoteAtRequest object complete with address command and command parameter. Starting on line 83 he shows you how to set different commands to the remoteAtRequest object. What I haven't been able to find or figure out is how to change the address for the object. Say I want to send a command to a specific XBee to set pin 3 high and then later change the address and send the same command to another XBee. I know how to send a bunch of anything to one XBee or broadcast to every XBee. There seems to be a lot of information on how to make a one way many-to-one network but little information on how to construct a one-to-many or even two way network. A good application example would be stand alone XBees that feed sensor data into a central node that then sends info either back to the same node or other nodes to wirelessly actuate something. Thanks for the insight.
ReplyDeleteavid reader
Dave
I spoke too soon!.. I think...
ReplyDeletefirst build 64 bit address object (I do this globally)
XBeeAddress64 Router1 = XBeeAddress64(0x0013A200, 0x40A09AAC);
second build remote at command request object (I also do this globally)
RemoteAtCommandRequest remoteAtRequest = RemoteAtCommandRequest(Router1, Cmd, Value, sizeof(Value));
then send the command out. (could handle the response in a function)
xbee.send(remoteAtRequest);
change the objects address
remoteAtRequest.setRemoteAddress64(Router2);
if needed change the command and it's value
remoteAtRequest.setCommand(Cmd2);
remoteAtRequest.setCommandValue(Value2);
remoteAtRequest.setCommandValueLength(sizeof(Value2));
repeat as necessary.
It may also be worth noting that setRemoteAddress16(16BitAddr) can be used to lower network overhead and speed things up once the 16 bit addresses are found.
Should I be posting this kind of stuff on the Arduino forum? I feel like a lot of people that are not well versed in formal languages find the XBee library to be daunting and confusing (I know I do). Judging from this blog I think it's safe to say you have seen and/or helped people that feel lost using it. I find it extremely powerful but at times difficult because there is a lot of variation in how things can be written so sometimes I'm not sure if I'm doing things properly i.e. like this example, making things more complicated because I don't fully understand the library
It would be kind to some people to post your experiences with this kind of thing out there where it's easy to find. The Arduino forum is a good place for this kind of thing. The problem is that there are people that will drive you nuts picking apart ever little thing.
DeleteSo, be sure to surround it with words that indicate that this is only one way to do it, it's an example for folks to use to get some idea how to proceed, etc. The incessant criticism is one of the things that annoys me about a number of forums out there.
If you have a thick skin, I'm sure your discovery would help a number of folk that have been driven nuts trying to get these devices to work.
And yes, your idea would work great. I only have a couple (actually 4) devices that are sensors, and none (yet) that control anything. When I use an XBee for control, I include a processor of some kind to handle default and unusual cases directly.
This works great for sending strings of characters. I can't figure out how to send integer data from several sensors hooked up to one arduino, to another, however. Any hints?
ReplyDeleteI don't even try to send integers or floats between arduinos using an XBee or wires or anything. I convert everything to a string and send it in the string. You can use positional strings where the first item is an integer and the second is a float or something like that.
DeleteI do this for several reasons, first and most important is that the darn thing is readable. I can look at the conversation between XBees and actually see what is going on. I've used several techniques, a comma separated string so it would be something like:'
temp=78.6,pressure=75
This can be parsed looking for temp or pressure, or just use the comma as a separator. More recently, I've gone to json for things like this because the larger computers can take it apart very easily.
When you try to use integers or floats, you run into problems with machine dependent thing like big Endian, little Endian, the way the floats are represented between languages, etc.
I just avoid all that by making everything into a string and sending that. I did a blog post on this kind of thing here http://www.desert-home.com/2013/10/floats-and-strings-over-serial-link.html I guess I should put a link to that on the XBee page (see tabs above)
Thanks!
DeleteThats very helpful. I can now transmit sensor data as a CSV string and it works great. I used the arduino sketch in xbee part 1, and I can see that it the data is received. I can't figure out in the sketch how to reverse the process to get the string from the payload (presumeably the data[i] array under handleXbeeMessage, and convert back to integers. Sorry for the questions, I am really a noob at this.
I understand what you're going through. The data that you want can be reached by something like xbee.getResponse().getFrameData() That will give you back a pointer to the data that you can index like this xbee.getResponse().getFrameData()[0] and then [1], etc.
DeleteTo make it easier to type and read later, do something like this:
data = xbee.getResponse().getFrameData()
Now you can just mess with the variable data because it will point to the same thing. This is where you need to understand how the string is constructed to do the rest of it. Why don't you put a copy of it here in a comment and we'll take a look at it. Or, you can look at the web page I listed above and step through it.
Thanks for you help, Dave.
DeleteI will try to get my head around this. I am just sending four values (two are temps) via one arduino as CSV string. I was trying to usehandleXbeeRxMessage(rx.getData(), rx.getDataLength()); because I thought the getData made an array of received characters. I obviously was wrong. If I use getFrameData, I suspect I need to know the where in the frame the data payload starts before I can extract the data?
Ok, made some progress.
DeleteI'm using the arduino sketch in xbee part 1
basically, all I am sending now is the string ":-30,\n"
I uncommented the code following "I commented out the the printing.....
made a data array, and added the code from the float,integer, etc sketch:
// I commented out the printing of the entire frame, but
// left the code in place in case you want to see it for
// debugging or something
Serial.println("frame data:");
for (int i = 0; i < xbee.getResponse().getFrameDataLength(); i++) {
print8Bits(xbee.getResponse().getFrameData()[i]);
Serial.print(' ');
}
Serial.println();
for (int i= 11; i < xbee.getResponse().getFrameDataLength(); i++){
Serial.write(' ');
if (iscntrl(xbee.getResponse().getFrameData()[i]))
Serial.write(' ');
else
Serial.write(xbee.getResponse().getFrameData()[i]);
Serial.write(' '); }
char datastream[100];
// (the : is the 11th bit in the frame)
datastream[0]=xbee.getResponse().getFrameData()[11];
datastream[1]=xbee.getResponse().getFrameData()[12];
datastream[2]=xbee.getResponse().getFrameData()[13];
datastream[3]=xbee.getResponse().getFrameData()[14];
datastream[4]=xbee.getResponse().getFrameData()[15];
Serial.println("the string is");
printbuffer(datastream);
Serial.println("");
char *tmp = strchr(buff, ':');
printbuffer(tmp);
tmp += 2;
printbuffer(tmp);
tmp = strchr(tmp, ',');
int recoveredInt = atoi(tmp);
Serial.println("");
Serial.print("Int recovered was: ");
Serial.println(recoveredInt);
Serial.println();
with printbuffer(data stream) I get :-30, which is good, progress for me as I couldn't do this before.
when I try to extract the integer (-30), I get gibberish though: ÿØ æ
Int recovered was: 0
Ok, let's start with the ascii characters you have :-30, If you KNOW that the colon is always going to be first, then the dash is at datastream[1], that is the beginning of the integer -30 that you want to extract. The kicker is that you have to call it with a pointer, so you can't use datastream[1], you have to use datastream+1 because atoi() takes a pointer as the input
DeleteNext, you don't have to get the data out one byte at a time, you can just set another pointer to it and use that, so
char * someptr = &xbee.getResponse().getFrameData()[11]
Which will set the pointer someptr to hold the address of the 11th byte in the frame data, but since you want the integer -30, why not point it to the 12th character and just skip the other stuff? Also, since you have a comma right after the -30 and atoi() stops at the first none decimal ascii character, you can really cheat and do something like this:
int someint = atoi(&xbee.getResponse().getFrameData()[12]);
and just grab it directly out of the data. The reason I use the parsing routine strchr() is to skip certain things in the incoming string. If you have something like this:
66,12,14,-31
Then you will want to suck them out one at a time by grabbing the number, skipping to the next one, grab the number, etc. So:
char * data = "66,12,14,-31";
char * P = data; // Get a pointer to data to play with
Serial.println(atoi(P)); // This will print 66
P = strchr(P, ','); // will skip the 66 and leave the P pointer pointing to the comma
P++; //move the pointer just past the comma
Serial.println(atoi(P)); // this will print 12
P = strchr(P, ','); // will skip to the next comma
P++; //point just after the comma
P = strchr(P, ','); // Skip the 14 and find the next comma
P++; // will bump it one to point to the dash
Serial.println(atoi(P)); // and finally, this will print the -31
You've gotten yourself confused on pointers vs arrays vs strings. Just take it a little bit at a time and you'll get it.
Thanks for your patience. Still working on this. If I tryint someint = atoi(&xbee.getResponse().getFrameData()[12]);
Deletei get the error invalid conversion from 'uint8_t*' to 'const char*' andinitializing argument 1 of 'int atoi(const char*)'
First, let's deal with the compile error. Just so you understand a little more the routine atoi() takes a pointer to a character string as its input. I messed up and left something out that would have taken care of this error. It should read:
Deleteatoi( (char *)&xbee.getResponse().getFrameData()[12]);
The (char *) is a typecast which tells the compiler to treat the next thing differently. This is complicated and I should have spoken more about it.
However, I have have led you astray. Let's take another tactic, go to the page
http://www.desert-home.com/2012/10/using-xbee-library.html
and take a look at the routine handleXbeeRxMessage, it's down the page a bit so you'll have to look for it. This routine prints out the data payload that you put into the XBee message when you sent it. It gets the data by doing a
handleXbeeRxMessage(rx.getData(), rx.getDataLength());
Notice how the XBee library has a getData() call to give back the adddress of the data payload? That's the piece that you want to work with. the getDataLength() call will tell you how long it is. This is the part of the XBee packet that you want to deal with.
If you deal with frameData, you have to worry about a number of things that you aren't really interested in ... yet. In the handleXbeeRxMessage() routine on the page, you already have a pointer to the data all set up and you can take it from there to get what you need.
Using getFrameData() will give you the entire frame, and that's not what you want to try and take apart, It can be used, but it makes it much more complicated that it should be.
Thanks, Dave, that makes some sense. Yep, worrying about the frame data has too much for me now. Still trying to understand the pointer stuff. So basically focus on handleXbeeRxMessage(rx.getData(), rx.getDataLength());
DeleteSo is where I can extract the data?: void handleXbeeRxMessage(uint8_t *data, uint8_t length){
// this is just a stub to show how to get the data,
// and is where you put your code to do something with
for (int i = 0; i < length; i++){
Serial.print(data[i]);
If I use
void printbuffer(uint8_t*buffer){
while(*buffer){
Serial.write(*buffer++);
}
I can get the data string with printbuffer(data); and pick up in the sketch about integers, floats, etc. However, its seems that uint8_t* and char* are two different pointers, so I can't use at or strchr. Sorry, I really am noob at this!
Ok, I can convert the first data point in a series to an integer, but I used
Deleteint firstVar =atoi( (char *)&xbee.getResponse().getFrameData()[12]); and got it from the data frame.
still trying to get it to work with handleXbeeRxMessage(rx.getData(), rx.getDataLength());
but again, not pointing to char*
OK, int y = atoi( (char *) &rx.getData()[1]); will print the first variable of a CSV series.
ReplyDeleteNow gotta figure out how to print the rest.
Now you're starting to get it. If I tried to explain data types here, it would go into pages and pages, so I suggest you look around the web for things like "pointers in c" "c datatypes", and those will give you hints on other things. There's thousands of examples and explanations that can help you over the hump.
DeleteNow, look back up a couple of posts to where I showed how to step through the data using strchr(). get a pointer to the beginning of the data and just start stepping through. That was way up there where I was using the variable P to step through. That will show you one way of many to work your way through the data.
The idea is that you create the variable P as a 'char *' which is a character pointer, then set p to the address of the data by simply: char * P = data; or maybe char * P = (char *)data; depending on how much this compiler complains. Then, just start through the data one comma separated field at a time.
Be sure to look at the documentation on strchr() so you have an idea how it works, don't just take my example without understanding what I did. That way when it breaks, you can fix it.
Here's a link to a GREAT book on the 'c' language. It's not c++, which is what your're using, but it deals in depth with the concepts you're working with right now. Sometimes we get into trouble because the various tutorials and explanations go wildly astray of what we actually want to do, and until you get experience with the nuances, you'll need something to fall back on. This will help a lot. It doesn't explain things like objects, methods, and the other items that are a little more advanced, but it will certainly help with pointers and data types.
Deletehttp://books.cat-v.org/computer-science/c-programming-language/The.C.Programming.Language.2nd.Edition.pdf
This comment has been removed by the author.
ReplyDeletei have two arduino mega 2560 with xbee S-2 with xbee shields.i used your codes to establish communications them in api mode(AP=2) but unable to do so.with your tx and rx codes.it would be a great help for me if you help me out in this.and send me the proper schematic description along with serial connections of this set up.
ReplyDeleteNote:X-CTU configuration of these two xbees in API(AP=2) mode has been made.
There's really not much to it. Connect the two serial pins on the arduino to the two serial pins on the XBee, Power and ground. There's only four wires to hook up. With a mega2560, use any one of the serial ports except serial 0, leave it for debugging output. The XBee only has one serial port, so that is easy.The XBee is shipped at 9600 baud, so use 9600 baud on the arduino to start with. And, that's basically it.
DeleteI have a fritzing diagram and schematic on my post about a temperature sensor I'm working with at http://www.desert-home.com/2015/02/battery-operated-temperature-sensor.html
The sensor stuff is more complex than you need because I also put the XBee to sleep, so I need a couple more wires to work with, but you can see the serial hookup there.
for transmitter i am using the 3 code of tx of your's.
ReplyDeletemy output at the serial monitor is:Initialization all done!
i used four pins of xbee that are VCC,DIN,DOUT,GND.i connected VCC to 3.3v,GND to GND,DOUT to rx3(15),DIN to tx(14) of arduino(Mega2560) respectively and xbee jumpers are on usb in both cases.
For RECEIVER:
i used the rx code which came up with this output :starting up yo!
i connected VCC to 3.3v,GND to GND,DOUT to serial pin 2 and DIN to serial pin 3 of ardunio respectively.
i am not be able to establish communication between them so please help me with this setup.
Thanks in advance.
Take a look at the about me link on the right and drop me an email so I can send to you directly. This will get too long for doing in a reply.
Deletethe project I would use fire mode. then take pieces of data that has sent the address of the sender. What command should I use.
ReplyDeletewhat is the difference between a command and rxresponse txrequest ??
To get the best explanation of this take a look at the XBee Users Guide. It's on the Digi web site. There's also a number of copies out there on various vendor sites. The section on API mode covers this in detail.
DeleteHey,
ReplyDeleteHow do You send an analog reading? The digital part works great. How to pass analog reading to"command" in Your example.
In my network I convert EVERYYHING to text. I got tired of trying to figure out which processor used big-endian, little-endian, significant digits. size of integers or floats, etc. So I convert a reading to text first, then send it as text. At the receiving end, I convert it back to whatever I need.
DeleteSomewhere on this blog I have examples of converting analog reading to text and back, In the very latest posts (at this time) about the battery operated temperature sensor, I have several examples.
Dave, just a quick thank you for being such a prolific provider of useful information. I've been pulling my hair out for 3 days trying to work out an easier way of sending data using the API mode. You've done a sterling job of making it understandable and usable. Many many thanks.
ReplyDeleteThankyou for the very helpful content here, but I have run into difficulties and wonder if you can offer any suggestions.
ReplyDeleteI am trying to set up a control system using 3 (eventually 5) Arduino Megas with XBee series 2 modules running in API mode. I have the coordinator set up with DL FFFF and the routers with DL 0000, and all on the same PANID.
I start by switching on the coordinator Arduino and then the router Aduinos. Each router Arduino is programmed to send an opening message of 13 bytes to the coordinator which replies with a 5 byte message to the addresses derived from the incoming messages telling the routers await further instructions. This works as expected. I can send a status change message (5 bytes) to either of the routers and then the chosen router will respond to keypad commands from the coordinator and report back with a 9 byte message the results of the keypad commands and the network is quiet between keypad commands.
My problems start when I try to get one router to accept commands and the second router to respond to the effect of those commands. As in the solo situation, I send keypad commands to the "lead" router and it replies to the coordinator with the same 9 byte message to report the results of that command. On receipt of that message the coordinator Arduino constructs a message of the same 9 bytes and sends it to the "follower" router. At that point the XBee on the "lead" router starts to send out a continuous stream of 9 byte messages which floods the network with traffic. I have checked the sketch on the "lead" router Arduino and it is only sending out instructions to send one 9 byte message and so I can only assume that the stream of messages is being generated by the XBee module. If I disable the command line in the coordinator Arduino that sends on the packet to the "follower" Arduino leaving all other setting the same the problem does not arise. If I change the content of the 9 byte message to the follower or change the message length, I get the same problem of streaming packets.
As I can initially send 5 byte status change messages to either router with no problems, the addressing (following your examples) works fine, but I am at a loss to work out what can be causing the "lead" XBee to start sending out continuous messages. I have tried switching the roles of the Arduinos to see if it is a hardware issue, but I get the same problem. As soon as I send on a message to the "follower" Arduino I get a stream on data packets.
Have you any thoughts on what might be setting off this stream of packets on the XBee.
I previously tried using broadcast from the "lead" Arduino, but this seemed to cause too much traffic - this is why I switched to using the coordinator to relay the message because it stores the addresses of the routers from the initial messages.
David F
I don't see a problem with the description you gave, but it does sound like something is going wrong in the code on the lead arduino that you haven't noticed. You're sending to the second arduino, but the lead arduino is apparently going nuts and sending at that point. That sounds like the addressing on the message to the second arduino is messed up and going to the lead instead, which responds, and you have a comm loop between the lead and the coordinator.
DeleteWhile it's true that the XBee will retry messages, there's a limit to that and it will settle after a short while. So, if you are accidentally sending to the lead instead of the secondary, you've just gotten yourself into this kind of situation.
Broadcast on an XBee network can cause problems when you get too many devices pumping out messages and they start interfering with each other. Three devices don't usually have this kind of problem unless you're sending really quickly. That's why I don't recommend using broadcast except in the debugging stages when you need to see what's going on.
The way I debug this kind of thing is to add code to the XBee library to print the contents of every message I'm sending and then watch the output to see if I messed up the addressing or something. I have to do it this way because there is no mode on the XBee that will just monitor the network so I can see every message flying around.
Thankyou for your comments. I will have a further dig at the addressing side of things to see if I have messed up in that area. I will certainly try to get an on-screen print of the address. I am already monitoring package size and some of the data content, and should be able to add the address.
DeleteRegards
David F
Dave
ReplyDeleteI am following your approach to do below:
RPI+XBee (coordinator) Sends commands to Arduino, receives data from arduino
Arduino (Router): receives and sends data to coordinator.
It works fine 1st time. But If I close the coordinator/or router and next time if I start running again, the data transmission stops. I need to press XBee reset for certain time to make it work again. My guess is because everything is inside the Arduino loop, it keeps sending even if there is no one receiving the data.
Any suggestion to resolve this problem? Is there a way to reset the XBee in the Arduino? Or maybe remotely from the RPI?
Here is the code flow in the Arduino
void setup() {
//Serial.begin(115200);
Serial.begin(9600);
Serial3.begin(9600);
xbee.setSerial(Serial3);
Serial.println("Testing");
}
void loop ()
{
receiveXbee();
//some code
sendXBee (param);
}
What do you mean by 'close the coordinator router' ? If you turn either of them off, they should re-establish connection when you turn them on unless they are binding to a different network. How long have you waited for them to coonnect? It can take a bit sometimes for them to find each other. I've never see it take more than around 3 minutes though.
DeleteAlthough, suppose you have the scan channels set up so they can step through all of the channels searching for a network. Then when you turn the coordinator off, it will come up and establish a network on a different channel and the two can sit there missing each other for quite a while.
That's only happened to me once when there was a long power failure and I had to walk around resetting things to get it going again.
However, in answer to your question, yes you can reset the XBee on the arduino by simply bringing the XBee reset line low. You can do this by hooking the XBee reset line to a pin on the arduino and holding it low.
You can't reset the XBee on the arduino from the Pi unless you can communicate, ... or run a couple of long wires across the room.
Tks you alot. It's verry usefull !
ReplyDeleteHave you tried using the reset call ever?
ReplyDeleteI want to reset the xbee from my Arduino using the API calls (not manual reset by xbee reset button) everytime the program starts. I see the function void XBeeResponse::reset() in xbee.cpp So I did the following in the setup
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
// create reusable response objects for responses we expect to handle
ZBRxResponse rx = ZBRxResponse();
ZBRxIoSampleResponse ioSample = ZBRxIoSampleResponse();
void setup (){
xbee.getResponse().reset();
}
But that doesn't seem to work. Any thoughts?
I never even knew there was a reset in there.
DeleteDo you have any example of implementing ZigBee mesh network with xbee?
ReplyDeleteYes, take a look around the site, I have several examples using different devices.
DeleteCan you be more specific which example you are referring to? I understand there are a few settings I need to do in the XCTU to create coordinator-router-end device architecture of a true Xbee mesh network. But I am wondering what do I need to do in terms of using the Xbee APIs
DeleteIn the upper right corner of this screen there is a search box, type 'zigbee' in there and you'll get all the posts that I have done in that area.
DeleteHello has any one tried implementing a python code to decode the received xbee package? the receiving xbee radio is configured as coordinator in API-2 mode and the sending xbee radio is configured as router. Please help with any sample code to decode the received packages at the coordinator.
ReplyDeleteOf course there's python code for reading an XBee packet. I have several examples of it on this site. Look around, use google.
Delete