Tuesday, October 30, 2012

Using the XBee library

Recently Paul Stoffregen created a new software serial library for the Arduino, then he modified Andrew Rapp's XBee library to use it (as well as the older, but really great, SoftwareSerial libray).  Suddenly, the XBee library is something that could be really useful.

See, the XBee library has traditionally been hooked into the hardware serial lines on Arduino Pins 0 and 1.  That means getting debugging information out of the device combination of an Arduino and an XBee is an exercise in frustration and annoyance.  Sure, you can use blinking lights to tell you what is going on, but this is the 21st century.  I have always written my own code to handle the XBee interaction because I wanted the serial port to provide status and control when I was working on a project.  Additionally, Andrew's library is heavily c++ and all the classes, inheritance, and instances confused the heck out of me.

However, maybe with the inclusion of a modified software serial port, and the capability to use the additional ports on an Arduino Mega, now is the time to take a serious look at using it.  I mean, if you have a mega, you can now put the XBee on Serial1 and keep Serial and Serial 2 for other things; this is just the ticket for converting RS485 into XBee packets to send over the air where you don't have wires.  Heck, I can think of dozens of things.

So, here is my first voyage into the use of the library.  I haven't linked in Paul's new serial library yet, I will on a future example, but I just wanted to understand what was going on and how to, at least, receive a packet and do something with it.  I took one of Andrew's library examples and modified it substantially to include many of the things I need in using an XBee and commented the heck out of it so others stood a chance of understanding what was going on.  It's amazing how few examples are out there that actually show what you need to do to do something along these lines.


The Arduino Sketch

/**
I took Andrew Rapp's receive example and modified it to be completely
unrecognizable.

I wanted to experiment with and better understand how to use his XBee
library for an actual project.  With the inclusion of support for SoftwareSerial
so that the XBee can be put on digital pins leaving the Arduino serial port
available for debugging and status, the library's usefullness shot way up.

This is a HEAVILY commented example of how to grab a receive packet off the
air and do something with it using series 2 XBees.  Series 1 XBees are left as
and exercise for the student.
*/

#include <XBee.h>
#include <SoftwareSerial.h>

XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
// create reusable response objects for responses we expect to handle
ZBRxResponse rx = ZBRxResponse();

// Define NewSoftSerial TX/RX pins
// Connect Arduino pin 2 to Tx and 3 to Rx of the XBee
// I know this sounds backwards, but remember that output
// from the Arduino is input to the Xbee
#define ssRX 2
#define ssTX 3
SoftwareSerial nss(ssRX, ssTX);


void setup() {
  // start serial
  Serial.begin(9600);
  // and the software serial port
  nss.begin(9600);
  // now that they are started, hook the XBee into
  // Software Serial
  xbee.setSerial(nss);
  // I think this is the only line actually left over
  // from Andrew's original example
  Serial.println("starting up yo!");
}

void loop() {
    // doing the read without a timer makes it non-blocking, so
    // you can do other stuff in loop() as well.
    xbee.readPacket();
    // so the read above will set the available up to
    // work when you check it.
    if (xbee.getResponse().isAvailable()) {
      // got something
      Serial.println();
      Serial.print("Frame Type is ");
      // Andrew call the frame type ApiId, it's the first byte
      // of the frame specific data in the packet.
      Serial.println(xbee.getResponse().getApiId(), HEX);
   
      if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
        // got a zb rx packet, the kind this code is looking for
     
        // now that you know it's a receive packet
        // fill in the values
        xbee.getResponse().getZBRxResponse(rx);
     
        // this is how you get the 64 bit address out of
        // the incoming packet so you know which device
        // it came from
        Serial.print("Got an rx packet from: ");
        XBeeAddress64 senderLongAddress = rx.getRemoteAddress64();
        print32Bits(senderLongAddress.getMsb());
        Serial.print(" ");
        print32Bits(senderLongAddress.getLsb());
     
        // this is how to get the sender's
        // 16 bit address and show it
        uint16_t senderShortAddress = rx.getRemoteAddress16();
        Serial.print(" (");
        print16Bits(senderShortAddress);
        Serial.println(")");
     
        // The option byte is a bit field
        if (rx.getOption() & ZB_PACKET_ACKNOWLEDGED)
            // the sender got an ACK
          Serial.println("packet acknowledged");
        if (rx.getOption() & ZB_BROADCAST_PACKET)
          // This was a broadcast packet
          Serial.println("broadcast Packet");
       
        Serial.print("checksum is ");
        Serial.println(rx.getChecksum(), HEX);
     
        // this is the packet length
        Serial.print("packet length is ");
        Serial.print(rx.getPacketLength(), DEC);
     
        // this is the payload length, probably
        // what you actually want to use
        Serial.print(", data payload length is ");
        Serial.println(rx.getDataLength(),DEC);
     
        // this is the actual data you sent
        Serial.println("Received Data: ");
        for (int i = 0; i < rx.getDataLength(); i++) {
          print8Bits(rx.getData()[i]);
          Serial.print(' ');
        }
     
        // and an ascii representation for those of us
        // that send text through the XBee
        Serial.println();
        for (int i= 0; i < rx.getDataLength(); i++){
          Serial.write(' ');
          if (iscntrl(rx.getData()[i]))
            Serial.write(' ');
          else
            Serial.write(rx.getData()[i]);
          Serial.write(' ');
        }
        Serial.println();
     
        // So, for example, you could do something like this:
        handleXbeeRxMessage(rx.getData(), rx.getDataLength());
/*
        // 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= 0; i < xbee.getResponse().getFrameDataLength(); i++){
          Serial.write(' ');
          if (iscntrl(xbee.getResponse().getFrameData()[i]))
            Serial.write(' ');
          else
            Serial.write(xbee.getResponse().getFrameData()[i]);
          Serial.write(' ');
        }
        Serial.println();
*/
      }
    }
    else if (xbee.getResponse().isError()) {
      // some kind of error happened, I put the stars in so
      // it could easily be found
      Serial.print("************************************* error code:");
      Serial.println(xbee.getResponse().getErrorCode(),DEC);
    }
    else {
      // I hate else statements that don't have some kind
      // ending.  This is where you handle other things
    }
}

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
  // it.
  for (int i = 0; i < length; i++){
//    Serial.print(data[i]);
  }
//  Serial.println();
}

// these routines are just to print the data with
// leading zeros and allow formatting such that it
// will be easy to read.
void print32Bits(uint32_t dw){
  print16Bits(dw >> 16);
  print16Bits(dw & 0xFFFF);
}

void print16Bits(uint16_t w){
  print8Bits(w >> 8);
  print8Bits(w & 0x00FF);
}

void print8Bits(byte c){
  uint8_t nibble = (c >> 4);
  if (nibble <= 9)
    Serial.write(nibble + 0x30);
  else
    Serial.write(nibble + 0x37);
     
  nibble = (uint8_t) (c & 0x0F);
  if (nibble <= 9)
    Serial.write(nibble + 0x30);
  else
    Serial.write(nibble + 0x37);
}

I tried to get all the major items out of the packet so they could be displayed and even included a tiny routine to illustrate using the received data.  This is what it looks like running:


You have to use the scrollbar at the bottom to see all of the message, but I wanted it that way instead of worrying about wrapping around.  I also put in print routines for the hex data; I love being able to see it in both hex and ascii.

Grab it, modify it to your purpose, and have fun.

83 comments:

  1. Hello,
    I was delighted to find your example as there don't seem to be many people using XBees on a software serial port.

    I have a lilypad main board connected to an XBee breakout board using conductive thread.
    I am using digital pins 2 and 3 on the Lilypad just like you as I'm keeping the hardware serial pins 0 and 1 free
    for use by the FTDI which I use for either a USB connection to my PC or a Bluetooth wireless connection to my laptop
    - I have a bluetooth modem with a FTDI header that I can connect to the lilypad for this. Output from Serial.print() etc.
    is then either displayed in a serial terminal window on the PC or laptop as expected.

    The laptop is running a Processing sketch that is broadcasting all the time, although I really only want this sender
    to broadcast every minute. I have a series 2 XBee radio (with coordinator firmware) connected to the laptop using an
    Explorer module. Here is an example of one of the transmit requests being broadcast:

    0x7e,0x00,0x1b,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xfe,0x00,0x08,0x45,0x41,0x01,0x00,0x50,0x52,0x49,0x4d,0x41,0x52,0x59,0x47,0x57,0x9b

    The only thing in this frame that I am unsure about is the 0x08 Options. the RF data and address fields look good.

    The red Tx led is on nearly all the time on the sender's Explorer as expected.
    On the lilypad's XBee breakout board, the power led is on and hte green rssi led only comes on occasionally.

    My big problem is that NONE of the XBee messages are getting through to the Lilypad!
    The lilypad is running your sketch from http://www.desert-home.com/2012/10/using-xbee-library.html
    I just put in an extra Serial.print to the else clause that you hate and of course it is being executed
    which indicated to me that the xbee.readPacket() is not working. No data is being received and there are
    no errors! Just as if the sender wasn't running at all....

    If you have any ideas about what might be wrong please let me know.

    Thanks in advance,
    Jackie.

    ReplyDelete
  2. First check two things for me, First make sure that both of the XBees are set for API mode and that they are using API mode 2. I've had a number of people have trouble and seek advice when that was their problem. Next, put a delay in the processing code to only transmit every couple of seconds. Using SoftwareSerial can chew up a lot of processing power on the little arduino and things get backed up and dropped on the floor.

    I had this happen big time on a project where things were coming in so fast that I couldn't process them on the board. Slowing down the conversation a tiny bit made it work perfectly every single time. I was getting behind and missing things like the checksum, start sentinel, etc and never managing to construct a complete packet.

    Try these two things and let me know

    ReplyDelete
  3. Thank you very much for getting back to me so quickly.

    I was very careful configuring each radio in X-CTU but I double-checked again and AP=2 on each radio.
    They each have the same PAN ID = 12345
    I also did a "Network Discovery" from the MoltoSenso Network Manager on the same laptop as the XBee coordinator.
    The other radio on the Lilypad was successfully discovered so it looks like the network is set up ok.

    I changed the delay between broadcasts from the sender (on the laptop).
    I tried a few different intervals like 0 (continuously broadcasting), 10, 30 and 60 seconds.
    No errors are ever reported by the sender but the XBee on the Lilypad never gets a message!

    Here is an example of a Transmit Status that the sender receives after a broadcast:

    [com.rapplogic.xbee.api.InputStreamThread] Received packet: int[] packet = {0x00, 0x07, 0x8b, 0x31, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x46};

    The delivery status and discovery status are both 0x00 for success.
    The 16-bit destination address is 0xFFFE which I assume is OK as it matches what I had in the Transmit Request that was broadcast.

    I don't know what to change on the Lilypad to get it to receive a message....

    ReplyDelete
  4. I agree with you about the options byte that is being sent by the processing code. According to the XBee user's guide, that's an undefined value and I don't have a clue if it matters or not. However, the transmit response indicates it found an XBee and actually delivered the message to it.

    So, everything indicates you sent something and it should have popped out the serial port of the XBee to the LilyPad you're using. Try checking the obvious: did you get the pins backwards such that output is hooked to output? Try switching them while it's running; that doesn't hurt anything. Did one or both of the wires from the XBee to the serial input break? You can also reverse the two XBees so that the coordinator is on the lilypad and the router is on the pc to see if something strange is going on.

    You can get the code to transmit I have on this blog and send from the lilypad to the pc; you'll have to modify it a tiny bit to use softwareserial, I think my example used a mega2560 with multiple serial ports. By transmitting you may turn up a clue what's going on.

    You can maybe try using different digital ports to see if there is a possible problem with either pin 2 or 3. Maybe temporarily hook the XBee to pins 0 and 1 so you have the leds on the board to tell you if data is coming in. If you have an arduino around, try plugging the XBee into it and running the same code to see if there's a difference.

    In a fit of desperation, look at the processing library to see if changing that darn 80 into 0 is possible; although I don't think it's a problem, I haven't seen that before.

    Let me know how it goes.

    ReplyDelete
    Replies
    1. Oh, one other thing. The else statement you mentioned doesn't indicate that the read failed, it just indicates that there is not an available packet nor was there an error. If you take out all the chaff I put in there, it will look like this:

      void loop() {
      xbee.readPacket();
      if (xbee.getResponse().isAvailable()) {
      }
      else if (xbee.getResponse().isError()) {
      }
      else {
      // I hate else statements that don't have some kind
      // ending. This is where you handle other things
      }
      }

      I intentionally did that to allow the little computer to be doing something besides just hanging looking for a packet from the XBee. So, what you're seeing with a debug statement in the else is perfectly normal.

      I should probably get that out of there to keep from confusing folk.

      Delete
    2. Ok, fine, I just can't seem to get it together today. When I looked on the web for clues to this a lot of people have problems doing what you're doing. Most of them seem to have problems getting enough power to run both the lilypad and the XBee. In this case, the XBee will be the big power user and when it transmits, it could starve your power supply. I haven't worked with a lilypad, but it was designed to work off a small battery and the XBee needs more than that to transmit.

      You probably already know all this, if so, just ignore me.

      Delete
  5. Hi Dave,

    Thanks for all your suggestions. I am worried about the power supply for the lilypad alright as I only have a 3.7v lipo:
    https://www.sparkfun.com/products/341
    I try to keep it fully charged and the xbee's power led is on. I also run the lilypad when it is getting extra power from my PC via USB.
    The tx and rx connections are sewn with conductive thread so it is not easy for me to switch these around while running a sketch.
    I wish that Options byte wasn't 0x08 but nevertheless I am fairly confident that the msg from the laptop is reaching the lilypad's xbee breakout board as its RSSI led comes on when the sender's TX is on.
    Although, having said that, the RSSI led is never very bright.

    However I did modify that dreaded else clause on the lilypad to send a message to the coordinator on the laptop and those msgs are working!
    So I have one-way communication out of the lilypad but not in...

    I do have an Uno as well so I will try to do some further testing with that although it was exhibiting similar behaviour as the lilypad when I last checked.

    Thks v much for your help,
    Jackie

    ReplyDelete
  6. Jackie, having one-way comm eliminates a lot of stuff. Could the conductive thread from the XBee to the Lilypad have broken? It appears power, setup and every thing else is ok or it wouldn't transmit. A simple broken connection could be your problem.. Time for an ohm meter check between the boards. If that works, then there may be a hardware problem with the XBee, its board or the serial input pin you're using. Since you're using broadcast and not addresses, you can reverse the two XBees and see if the problem moves with the XBee, which would likely mean a bad XBee.

    You're getting closer, and some testing on the UNO should narrow it down a lot.

    ReplyDelete
  7. Hello Dave,

    I appreciate too much your xbee examples!!! It helped me a lot to make my Xbee API network. I was having problems to get the RSSI data. I am using the Xbee series 2 and have tried use rx.getRssi() but it didnt work, then I thats happens because I am using wrong function for this series. Andrew suggested use rx16.getRssi() on his site, but i think this function is for series 1. Would you help me on this mattter?

    Tks too much for your help,

    Alipio Carvalho

    ReplyDelete
  8. Alipio,

    As I understand it, the only way to get the rssi value from a series two XBee is to use an AT command which is frame type 8 and it will return an AT command response, frame type 88 that holds the register contents. The relevant API frames are on pages 103 and 110 of the User's guide.

    The command to send in the AT command is "DB" and is described on page 132. So you should be able use the XBee library's AT command interface and get the value back.

    The XBee document is at: http://ftp1.digi.com/support/documentation/90000976_G.pdf

    In theory, there is a way to get it using the digital pins I/O interface, but I've never heard of anyone successfully using it.

    You can even set an XBee up in AT mode, hook it to a PC, and use XCTU to test this before you try and program the frame construction on an Arduino.

    ReplyDelete
  9. Hello Dave,

    Thank you very much for your suggestion!!

    Alipio Carvalho

    ReplyDelete
  10. Hi Dave,

    My problem is fixed! My supervisor suggested using the AltSoftSerial library instead of SoftwareSerial. This involved switching to pins 8 and 9 on the lilypad. It has done the trick! I finally have 2-way ZigBee communication. I should have paid more attention to this recommendation on http://code.google.com/p/xbee-arduino/wiki/SoftwareSerialReleaseNotes

    Thank you very much for your help and great suggestions. Best of luck with your projects,
    Jackie

    ReplyDelete
  11. Jackie,

    That's great, but I wonder why you need to use the alt. Your description didn't indicate that you were running anything that would interfere with the software serial that comes with 1.0.1 or above.

    But, then again, it works! That's the important part.

    ReplyDelete
  12. Thanks to everyone for all this great information!

    Jackie -- perhaps the reason that switching pins worked has to do with the particular way in which softserial is setup on the Lilypad. The latest lilypad uses the same processor as the Leonardo does, and only particular pins on the Leonardo (including 8 and 9) are capable of software serial, I believe. This fellow provides a bunch of relevant detail on the issue in a blog post here:

    http://vort.org/2012/05/25/trouble-softserial-arduino-leonardo/

    I'll be using all this great info you've all collected here soon myself. Thanks again so much for posting.

    ReplyDelete
  13. Hello,
    I am working on designing an XBEE pro to form a mesh networking for image transmission. Could any body explain how i can achieve this? first i want to know if it is possible? I have 9 arduino uno board and 10xbee pro and a USB dongle connected to the computer. Can any one help with the codes, i am ready to pay. Thanks....................mail: ay4real@hotmail.ca

    ReplyDelete
    Replies
    1. Not sure what you mean by image transmission, but it's very likely that the XBees won't do it for you. They're designed for real time transmission of small packets over a mesh network to monitor and control devices. That doesn't include the large amounts of data that images require. You could easily flood an XBee network with a single image for several minutes. Yes, minutes.

      Images need a high rate of data transfer and you just can't get that from an XBee. Start looking at wireless ethernet techniques.

      Delete
  14. Hi Dave,

    Your site has made my efforts sooo much easier. Many Thanks. But I could use a little help.

    I'm trying to send data between two Arduino Uno's. From your examples, I've been able to make Arduino A talk to Arduino B with your "Hello world" and "I saw...". Yippee!

    I've looked around your site but have not seen where you send float, long and int type data. In my case I'm sending a variable - micros() of Arduino A to Arduino B so that the two are kinda time synced. Arduino B then does some calculations with external sensor inputs. Arduino B then sends back a variable (probably an unsigned long) to arduino A.

    Could you point me in the right direction as to how I would substitute your "Hello World" with these types of variables?

    Thanks

    Bill

    ReplyDelete
  15. There's a huge discussion of this on one of the pages ... somewhere in the comments. Basically what I do is to convert it to text then send it. When I get it at the other end, I convert it back to whatever I need. For integers, I use the c routine itoa() to get an ascii numeric representation and then atoi() to turn it back into an integer. Then, I found out that printf() actually worked on the arduino and I mostly converted everything to use that. A simple statement like:

    sprintf(Dbuf,"Power,%d.%02d,%d.%02d,%d.%02d,%d.%02d,%d.%02d,%d.%02d\r",
    (int)realPower, frac(realPower),
    (int)apparentPower, frac(apparentPower),
    (int)powerFactor, frac(powerFactor),
    (int)Vrms, frac(Vrms),
    (int)Irms, frac(Irms),
    (int)freq, frac(freq));

    should be a reasonable illustration of what can be done. the things like (int)variable, frac(variable) are taking the integer and fractional part of a float apart and converting it to ascii in the %d.%2d parts of the format string sent to printf. There are many ways of doing this, but I chose this one because it was easy. To get it back, you do something like:

    realPower = atof(strtok(0, ","));
    apparentPower = atof(strtok(0, ","));
    powerFactor = atof(strtok(0, ","));
    rmsVoltage = atof(strtok(0, ","));
    rmsCurrent = atof(strtok(0, ","));
    frequency = atof(strtok(0, ","));

    The sttrtok() call is used to separate the values and then atof() is used to turn them back into floats. I did it this way so I could monitor the traffic and actually see the values. Instead of trying to figure out what the values were from binary data, it's clearly readable. It also helps in debugging the code while you're working on it because you can print the string to the terminal and take a look at it, then at the other end look at it as it comes out of the XBee and see that it got there ok.

    Hope this helps.

    ReplyDelete
    Replies
    1. Thank you... I will try that tomorrow. I'm calling it a night.

      I just finished fiddling with code that broke a long into separate "parts" then reassembling them on the receiver end. I got it to sorta work. But since I'm a real beginner, my methodology is to try something then see what happens.

      But no doubt, your website has been of tremendous help. There is NO WAY I would have gotten this far with just the Xbee library docs, etc.

      I'll let you know

      Thanks again

      Bill

      Delete
    2. Floats are the problem since the arduino library doesn't handle them as well as other datatypes. It's a little confusing, but you'll get it in a couple of tries.

      And don't worry about trial and error programming. That's the way it's done these days.

      Delete
  16. Good evening Dave,

    I've been messing around with different types of variables and arrays all day. It seems I could have saved a great deal of time just listening to your comments about arrays.... way to slow...

    So thanks to your help, I've been able to convert a long to a string and successfully send the string. But I'm stuck on the receiving end. Your examples can println the string, but I don't know how to make it into a variable. Do you have an example somewhere of how to reconstruct a string variable on the receiving end. Once I get that string variable, I can convert it to a long.

    Thanks for all your help,

    Bill

    ReplyDelete
    Replies
    1. Bill, I decided to put together a blog post on this so I could include the code easily. I've gotten many questions on how to send this kind of data over an XBee or a serial connection of some sort, and now seems like a good time to address it in a way that people can cut and paste from. So, hit the button up top for the main page and take a look. Here's URL if that doesn't work http://www.desert-home.com/2013/10/floats-and-strings-over-serial-link.html

      Delete
    2. Good afternoon Dave,

      I still seem to be stuck on the receiver end, particularly around how to get the string from the rx.getdata() array.

      This is what I use to send my string... i.e. real simple

      unsigned long basetime = micros();
      ltoa(basetime, buf, 10);
      ZBTxRequest zbtx = ZBTxRequest(Broadcast, (uint8_t *)buf, strlen(buf));
      xbee.send(zbtx);

      On the receiving end, I can print all the data along with your other cool information print outs... but my basetime variable (as a string) seems to be only accessible by using the following -

      for (int i= 0; i < rx.getDataLength(); i++){
      //Serial.write(' ');
      if (iscntrl(rx.getData()[i]))
      Serial.write(' ');
      else
      Serial.write(rx.getData()[i]);
      Serial.write(' ');

      Is this "for" loop the only way to get the data. I studied your new blog code (thank you!) but ...well... am I missing something right in front of me?

      Thanks

      Bill

      Delete
  17. Nope, you're not missing anything that I can think of. Notice up there in my example how I print the text from the payload in a loop? That's because the data isn't guaranteed to have a null at the end of it to make it into a 'c' string.

    Let me 'splain what the loop you're using is actually doing. It's taking the characters out of the packet that was returned one at a time, checking to make sure the character isn't control character because that might mess up the display and the printing it using 'write' so there isn't any formatting done by Serial.print(). Since we don't know how long the buffer is and if it is safe to just stuff a null at the end of it, we have to copy it out into another place and stick the null at the end ourselves.

    so make a buffer to hold it and copy it character by character into the buffer and stick a null at the end. Then it's a real string and you can Serial.println( thenewbuffer); just fine. Actually, the code is almost there:

    char buffer[50];

    for (int 1=0; i<rx.getDataLength(); i++){
    buffer[i] = rx.getData()[i];
    }
    buffer[i] = 0;
    Serial.println(buffer);

    Taa Daa, buffer will now hold a string (if I didn't mess something up above). You can now use the new string any way a string can normally be used.

    Did this help?

    ReplyDelete
  18. Hi Dave,

    Yes that made all the difference. I did make that i=0; instead 1=0 and I took out the buffer[i]=0 ... but it seems to be ok. Now I'm working to reduce latency... more fun :-)

    Thanks again for all your help.

    Bill
    Thanks

    ReplyDelete
    Replies
    1. oops ...

      Be careful about not using the last buffer[i]=0; What can happen is that you put something longer in the buffer like "Hello World" then later put a number in it, you'll get something like "1.23o World" in the buffer which can cause you trouble. That's why most programmers stuff a null explicitly at the end of the text they're copying to be darn sure there's a null to terminate the string.

      Delete
  19. Hi Dave,

    Thanks for the advise. I've been redesigning the whole system and found a great way to simplify ... The biggest headache was getting the data transmitted with the correct time attached... time being accurate to a millisecond. I recently discovered the PPS signal from an Adafruits GPS. So now my arduinos are all synced and I can transmit much simpler data.

    ReplyDelete
    Replies
    1. I spent a couple of months messing around with time trying to get it right. Although I only want (not need) accuracy to the second, I couldn't get it. Finally I got one of Adafruit's GPS chips, combined it with an arduino and an XBee and put it in the attic. Now I have a time standard for the house that everything uses. They each sync their clock code to the house clock on boot and every time a new clock packet comes over the XBee network.

      I even have a tab for the clock up there somewhere. That was one of my best ideas.

      Delete
  20. I have a question. Will this code work on a Xbee Series 2 coordinator in API with 2 Xbee Series 2 routers in AT mode?

    ReplyDelete
    Replies
    1. Yes, but you have to be aware of what you'll get out. The routers, being in AT mode will only output the payload data to the serial port. Going the other way, what ever you send will come out the serial port in an API packet and have to be taken apart by the library.

      Delete
    2. Thanks for the reply! I got the code working & it works greats! But This still leaves me with a few other problems:

      In my network, there are 2 routers & 1 coordinator
      1. Error code 3 & Error code 1 comes up, & I think it may be due to my routers being in AT mode. My theory is they are both trying to talk to my coordinator at the same time & this creates a deadlock.
      2. Even when one of my routers are disconnected, I get to one Error code 1 message & 1 Error code 3 message momentarily.

      So here's my questions:
      First, to prevent deadlock, is it at all possible to program the coordinator in Arduino-C to tell each router to "wait"? Or can I do that straight from X-CTU?
      Second, what is the possible cause of the Error codes coming up when I only have only one of the routers connected? When I have the coordinator (in API mode) & one of the routers (in AT mode) connected to the network, it still displays Error code 1 & 3. The great thing is that the network displays those error print statements for short periods of time & goes back to normal, displaying the data as it should. I think both routers are walking all over each.

      Delete
    3. Error code 1 is a bad checksum and error code 3 is an unexpected start byte. So it sounds like you're using API mode 1 instead of API mode 2. Check your configuration, it's the AP command and it should be set to 2. In XCTU it's under the serial interface.

      The XBees don't deadlock. They may well transmit over the top of one another, but they automatically retry to take care of that. On an incredibly busy network, the collision rate can get high, but they do their best to correct for it. The way it works is they enable the radio and listen for a quiet spot and then try to transmit, if it gets clobbered by some other device, they will do it again. The times that they wait are semi random, so they will recover really well. There's no locking to worry about.

      Delete
  21. I just want to say Thank-you, Thank-you, Thank-you! I read both books "Building Wireless Sensor Networks" and "The Hand-on Xbee Lab Manual" and I learned far more from your site than both books combined regarding using the Arduino, Xbee, and the Xbee library. You explained everything in great details.

    You should consider writing a book about it and include all the projects that you have done. I would be the first one to buy it.

    I have a question. When you setup a wireless sensor network about 10 nodes or more, how much delay would you recommend to put in each node when sending a package to the coordinator? I found out that sending a package every 10-15 seconds for each node would reduce the traffic greatly and without errors.

    ReplyDelete
    Replies
    1. I use different delays for different devices. For example, I use 5 seconds in power measurements so I can catch some of the appliances when they cycle. Clothes dryers operate the heating element in short bursts and can be hard to catch on. The garage doors report every minute or whenever they're told to do something. Thirty seconds for the pool, three minutes for the acid pump. The septic tank is the longest at 3 and a half minutes.

      However, all of them except the pool, will report on command. I send them a packet with something in it like 'status' or '?' and they send back what they've got right now. This is to be able to interrogate the sensors to be sure something happened.

      Yes, cutting back on the reporting interval cuts the traffic way back. Especially since some of my devices are too far away from the controller and have to rely on store forward.

      Delete
    2. Regarding report on command. I am sending the value of XBee SL address as a string "0x40ade9b5" via the serial port. How can I pass this value as a parameter into XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, x) since x is in hex.

      Do you have an example code of report on command?

      Delete
    3. Actually, there's several examples of this kind of thing on this blog. For example, the post: http://www.desert-home.com/2013/02/using-xbee-library-part-3.html uses the hex addresses you're wondering about. The way I get it to report on command is to send a command such as 'status' to the device and let the attached processor decode it and respond.

      If you don't have an attached processor, just using the XBee alone, you have to wait for the XBee to time out and send on its own. Almost all of my homemade devices have an attached processor.

      Delete
    4. Dave, I stop using broadcast altogether because it required too much processing and bandwidth. It slows down everything. Right now, I am using report on command only. Each router will send the report to the coordinator and end devices will send the report to one of the routers or the coordinator.

      What I did was very simple. I wrote a Windows program (controller) that communicates through the serial port sending the node address and command.

      For example I would send a string of "0x40b77a1b,LightOn" through the serial port. Assume hexAddress = "0x40b77a1b" and the command = "LightOn" The code would be:

      // convert hex string to long integer
      long decAddress = (long) strtol(hexAddress, NULL, 0);

      // Pass the address of the XBee that you want to send the command
      XBeeAddress64 nodeAddress = XBeeAddress64(0x0013a200, decAddress);

      // Send the command. From your example. I love what you done here.
      ZBTxRequest zbtx = ZBTxRequest(nodeAddress, (uint8_t *)command, strlen(command));

      xbee.send(zbtx);
      delay(10);

      How easy is that!

      Delete
    5. Cool. You do realize I'm totally going to steal your idea.

      Delete
    6. I have a little problem. Since I no longer use broadcast, my routers only send the packet to the coordinator. The coordinator's SL address is already preprogrammed into each router. If the coordinator's radio dies, I would have to reprogram all the routers again. There must be a solution whereby I can just change the coordinator's radio without having to reprogram the routers. What are your thoughts?

      Delete
  22. First you don't have to use the coordinator as the central destination; the coordinator can be just another device on the network. My coordinator is my satellite clock that stays up in the attic gathering the time and coordinating the network. My automation controller is just another router, but I have all the devices send to it. We tend to think that the coordinator has to be the central control point, but it doesn't. That means you aren't constantly taking it off line running the risk of breaking it or messing up the programming. Heck, it can be an XBee hooked to a wall wart plugged into the wall somewhere, it doesn't need to do anything else.

    Next, the trick ( I learned this relatively recently) is to let the XBee take care of addressing. By programming the address you want to send to into the XBee instead of the processor code, you simply change the address in the XBee and you're ready to go. This depends on reading the destination address out of the XBee in your code when you're using code that always sets the address. You can get the DL with an AT command. If the code just uses the address in the XBee, you can skip reading it and just use it.

    I did this several times by using the remote configuration capabilities of XCTU. I simply changed the destination address in the XBee remotely. I don't think I ever did a post on this capability of XCTU, but it's a really nice feature.

    Another way is to have the processor get the address it's supposed to send to when it first boots up. I did this once by having the device that wanted the data send its address in a broadcast every 10-15 seconds. Each device, on boot, just listens until it hears the message and then sends its data to that address.

    Also, if you set the network up in a flexible fashion, the routers can all set themselves up to a new controller in just a few minutes. I discovered this when I screwed up my entire network trying out some new techniques. I posted about it here: http://www.desert-home.com/2014_01_01_archive.html

    So, pick whichever combination of techniques you feel will best work for you and try them out. I like the flexible network with the automation controller (not the XBee controller) sending its address over the network repeatedly. This also allows you to be sure any particular XBee can see the automation controller by simply watching for the address message. In network jargon, this is called a 'beacon'. I haven't posted about this technique either; glad you brought it up.

    ReplyDelete
  23. Dave, thanks for the suggestions, but I am a little bit confused. If you program the address you want to send to into the XBee instead of the processor code, then what do you need to do in the processor code to send the packet?

    XBee library requires a 64bit address so that it knows where to send the package. What would you do in the //Specify the address of the remote XBee? Do you leave it at 0x0 for the SH and 0x0000ffff for the SL? Will XBee uses the processor code SL address or the address that you already programmed into the XBee?

    // Specify the address of the remote XBee (this is the SH + SL)
    XBeeAddress64 addr64 = XBeeAddress64(0x0013a200, 0x403e0f30);

    // Create a TX Request
    ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));

    // Send your request
    xbee.send(zbTx);

    ReplyDelete
  24. You're right, I used that technique when I was still using broadcast between the devices. When I went to API mode on all of them I put in code to read the DL from the XBee on boot up and saved it to stick in the packets. I sort of used the XBee as non-volatile storage of the destination address. I could then change the address remotely with XCTU, send a command for the arduino to reset and it would come up, read the address and use it. Later, I realized that I could simply send a new address in a message; something like "sendto 403e0f30" and I could change the destination address without having to reset the arduino.

    Since I did it several different ways over time, I get them mixed up.

    On XBees that only have sensors attached, I simply change the DL address using XCTU since there is no other processor involved. I do this with my battery monitors and outdoor temperature sensor.

    ReplyDelete
  25. Dave, I thought you might be interested in these devices.

    1. Connect anything anywhere. http://www.sodaq.net/#!getting-started/c21ma

    1. XBee controlled smart outlet http://www.seeedstudio.com/depot/Smarthome-Kit-Smart-Outlet-p-1105.html

    2. Generic gateway for internet of things. http://www.seeedstudio.com/depot/Dragrove-Generic-gateway-for-internet-of-things-p-1118.html

    ReplyDelete
    Replies
    1. Thank you. The outlet is discontinued darn it, but at $50, not the best price for a single external device. The Sodaq is pretty tempting. I'd have to buy a solar cell and lipo battery to use it. I wonder why they put thermometers on boards that are going to be inside an enclosure; seems to defeat the purpose. The generic gateway is meant to have wires hooked to it. Isn't that a bit silly in the 21st century?

      But, they are all compelling products. It shows that people are starting to think seriously about this kind of thing.

      Thanks again for the pointers.

      Delete
  26. Hi Dave,

    I am trying to send GPS data from one XBee to another using Arduino Mega and Uno. Both XBee's are in API mode and Series 2 version. The problem is that GPS returns results in double but payload in my program accepts int only. You can see some fragments of the code below:

    XBeeAddress64 addr64 = XBeeAddress64(0x0013A200, 0x40ADD02C);
    ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));
    ZBTxStatusResponse txStatus = ZBTxStatusResponse();

    pin5 = UTC();

    payload[0] = pin5 >> 8 & 0xff;
    payload[1] = pin5 & 0xff;

    xbee.send(zbTx);

    I have a UTC() method which returns local time in double. So, can you please tell me how to send data other than int in API mode.

    ReplyDelete
    Replies
    1. I did a post in response to this particular problem here: http://www.desert-home.com/2013/10/floats-and-strings-over-serial-link.html . Lots of people have this problem.

      Delete
    2. Thanks Dave this is really helpful. But what about sending it? You have mentioned in " Floats and Strings Over a Serial Link (like an XBee) " section that - "The middle part where the string is sent between two devices can be found in other places on this blog." . So can you give me proper link for this??

      Delete
    3. I cover that in detail in several places take a look at my XBee page. It's the tab up at the top labeled "The World of XBee". Look at the posts on the XBee library.

      Delete
  27. Hi Dave,

    Thank you so much for the example code - it has really helped me. One issue I'm having at the moment is that every 3rd, or 4th, or 5th packet returns with error code 3, "UNEXPECTED_START_BYTE." Right now I'm testing on an Arduino Duo, with two S2 XBees. The coordinator is in API mode with escape characters. The router is in AT mode.

    Is this behaviour normal, or would you say it's happening too often? I'm wondering what I can do to fix this.

    Thanks again! :)

    ReplyDelete
  28. Actually, I did some closer inspection and the error code is happening every 12th packet, and then every 11th packet, and then every 12th packet, etc etc. It doesn't seem to be deviating from this pattern. I'd call that a strange, dependable error, wouldn't you?

    ReplyDelete
    Replies
    1. Go double check your API mode setting. It MUST be API mode 2 (escaped characters) to use the arduino XBee library. If you accidentally left it in mode 1, this is the exact kind of error you would get.

      The other possibility I've seen is noise cutting a packet in half. So, the packet doesn't finish because of the noise and then another packet comes in. This usually has unexpected start byte and then a checksum error.

      I have a whole blog entry explaining the API modes and why they are important, as well as how to set them under the older version of XCTU. Look around for it.

      Delete
  29. Dave,

    sorry to be a pain, but I don't really know much c++. Could you please explain why in this function you use the same if statement twice.
    void print8Bits(byte c){
    uint8_t nibble = (c >> 4);
    if (nibble <= 9)
    Serial.write(nibble + 0x30);
    else
    Serial.write(nibble + 0x37);

    nibble = (uint8_t) (c & 0x0F);
    if (nibble <= 9)
    Serial.write(nibble + 0x30);
    else
    Serial.write(nibble + 0x37);
    }

    Thank you in advanced

    ReplyDelete
    Replies
    1. Heh, I'm sorry, I thought I was making things clearer and it had the opposite affect. In the first set, I SHIFT the bits 4 to the right, that takes the high order 4 bits and puts them in the low half, then I add either 30 (an ascii zero) or 37 (an ascii seven) to it depending on its value.

      This effectively converts the low order half into a number 0-9 and A-F to represent the hex value for display. Then in the second set of statements I AND it with 0x0f to strip off the high order bits because I already displayed them and do the same addition converting those bits to another hex number.

      I did this a long time ago in an early version of the Arduino IDE which didn't have sprintf so I could see the value of the various bytes in hex for debugging.

      Does this make sense??

      Delete
  30. Dave,

    Thank you for your explanation. It does make sense now. I'm sure they way the code is written is clear for those with more arduino / c++ experience that I have.

    I have to say I'm learning more from your website then after reading Building wireless sensor network book. You should think about writing your own book!

    ReplyDelete
    Replies
    1. This is a book, have you seen how many posts there are?

      Delete
  31. Thank you so much for this post! It helped me do exactly what I wanted :)

    ReplyDelete
  32. Thanks! API Mode 2... that's what I had forgotten to set and my code started working like a charm :-)

    I realized my mistake after reading your article and the comments: no more Error Code #3 after that!

    Thanks again!

    Marc

    ReplyDelete
  33. Hello Dave
    Greetings from Southern UK
    I've been tinkering around with XBees (all Series 2) in a small network of three routers in AT mode and a sleeping end device.
    In XCTU, everything is fine, good signal etc.
    The data is a mixture of analogue and digital, again all fine.
    I have a working sketch on Arduino based largely on Faludi's book examples which again works fine, but occasionally drops some data.
    I thought I might try a different approach with Andrew Rapp's library, but to date, not a sausage.
    I found and tried your sketch and for the irst time, actually got some data, so many thanks.
    However.... the only data I get is Frame type (always 92 which I would expect), nothing else.
    API mode set to 2 on the coordinator.
    Any ideas what might be going wrong? I feel that I might be within spitting distance

    Regards
    Phil

    ReplyDelete
    Replies
    1. Phil, not getting data is usually one of two reasons: You're not putting it in, or you're not getting it out. That may sound silly, but I've managed to mess up and not get the data into the transmitter XBee and then spent days trying to find out why over on the receiver.

      Once I was sending binary data and it started off with a null byte; then on the coordinator, I was trying to read it with a strcpy() which terminated immediately because of the null.

      That's the kind of thing I've had happen.

      Delete
    2. Hello Dave
      Thanks for that.
      The data is certainly getting to the coordinator because if I do a simple Serial.read() on the Arduino, I get the full set of bytes from 7E to the checksum.
      It's stalling at "if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {", which must be returning a FALSE.
      All my frames are 0x92 in Native mode or 0x91 in explicit.
      I'm not familiar with AR's library and haven't had a chance to understand or see what the stalling "if" is looking for.
      Is 0x92 an acceptable frame type for your sketch?
      Excuse the dumb questions, but I'm a very late in life learner.
      Cheers

      Delete
    3. I think I'm catching on. No, the code on this page doesn't handle an io sample packet. Andrew's library does handle it, but I didn't cover it until part two of my description of how I use his library.

      http://www.desert-home.com/2012/11/using-xbee-library-part-2.html

      The code there is for a different board, but you should be able to cut and paste to get what you need. This code is specifically for folk that have the data in some other form on a little processor and want to send it through the XBee.

      Delete
    4. Thanks Dave,
      I'll have a look tomorrow as I have to fix the wash basin before bed. I used to write technical manuals amongst other things and it's so important to explain everything as you go along, the train of thought, even for yourself. It should be good enough for your mother or whatever to sort of understand it. Andrew is undoubtedly a very clever person, but his code does take some working out. I'm not ashamed to say I'm a cut and paste type, but my aim is to run the ventilation fan, not understand degree level programming. By the way, all this is to do with controlling better energy usage and all the XBee packets come from utility energy meters. It's taken three years to get reliable counts from the gas meter, but the hardware (Hall sensors, optical etc. all take time as well). But if you crack it for one, you've cracked it for all of them. I'm just waiting for the day they fit a smart meter to mess it all up.
      Cheers, Phil

      Delete
    5. You can read the XBee packets? Here they encrypt them with super secret keys and no one I know of has broken the encryption. I built around it long before they put a smart meter on the house and haven't even bothered to look at what they're doing.

      Delete
    6. No, I'm afraid I'm not that clever.
      What I meant was nothing more than if you get methods right (optical, magnetic etc.) fot one type of meter, then it generally works for all types. The three years was just to get the basic pulses going - you could add a couple of noughts to the three if I was was decrypting.
      Smart meters aren't there for our benefit - I used to work for the water company

      Cheers

      Delete
    7. Here in AZ some years ago they convinced the regulators to let them charge to read the meters on our houses. Then they installed the smart meters and they no longer have to read the meters. Did they remove the charge to read the meters? Of course not.

      I'm so tempted to surround the meter with a faraday shield to stop it from transmitting so they have to come out and actually read it.

      Delete
    8. Greedy minds think alike. Thames Water (one of the big ten)tried to charge for reading some years, but got shouted down. My firm (Southern Water) used to charge for disposing of rainwater, even if it went to a soakaway. They were eventually found out and dropped the charge - refund what customers had already paid for a non-existant service? did they hell.
      I happen to know that the "electronic" readings can be way off the dial readings - sometimes the dials move but no readings are registered. The ones we use are on a 3G network. I have a feeling that shielding it might be classed as tampering, but you could always make the shield look like oil drum or a wheelbarrow if the meter's on your land. A lot of meter readers are looking for new jobs thanks to smart.
      I'll have a look at the 92 frames when I look at your part 2 and let you know how I get on. I have a rudimentry frame handling sketch going on the Arduino, but the frames are all different lengths, so lots of "if"s and "switch case"s.
      Cheers

      Delete
    9. Handling the frames is not as tough as it looks at first. Essentially it's a big switch statement with all the frames represented by specific cases inside. I was doing that exact thing for a year or two until the changes to the serial input and expansion to a mega board happened. It was at that point that I switched over to Andrew's library.

      Then, I actually had to add to the library to include some frames that he left out so I could play with Zigbee. I now have my own version of the library that I can muck with when I'm debugging something.

      Good luck playing around, I look forward to hearing about your adventure.

      Delete
  34. hello sir, I'm working with zigbee series 2 and arduino atmega 2560. I wanted to build a mesh network where 3 zigbee modules communicate each other. But my first step is only not working :( I tried your code too, but its not working. I don't know where I'm going wrong. I configured my zigbees in API mode. Can you please guide me where I'm going wrong and with the code too.
    Thankq :)

    ReplyDelete
  35. hello sir, I'm working with zigbee series 2 and arduino atmega 2560. I wanted to build a mesh network where 3 zigbee modules communicate each other. But my first step is only not working :( I tried your code too, but its not working. I don't know where I'm going wrong. I configured my zigbees in API mode. Can you please guide me where I'm going wrong and with the code too.
    Thankq :)

    ReplyDelete
    Replies
    1. Sure I'll help, but I have no idea what you have set up and what doesn't work. Tell me more.

      If you want, look at the 'about me' for my email address.

      Delete
  36. Thankq sir for your reply:)
    Our project is to communicate 3 zigbee modules which are in motion. I configured the zigbee modules as following:

    Zigbee coordinator API

    Pan ID
    Operating channel
    Destination address high : 0000
    Destination address low:FFFF
    MY:0000
    Encryption enable :1
    API enable :2

    Zigbee router API (Other two zigbee modules)

    Pan ID: (Same as coordinator)
    Operating channel: (same as coordinator)
    Destination address high : 0000
    Destination address low:0000
    MY:FFFE
    Encryption enable :1
    API enable :2

    Coordinator code:

    #include
    XBee xbee = XBee();
    #include
    #define ssRX 2
    #define ssTX 3
    SoftwareSerial nss(ssRX, ssTX);
    void setup()
    {
    Serial.begin(9600);
    nss.begin(9600);
    // now that they are started, hook the XBee into
    // Software Serial
    xbee.setSerial(nss);
    }
    void loop() {
    uint8_t data[] = {'H','I'};
    XBeeAddress64 addr64 = XBeeAddress64();
    XBeeAddress64 addr164 = XBeeAddress64();
    addr64.setMsb(0x0000);//XXXXX -> Msb address of router/end node
    addr64.setLsb(0xFFFF);//XXXXX -> Lsb address of router/end node
    ZBTxRequest zbTx = ZBTxRequest(addr64, data, sizeof(data));
    xbee.send(zbTx);
    delay(100);
    }

    Router code:

    #include
    XBee xbee = XBee();
    #include
    XBeeResponse response = XBeeResponse();
    ZBRxResponse rx = ZBRxResponse();
    #define ssRX 2
    #define ssTX 3
    SoftwareSerial nss(ssRX, ssTX);
    void setup()
    {
    Serial.begin(9600);
    nss.begin(9600);
    xbee.begin(nss);
    }
    void loop()
    {
    String sample;
    xbee.readPacket();
    if (xbee.getResponse().isAvailable())
    {
    Serial.println(xbee.getResponse().getApiId());
    if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE)
    {
    xbee.getResponse().getZBRxResponse(rx);
    for (int i = 0; i < rx.getDataLength(); i++)
    {
    sample += (char)rx.getData(i);
    }
    Serial.println(sample);
    }
    }
    else if (xbee.getResponse().isError())
    {
    Serial.println("Error reading packet. Error code: ");
    Serial.println(xbee.getResponse().getErrorCode());
    }
    delay(100);
    }

    After uploading these codes to arduino, router is not receiving the message sent by coordinator i.e I'm not able to see message on serial monitor. So, sir can you please help me where I’m going wrong as early as possible. This is my final year project, as project deadlines are near and I’m worried. Please help me sir.

    ReplyDelete
    Replies
    1. A few things to start off with. Disable encryption, this makes things more complicated at first. It's better to get the project going and then turn it on if needed.


      Download the latest XCTU from digi if you haven't already. Then supply power to all the XBees and plug the coordinator into the PC. Use the network mapping function of XCTU and make sure all the XBees show up as a network.

      You are using a 2560, and should not use software serial. The mega has multiple serial ports. Use the first port as your debug console and the second one for the XBee serial line. Software serial won't work on a uart controlled port like that. It will also make the code much simpler and smaller.

      Let me know what happens when you do these things.

      Delete
  37. Thankq for the reply :)
    sir, i understood first two points but I'm not getting your point on atmega 2560.
    As I don't know much about atmega, then how should we set baud rate to 9600?
    can you please guide us..

    ReplyDelete
  38. The Arduino Mega 2560 has four serial ports, not one. That means you don't have to use the SoftwareSerial library. In fact, it's difficult to get the SoftwareSerial library to work properly on a 2560.

    So, use one of the serial ports to connect to the XBee and it will be much easier to implement the XBee. I have a post where I illustrate this:

    http://www.desert-home.com/2012/11/using-xbee-library-part-2.html

    There's only slight modifications to your existing code to do this, so it isn't hard. Notice also that the link above is part 2 of this post.

    ReplyDelete
  39. Sir, i did the following changes:
    I disabled encryption enable and made the following changes to my code:

    coordinator code:

    #include
    #include
    LiquidCrystal lcd(12,11,10,5,4,3,2);
    XBee xbee = XBee();
    void setup()
    {
    Serial.begin(9600);
    Serial3.begin(9600);
    // now that they are started, hook the XBee into
    // Software Serial
    xbee.setSerial(Serial3);
    lcd.setCursor(0,0);
    }
    void loop()
    {
    uint8_t data[] = {'H','I'};
    XBeeAddress64 addr64 = XBeeAddress64();
    XBeeAddress64 addr164 = XBeeAddress64();
    addr64.setMsb(0x0000);//XXXXX -> Msb address of router/end node
    addr64.setLsb(0x00FFFF);//XXXXX -> Lsb address of router/end node
    ZBTxRequest zbTx = ZBTxRequest(addr64, data, sizeof(data));
    xbee.send(zbTx);
    delay(100);

    }

    router code:

    #include
    #include
    LiquidCrystal lcd(12,11,10,5,4,3,2);
    XBee xbee = XBee();
    XBeeResponse response = XBeeResponse();
    ZBRxResponse rx = ZBRxResponse();
    void setup()
    {
    Serial.begin(9600);
    Serial3.begin(9600);
    xbee.setSerial(Serial3);
    lcd.setCursor(0,0);
    }
    void loop() {
    String sample;
    xbee.readPacket();
    if (xbee.getResponse().isAvailable()) {
    Serial.println(xbee.getResponse().getApiId());
    if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE)
    {
    xbee.getResponse().getZBRxResponse(rx);
    for (int i = 0; i < rx.getDataLength(); i++)
    {
    sample += (char)rx.getData(i);
    }
    Serial.println(sample);
    lcd.print(sample);
    }
    }
    else if (xbee.getResponse().isError()) {
    Serial.println("Error reading packet. Error code: ");
    Serial.println(xbee.getResponse().getErrorCode());
    }
    delay(100);
    }


    but still router is not receiving the message. What may be the mistake?

    ReplyDelete
    Replies
    1. I don't see anything wrong from the example you sent. So, let's try splitting it up. Put the router XBee in a USB adapter (like you're programming it) and watch it with XCTU. Turn the coordinator on and watch what you get in XCTU.

      If you get nothing, then your not sending so put some print statements in the coordinator code to make sure you're sending what you expect to the address you expect.

      For a test like this I would change the DH and DL to broadcast just to make sure you didn't copy the addresses wrong.

      The idea is to test each piece (router and coordinator) separately to try and isolate which end is giving trouble.

      Delete
  40. sir, i tried the last idea you gave it to me. but there is no message displayed on the xctu terminal window.

    ReplyDelete
    Replies
    1. I just got your email. Look for my response.

      Delete
  41. Hello, I tried your code and it works! Yeyy However I wanna try to use the unicast mode of transmission. The question is lets say Router 1 Wants to send a unicast data to a router 2 such that router 2 would only listen and obtain the data from router 1 avoiding all the broadcast messages and router 2 to forward the received data from router 1 to the Coordinator node. In other words how do I successfully implement a hop towards the coordinator node?

    ReplyDelete
    Replies
    1. As I understand it, you can't do that with the XBee. These little things route themselves and allow for devices to enter and leave the network. You can do it if you put a processor in the mix and eliminate what you don't want. You can also set up a specific route using the API and control the exact path to the coordinator. That's in the user manual, and is complicated, but can be done. I tried it ONCE, and it worked, but didn't allow for failure in any of the node, so I didn't bother going forward with that idea.

      Now, if I'm misunderstanding what you want to do, keep in mind that the devices will automatically route traffic for you with the exception of the broadcast message. That goes everywhere, so limit those if you're using little processors to take the messages apart.

      Delete
    2. I see so its a little bit complicated. I guess i just have to use the unicast mode of transmission. So the thing is I have 5 router nodes and a single coordinator node. Each node just sends a data to the coordinator node. Is unicast possible such that i can do it where all the 4 nodes directly report to the coordinator and the other one node implements a single hop towards the coordinator? If so, how can i acheive this and what are the configurations in XCTU needed for a unicast mode and adjustments to the code? Your reply is really appreciated! Thank you so muchh

      Delete
    3. It's been too long since I did that I don't remember the details well enough to give you too many specifics. I send most things to an XBee that is not the coordinator so the computer attached to it can process the data. The coordinator is an XBee attached to an Arduino that is only responsible for the network (which it does all by itself with no special configuration at all) and the Arduino gets the time from a GPS receiver and broadcasts it to the entire network to keep things in sync.

      I do remember that I set up a route using AT commands that I found in the user manual for the XBee, so you can start looking there. You can check the paths using XCTU, it will show you a picture of the XBee connections.

      One easy way to do it is to move one of the XBees far enough away so it HAS to jump through an intermediate router to get to the coordinator. Actually, you don't have to send and receive from the coordinator, it's just responsible for network coordination and joining. Once joined, two XBee routers can talk to each other just fine. I know because I had a coordinator die (bad power supply) and didn't even find out for more than a week.

      Sorry I can't be more help, but it's been too long since I did that experiment.

      Delete