The power of Arduino and Zigbee

Today i had some spare time to combine a few of the things i’ve been working on lately:

  • My Zigbee API;
  • Arduino;
  • Pan & Tilt mechanism

I wanted to create a small executable that would enable me to control the position of the 2 servo’s.

XBee module

I started with programming the XBee: Zigbee End Device AT firmware, the right PAN, Node Identifier ED5 (as in End Device 5), Sleep Mode=1 (Pin Hibernate). I put the module on a breadboard by use of a Breakout Board. Grounded pin 9 and used the 3.3V output of the Arduino to power the module.

Arduino

I strapped the Arduino Duemilanove to the same breadboard and wired the 2 servo’s. Pins 9 and 10 of the Arduino are used as PWM output for the 2 servo’s. Arduino pins 2 & 3 were connected to the DIN and DOUT pins of the XBee module.

Sketch

Now it was time to write a sketch that would receive commands from the XBee and move the servo’s accordingly. The sketch is a real quick and dirty one, low on error handling and validation. I made up a small ‘protocol’: commands have to end with the exclamation mark (“!”) and can be either 1 or 2 characters long.

P+! would Pan right 3 degrees, P-! would Pan left 3 degrees, T+! would Tilt up 3 degrees and so on. H! is the command to go back to the Home position. Of course you can extend this as much as you like, e.g. add absolute positioning, presets, you name it.

This is the sketch:

#include <NewSoftSerial.h>
#include <ServoTimer1.h>
#include <PString.h>

ServoTimer1 PanServo;
ServoTimer1 TiltServo;

int PanAngle = 90;
int TiltAngle = 90;
byte DeltaPan = 3;         // move 3 degrees
byte DeltaTilt = 3;        // move 3 degrees
char cbuffer[40] = "";     // receive buffer
NewSoftSerial XBSerial = NewSoftSerial(2, 3);
PString buffer(cbuffer, sizeof(cbuffer));

void setup() {

  XBSerial.begin(9600);         // set up XBee at 9600 bps
  delay(10000);                 // wait 10 sec. for possible joining

  PanServo.attach(9);
  TiltServo.attach(10);

  PanServo.write(PanAngle);
  TiltServo.write(TiltAngle);
}

void waitforcommand()
{
  while (true)
  {
    if (XBSerial.available())
    {
      int c = XBSerial.read();
      if (c == 0x21)     // command terminator = "!"
      {
        break;
      }
      else
      {
        // add to buffer
        buffer.print(c,BYTE);
      };
    };
  };
}

void loop() {

  buffer="";
  waitforcommand();

  // what's the first character?
  switch (buffer[0])
  {
    case 0x50:             // P for Pan
      {
        // what's the next character?
        switch (buffer[1])
        {
          case 0x2B:       // +
            PanAngle += DeltaPan;
            break;

          case 0x2D:       // -
            PanAngle -= DeltaPan;
            break;
          };
          break;
      };
    case 0x54:            // T for Tilt
      {
        // what's the next character?
        switch (buffer[1])
        {
          case 0x2B:       // +
            TiltAngle += DeltaTilt;
            break;

          case 0x2D:       // -
            TiltAngle -= DeltaTilt;
            break;
          };
          break;
      };
    case 0x48:            // H for Home
      {
        PanAngle=90;
        TiltAngle=90;
        break;
      };

  };

  // check boundaries for Pan
  PanAngle=(PanAngle < 0)?0:PanAngle;
  PanAngle=(PanAngle > 180)?180:PanAngle;

  // check boundaries for Tilt
  TiltAngle=(TiltAngle < 90)?90:TiltAngle;
  TiltAngle=(TiltAngle > 180)?180:TiltAngle;

  // Set dervo's accordingly
  PanServo.write(PanAngle);
  TiltServo.write(TiltAngle);

}

PC software

Next item was a small program that would use the API to address the XBee module.

XBee servo control

XBee servo control

4  buttons for Left, Rigth, Up and Down, a Home button and a button to connect to the Zigbee network. Not very spectacular, I’d say.

There are 2 important API functions that are used to communicate with the Zigbee module:

  • Node Discovery
  • XBee Transmit Request.

The code that is executed when the “Connect” button is pressed, sends out a Node Discovery command. This will trigger all joined Zigbee modules to respond with information about themselves, like 16- and 64-bit address, node identifier and some more interesting stuff. The code goes something like this:

  XB:=TXBEE.Create(14,9600);
  XB.Open;
  gXBeeModules.Clear;
  cmd:=TXBee_NodeDiscover.Create('');
  XB.SendPacket(cmd.GetPacket);

The Node Identifier is used to see if the Zigbee module that is connected to the Arduino, is “in the air”. Cause it doesn’t have to be, it could be disconnected from power or whatever…

When the Zigbee module with Node Identifier “”ED5” has responded, the 5 buttons are enabled and clicking them will move the servo’s. This is done with the XBee Transmit Request function; a string is being sent to the XBee and the XBee will take care of transferring it out on the UART.  Below the code for the “Home” button:

i:=gXBeeModules.Indexof('ED5');
if i >=0
then begin
Module := TXBeeModule(gXBeeModules.Objects[i]);
Addr16:= Module.Addr16 ;
Addr64:= Module.Addr64 ;
TR:=TXBeeTransmitRequest.Create(1,Addr16,Addr64,"H!");
X.SendPacket(TR.GetPacket);
end;

Et voila, the servo’s start moving!

To see how (good or bad) it works, i’ve made a small video.
The power of Arduino and Zigbee!!!

Tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *