Wireless Arduino/XBee Remote Control with Compass and Accelerometer

A few weeks ago we played with XBee wireless devices. Last week we played with accelerometers and compass. This week we will put it all together in a custom remote control. Our first project will be to remotely control a servo motor by using two Arduinos and two XBee modules.

The remote control (transmitter) should be straight forward to build using our last project and replacing the USB interface with the XBee module.

The wireless servo controller (receiver) on the other hand needs to be built from scratch. We will connect an XBee shield and a servo motor to an Arduino board. The Arduino receives the commands from the serial port and sets the servo position accordingly.

Remote Control (ransmitter)

Arduino/XBee remote control with accelerometer and compass

Arduino/XBee remote control with accelerometer and compass

Let’s start with the transmitter. Instead of using a simplified Arduino board as in our previous articles, we will be using a standard Arduino board, an XBee shield and a Proto Shield all stacked together. The prototyping board is used to make the circuit for the accelerometer and the compass sensors.

Both sensors are powered with 3.3v from the Arduino. The accelerometer X, Y and Z axis are respectively connected to the Arduino analog pins #0, #1 and #2. The compass SDA and SCL outputs for the IC2 protocol are connected to the Arduino analog pins #4 and #5.

The remote control is powered by a 6V NiMH rechargeable battery pack. The battery is connected to the Vin and Gnd beaders of the Arduino board.

Following is the program of the remote control used to read the sensors and send data to the receiver:

#include <Wire.h>

int x, y, z;
int pin13 = LOW;

int slaveAddress;
byte headingData[2];
int i, headingValue;
int HMC6352Address = 0x42;

void setup()
{
  Wire.begin();
  slaveAddress = HMC6352Address >> 1;  

  pinMode(13, OUTPUT);
  Serial.begin(19200);
}
void loop()
{
  // Send a "A" command to the HMC6352
  Wire.beginTransmission(slaveAddress);
  Wire.send("A");  // The "Get Data" command
  Wire.endTransmission();
  delay(10);

  i = 0;
  Wire.requestFrom(slaveAddress, 2);        // Request the 2 byte heading (MSB comes first)
  while(Wire.available() && i < 2)
  {
    headingData[i] = Wire.receive();
    i++;
  }

  headingValue = headingData[0]*256 + headingData[1];

  Serial.print("<");
  Serial.print(int (headingValue / 10));
  Serial.print(":");      

  x = analogRead(0);
  y = analogRead(1);
  z = analogRead(2);
  Serial.print(x, DEC);
  Serial.print(":");
  Serial.print(y, DEC);
  Serial.print(":");
  Serial.print(z, DEC);
  Serial.print(">");

  delay(190);
}

Wireless Servo Controller (receiver)

Arduino/XBee wireless servo controller

Arduino/XBee wireless servo controller

To build the receiver you will need both an Arduino board and an XBee shield along with a servo motor. Connect the XBShield onto the Arduino board and the servo motor data wire to the Arduino pin #10. The pins #9, #10 and #11 of the Arduino are Pulse With Modulation (PWM) outputs. A pulse can be sent to these outputs to control a servo motor.

I have used a 9V battery to power the receiver but I would strongly recommend a rechargeable battery pack. The 9V battery will not last a long time driving the servo motor.

Following is the code of the receiver:

#include <Servo.h>

#define BUFFER_MAX 24
#define CENTER_MIN 490
#define CENTER_MAX 510
#define MAX_MAX 590
#define MON_MIN 410

Servo servoA;

byte counter = 0;
char buffer[BUFFER_MAX];

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(19200);
  servoA.attach(10);
}

void loop() {
  if (Serial.available()) {
    char c = (char) Serial.read();
    if(c == '<')
    {
      digitalWrite(13,HIGH);
      counter = 0;
      memset( buffer, 0, BUFFER_MAX);
    }
    else if(c == '>')
    {
      digitalWrite(13,LOW);
      processMessage();
    }
    else
    {
      if(counter == BUFFER_MAX)
        counter = 0;

      buffer[counter++] = c;
    }    

    delay(10);
  }
}

void processMessage()
{
//  Serial.println(buffer);
//  Serial.println(counter, DEC);

  int count = 0;
  int tokenCount = 0;
  char tokenValue[4];
  int tokenValues[4];
  for(int i=0; i<=counter; i++)
  {
    if(buffer[i] == ':' || i == counter)
    {
      tokenValues[tokenCount++] = atoi(tokenValue);
      count = 0;
      memset(tokenValue, 0, 4);
    }
    else
    {
      tokenValue[count++] = buffer[i];
    }
  } 

  if( tokenValues[3] > MAX_MAX )
  {
    int servoValue = ((int)tokenValues[0]) - 180;
    if(servoValue < 0)
      servoValue *= -1;
    servoA.write(servoValue);
  }
  else
  {
    int angle = 90;
    if(tokenValues[2] < CENTER_MIN)
      angle = 180 - (tokenValues[2] - 400);
    if(tokenValues[2] > CENTER_MAX)
      angle = 600 - tokenValues[2];

    if(angle > 180)
      angle = 180;
    if(angle < 0)
      angle = 0;

    servoA.write(angle);
  }

}

XBee Configuration

To configure the XBShield you can refer to the ladyada website. First when using the XBShield, make sure to set the on-board switch to the right position at the right time. Then, when uploading a sketch to the board, place the switch on the DLINE position. And lastly, when using the XBee as serial port, set the switch to UART.

Tags: , , , , , , , ,

Post a Reply

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

Top