Xbee network test

From emboxit
Jump to: navigation, search

Network

  • Already Tested and can be demonstrated: The self creating network and the range extension using intermediate nodes


Network1.PNG The first node network, implemented with XBee modules

  • This is a ZigBee STAR network with one Coordinator and 5 Router-nodes
  • Based on Simple_Actuator_Network page 170 of Robert Faludi book
  • Distances beetween nodes are 30 steps ~20 meters
  • Nodes are always ON
  • ZigBee protocol does not support sleeping Routers, only sleeping END nodes.
  • The ZigBee network is self creating so a sleeping node can enter the network any time it wakes-up
  • Already Tested and can be demonstrated: The self creating network and the range extension using intermediate nodes


Nodes

Nodes.png

Node2.png Green Led indicates communication. A node needs 5 seconds to enter the network. With duty cycle 1/600 the 5 seconds lead to 25 minutes frame !!!

  • XBee module used is XB24-Z7CIT-004 revG
series2
series XBeeZB
ZigBee

XCTUCORDINATOR.PNG XCTUROUTER.PNG XCTUATAP2.PNG


Coordinator Configuration with X-CTU

ZigBee Coordinator API
PANID = 2011
Serial Interface API enable mode 2 (ATAP = 2)
WRITE
After WRITE above, the XBee module has changed the way it communicates via the serial port.
In order X-CTU to be able to communicate correctly via the serial port, at [PC Settings TAB] click check-boxes:
Enable API
Use Escape characters (ATAP=2)


Routers Configuration with Terminal

ATID 2011           PANID = 2011
ATDH 0              Address of Coordinator is set to 0
ATDL 0
ATJV 1              Router attempts to rejoin the coordinator at startup
ATD04               Set pin 0 as Digital Output
ATWR                Store configuration


Coordinator Configuration file, saved from X-CTU as COORDINATOR_API.pro

XB24-ZB_218C.mxi
80
0
251
218C
0
[A]ID=2011
[A]SC=FFFF
[A]SD=3
[A]ZS=0
[A]NJ=FF
[A]DH=0
[A]DL=0
[A]NI= 
[A]NH=1E
[A]BH=0
[A]AR=FF
[A]DD=30000
[A]NT=3C
[A]NO=0
[A]PL=4
[A]PM=1
[A]EE=0
[A]EO=0
[A]BD=3
[A]NB=0
[A]SB=0
[A]D7=1
[A]D6=0
[A]AP=2
[A]AO=0
[A]SP=20
[A]SN=1
[A]D0=1
[A]D1=0
[A]D2=0
[A]D3=0
[A]D4=0
[A]D5=1
[A]P0=1
[A]P1=0
[A]P2=0
[A]PR=1FFF
[A]LT=0
[A]RP=28
[A]IR=0
[A]IC=0
[A]V+=0


Router Configuration file, saved from X-CTU as ROUTER.pro

XB24-ZB_228C.mxi
80
0
251
228C
0
[A]ID=2011
[A]SC=FFFF
[A]SD=3
[A]ZS=0
[A]NJ=FF
[A]NW=0
[A]JV=1
[A]JN=0
[A]DH=0
[A]DL=0
[A]NI= 
[A]NH=1E
[A]BH=0
[A]AR=FF
[A]DD=30000
[A]NT=3C
[A]NO=0
[A]SE=E8
[A]DE=E8
[A]CI=11
[A]PL=4
[A]PM=1
[A]EE=0
[A]EO=0
[A]BD=3
[A]NB=0
[A]SB=0
[A]RO=3
[A]D7=1
[A]D6=0
[A]CT=64
[A]GT=3E8
[A]CC=2B
[A]SM=0
[A]SN=1
[A]SO=0
[A]SP=20
[A]ST=1388
[A]D0=4
[A]D1=0
[A]D2=0
[A]D3=0
[A]D4=0
[A]D5=1
[A]P0=1
[A]P1=0
[A]P2=0
[A]PR=1FFF
[A]LT=0
[A]RP=28
[A]IR=0
[A]IC=0
[A]V+=0




PC Software


SAN 1.PNG 2 active nodes
SAN 2.PNG 5 active nodes
SAN 3.PNG Switches can be changed only if nodes can communicate and give feedback


/*
 * Draws a set of switches for managing XBee Actuators
 * by Rob Faludi http://faludi.com
 */
// used for communication via xbee api
import processing.serial.*; 

// xbee api libraries available at http://code.google.com/p/xbee-api/
// Download the zip file, extract it, and copy the xbee-api jar file 
// and the log4j.jar file (located in the lib folder) inside a "code" 
// folder under this Processing sketch’s folder (save this sketch, then 
// click the Sketch menu and choose Show Sketch Folder).
import com.rapplogic.xbee.api.XBee;
import com.rapplogic.xbee.api.XBeeAddress64;
import com.rapplogic.xbee.api.XBeeException;
import com.rapplogic.xbee.api.XBeeTimeoutException;
import com.rapplogic.xbee.api.zigbee.ZNetRemoteAtRequest;
import com.rapplogic.xbee.api.zigbee.ZNetRemoteAtResponse;

import com.rapplogic.xbee.api.ApiId;
import com.rapplogic.xbee.api.AtCommand;
import com.rapplogic.xbee.api.AtCommandResponse;
import com.rapplogic.xbee.api.XBeeResponse;
import com.rapplogic.xbee.api.zigbee.NodeDiscover;

String version = "1.02";

// *** REPLACE WITH THE SERIAL PORT (COM PORT) FOR YOUR LOCAL XBEE ***
String mySerialPort = "COM1";

// create and initialize a new xbee object
XBee xbee = new XBee();

int error=0;

// make an array list of thermometer objects for display
ArrayList switches = new ArrayList();
ArrayList nodes = new ArrayList();

// create a font for display
PFont font;
float lastNodeDiscovery;


void setup() {

  size(800, 230); // screen size
  smooth(); // anti-aliasing for graphic display

  // You’ll need to generate a font before you can run this sketch.
  // Click the Tools menu and choose Create Font. Click Sans Serif,
  // choose a size of 10, and click OK.
  font =  loadFont("SansSerif-10.vlw");
  textFont(font);

  // The log4j.properties file is required by the xbee api library, and 
  // needs to be in your data folder. You can find this file in the xbee
  // api library you downloaded earlier
  PropertyConfigurator.configure(dataPath("")+"log4j.properties");

  // Print a list in case the selected serial port doesn't work out
  println("Available serial ports:");
  println(Serial.list());
  try {
    // opens your serial port defined above, at 9600 baud
    xbee.open(mySerialPort, 9600);
  }
  catch (XBeeException e) {
    println("");
    println("  ** Error opening XBee port: " + e + " **");
    println("");
    println("Is your XBee plugged in to your computer?");
    println("Did you set your COM port in the code near line 30?");
    error=1;
  }

  // run a node discovery to find all the radios currently on the network
  //  (this assumes that all the network radios are Actuator nodes)
  nodeDiscovery();
  lastNodeDiscovery = millis(); // note the time when the discovery was made
}


// draw loop executes continuously
void draw() {

  background(255); // draw a white background

  // report any serial port problems in the main window
  if (error == 1) {
    fill(0);
    text("** Error opening XBee port: **\n"+
      "Is your XBee plugged in to your computer?\n" +
      "Did you set your COM port in the code near line 27?", 
      width/3, height/2);
  }

  // create a switch object for each node that doesn't have one yet
  // ...and get current state of every new node
  for (int j=0; j < nodes.size(); j++) {
    XBeeAddress64 address64 = ((NodeDiscover) nodes.get(j)).getNodeAddress64();
    int i = 0;
    boolean foundIt = false;
    for (i=0; i < switches.size(); i++) {
      if  ( ((Switch) switches.get(i)).addr64.equals(address64) ) {
        foundIt = true;
        break;
      }
    }

    // if the switch does not yet exist, create a new one
    // stop if there's more than can fit on the screen
    if (foundIt == false && switches.size() < 5) { 
      switches.add(new Switch(address64, (switches.size())));
      ((Switch) switches.get(i)).getState();
    }
  }


  // draw the switches on the screen
  for (int i =0; i<switches.size(); i++) {
    ((Switch) switches.get(i)).render();
  }


  // periodic node re-discovery
  if (millis() - lastNodeDiscovery > 15 * 60 * 1000) { // every 15 minutes
    nodeDiscovery();
    lastNodeDiscovery = millis();
  }
} // end of draw loop




// function to look up all the nodes on the network 
// and add them to an ArrayList
void nodeDiscovery() {

  long nodeDiscoveryTimeout = 6000;
  nodes.clear(); // reset node list, removing all old records
  switches.clear(); // reset switch list, removing all old records
  print ("cleared node list, looking up nodes...");

  try {
    println("sending node discover command");

    // send the node discover command:
    xbee.sendAsynchronous(new AtCommand("ND")); 
    long startTime = millis();

    //spend some time waiting for replies:
    while (millis() - startTime < nodeDiscoveryTimeout) {       
      try {
        // look for incoming responses:
        XBeeResponse response = (XBeeResponse) xbee.getResponse(1000); 

        // check to make sure it's a response to an AT command
        if ( response.getApiId() == ApiId.AT_RESPONSE) {
          // parse the node information from the response:
          NodeDiscover node = NodeDiscover.parse((AtCommandResponse)response);
          nodes.add(node); // add the node to an existing Array List
          println("node discover response is: " + node);
        } 
        else {
          // println("ignoring unexpected response: " + response);
        }
      }
      catch (XBeeTimeoutException e) {
        print("."); // prints dots while radio lookups are in progress
      }
    }
  }   
  // if the ND response times out, note the error
  catch (XBeeTimeoutException e) {
    println("request timed out. make sure your " + 
            "remote XBee is configured and powered on");
  } 
  // if some other error happens, print it to the status window
  catch (Exception e) {
    println("unexpected error" + e);
  }
  println("Node Discovery Complete");
  println("number of nodes: " + nodes.size());
}



// this function runs once every time the mouse is pressed
void mousePressed() {
  // check every switch object on the screen to see 
  // if the mouse press was within its borders
  // and toggle the state if it was (turn it on or off)
  for (int i=0; i < switches.size(); i++) {
    ((Switch) switches.get(i)).toggleState();
  }
}



// defines the switch objects and their behaviors
class Switch {

  int switchNumber, posX, posY;
  boolean state = false; // current switch state
  XBeeAddress64 addr64;  // stores the raw address locally
  String address;        // stores the formatted address locally
  PImage on, off;        // stores the pictures of the on and off switches


  // initialize switch object:
  Switch(XBeeAddress64 _addr64, int _switchNumber) { 
    on = loadImage("on.jpg");
    off = loadImage("off.jpg");
    addr64 = _addr64;
    switchNumber = _switchNumber;
    posX = switchNumber * (on.width+ 40) + 40;
    posY = 50;

    // parse the address int array into a formatted string
    String[] hexAddress = new String[addr64.getAddress().length];
    for (int i=0; i<addr64.getAddress().length;i++) {
      // format each address byte with leading zeros:
      hexAddress[i] = String.format("%02x", addr64.getAddress()[i]); 
    }
    // join the array together with colons for readability:
    address = join(hexAddress, ":"); 

    println("Sender address: " + address);
  }

  void render() { // draw switch on screen
    noStroke(); // remove shape edges
    if(state) image(on, posX, posY); // if the switch is on, draw the on image
    else image(off, posX, posY);     // otherwise if the switch is off, 
                                     // draw the off image
    // show text
    textAlign(CENTER);
    fill(0);
    textSize(10);
    // show actuator address
    text(address, posX+on.width/2, posY + on.height + 10);
    // show on/off state
    String stateText = "OFF";
    fill (255,0,0);
    if (state) {
      stateText = "ON";
      fill(0,127,0);
    }
    text(stateText, posX + on.width/2, posY-8);
  }

  // checks the remote actuator node to see if its on or off currently
  void getState() {
    try {
      println("node to query: " + addr64);

      // query actuator device (pin 20) D0 (Digital output high = 5, low = 4)
      // ask for the state of the D0 pin: 
      ZNetRemoteAtRequest request=  new ZNetRemoteAtRequest(addr64, "D0"); 

      // parse the response with a 10s timeout 
      ZNetRemoteAtResponse response = (ZNetRemoteAtResponse)
        xbee.sendSynchronous(request, 10000); 

      if (response.isOk()) {

        // get the state of the actuator from the response
        int[] responseArray = response.getValue();
        int responseInt = (int) (responseArray[0]);

        // if the response is good then store the on/off state: 
        if(responseInt == 4|| responseInt == 5) { 
          // state of pin is 4 for off and 5 for on:
          state = boolean( responseInt - 4);  
          println("successfully got state " + state + " for pin 20 (D0)");
        }
        else {	
          // if the current state is unsupported (like an analog input)
          // then print an error to the console
          println("unsupported setting " + responseInt + " on pin 20 (D0)");
        }
      } 
      // if there's an error in the response, print that to the 
      // console and throw an exception
      else {
        throw new RuntimeException("failed to get state for pin 20. " +
                                   " status is " + response.getStatus());
      }
    } 
    // print an error if there's a timeout waiting for the response
    catch (XBeeTimeoutException e) {
      println("XBee request timed out. Check remote's configuaration, " +
              " range and power");
    } 
    // print an error message for any other errors the occur
    catch (Exception e) {
      println("unexpected error: " + e + "  Error text: " + e.getMessage());
    }
  }

  // this function is called to check for a mouse click
  // on the switch object, and toggle the switch accordingly
  // it is called by the MousePressed() function so we already
  // know that the user just clicked the mouse somewhere
  void toggleState() {

    // check to see if the user clicked the mouse on this particular switch
    if(mouseX >=posX && mouseY >= posY && 
       mouseX <=posX+on.width && mouseY <= posY+on.height) 
    {
      println("clicked on " + address);
      state = !state; // change the state of the switch if it was clicked

      try {
        // turn the actuator on or off (pin 20) 
        // D0 (Digital output high = 5, low = 4) 
        int[] command = {
          4
        }; // start with the off command
        if (state) command[0]=5; // change to the on command 
                                 // if the current state is on
        else command[0]=4; // otherwise set the state to off

        ZNetRemoteAtRequest request = 
          new ZNetRemoteAtRequest(addr64, "D0", command);
        ZNetRemoteAtResponse response = 
          (ZNetRemoteAtResponse) xbee.sendSynchronous(request, 10000);

        // if everything worked, print a message to the console
        if (response.isOk()) {
          println("toggled pin 20 (D0) on node " + address);
        } 
        // if there was a problem, throw an exception
        else {
          throw new RuntimeException(
            "failed to toggle pin 20.  status is " + response.getStatus());
        }
      } 
      // if the request timed out, print
      // that error to the console and 
      // change the state back to what 
      // it was originally
      catch (XBeeTimeoutException e) {
        println("XBee request timed out. Check remote's " +
                 "configuaration, range and power");
        state = !state;
      } 
      // if some other error occured, print that 
      // to the console and change the state back
      //  to what it was originally
      catch (Exception e) {
        println("unexpected error: " + e + 
                "  Error text: " + e.getMessage());
        state = !state;
      }
    }
  }
} //end of switch class




Conclusions

  • In tested network nodes are always ON
  • Using Zigbee XBee modules, ArduinoFIO can put node in sleeping mode and wake it up at predefined rendezvous time
PC software must keep rendezvous-table for all nodes and inform all nodes via Coordinator when to wake-up
This is a way to create sleeping network without support from the XBee module firmware
Disadvantage is that the active time will be in the range of 1 second so the frame period should be in the range of 5 minutes
Measured time for node to enter to the Zigbee network is 5 sec leading to a frame period of 25 minutes. This is too much for our application
A node with sleep-support-firmware could have some milli-seconds active time and frame period in the range of some seconds
  • An XBee sleeping network can be implemented only with Digimesh-XBee-Modules at the same cost per module with ZigBee-XBee-Modules
  • XBee series2 modules chipset (EMBER E250) is not supported by any open source WSN OS



TODO

  • Check how to decrease the time for a node to enter the ZigBee network