Posts Tagged ‘remote’

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.

Arduino and Infrared … (Part 3)

That post is due for a long time. I’ll continue with the infrared project and add control of X10 devices in your house. Don’t know what X10 is? Click here to learn more.

Arduino, IR and X10

Arduino, IR and X10

The code in this post is not much different than the code presented on part 2 of this series. In addition to controlling red, green and yellow LEDs, we will control your home appliances. To do so, you will need two new parts, the X10 transmitter and an X10 appliance receiver. Simply Google “X10 devices” to find stores selling these in your area.

You connect to the X10 transmitter using a standard telephone cable. Make sure you use a 4 wires cable. Many phones are sold with two wire cables. Keep one connector to connect to the transmitter and strip the wires on the other end to connect to your circuit.

Telephone cable

Telephone cable

In our example, the match between the colors of the telephone cable wires and the modem pin numbers is the following:

#1 => Black
#2 => Red
#3 => Green
#4 => Yellow=4

X10 Modem connector

X10 Modem connector

The complete circuit should be wired as following. The black wire (pin #1) should be connected to a pull-up 10K resistor and the red wire (pin #2) to the ground. The yellow wire (pin #4) must be connected to the output signal pin of the Arduino board. Finally, the green wire (pin #3) of the modem is not connected.

Arduino, IR and X1 Circuit

Arduino, IR and X1 Circuit

Additions to this project code are the calls to the X10 library. Following are the differences with the code of the previous project. You can download the complete project on my Github account: https://github.com/pchretien/ir_x10

#include <x10.h>
#include <x10constants.h>

...

#define ZC_PIN 2
#define DATA_PIN 3
#define X10_REPEAT 3

...

x10 myHouse = x10(ZC_PIN, DATA_PIN);

...

void setup()
{
  ...
  // X10 Controller
  myHouse.write(A, ALL_UNITS_OFF,3);
}

...

void loop()
{
    // POWER BUTTON 279939191
    // Toggle red LED and X10 device when POWER button command is received
    if( code == 279939191 && bit_position > 0)
    {
      myHouse.write(A, UNIT_1, X10_REPEAT);    

      red_led_state ^= 1;
      if(red_led_state)
      {
        myHouse.write(A, ON, X10_REPEAT);
        digitalWrite(RED_LED, HIGH);
      }
      else
      {
        myHouse.write(A, OFF, X10_REPEAT);
        digitalWrite(RED_LED, LOW);
      }
    }
}

...

You can download the X10 library at the following location:
http://www.arduino.cc/en/Tutorial/X10

Q-Steer Mazda RX-8 Tiny RC Car

L’année dernière j’ai acheté ce petit bolide téléguidé chez Think Geek … quelques semaine plus tard j’ai acheté une caméra vidéo. Le vidéo qui suit était inévitable!

Arduino and Infrared … (Part 2)

ir arduino

Arduino and infrared (IR) remotes (Part 2)

In the first article of the series, I explained how to break the code of a standard infrared remote control. In this article, we will use these results to control real world devices. The so called “real world devices” are, at this point of the project, three LEDs. I’ll keep lamps and washing machines control for the next article about X-10 control.

The first step is to convert the pulses we receive into streams of bits. The remote we will use for this project is an old air conditioning remote control. Following are the results for the remote control protocol:

  • Threshold start pulse duration: 4000 micro seconds
  • Threshold “1″ bit pulse duration: 1500 micro seconds
  • Threshold ”0″ bit pulse duration: 400 micro seconds
  • Threshold repeat pulse duration: 2000 micro seconds
  • Bit stream length: 32 bits

These values are used to build binary streams to reconstruct the 32 bit commands emitted by the remote control. Once the code values are known, we can add behavior in our micro controller. The command code is built using X-Or operations with the bits received from the remote.

The power-on/power-off command of our remote control match the decimal number 279939191. When the button is pressed, the red LED is toggled on/off. The green LED is turned off during the time the Arduino is processing a command. If a new command is sent while the green LED is off, the program wont be able to catch it. Finally, the yellow led is flashes ON for 50 milliseconds every time a repeat command is received.

Using this code you can control about anything you want using an infrared remote control. In the next article we will control lamps through X-10 power line protocol.

Philippe Chrétien

#define DEBUG 0

#define IR_LED 7
#define GREEN_LED 6
#define RED_LED 5
#define YELLOW_LED 4

#define MAX 128
#define MICRO_STEP 10

#define IDLE_PULSE 10000
#define START_PULSE 4000
#define REPEAT_PULSE 2000
#define ONE_PULSE 1500
#define ZERO_PULSE 400

unsigned long pulses[MAX];
unsigned long code = 0;
int red_led_state = 0;

void setup()
{
  pinMode(IR_LED, INPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  digitalWrite(YELLOW_LED, LOW);

  // For debug
  Serial.begin(115200);
}

void loop()
{
  // The IR receiver output is set HIGH until a signal comes in ...
  if( digitalRead(IR_LED) == LOW)
  {
    // No command can be received while the green LED is off
    digitalWrite(GREEN_LED, LOW);

    //Start receiving data ...
    int count = 0; // Number of pulses
    int exit = 0;
    while(!exit)
    {
      while( digitalRead(IR_LED) == LOW )
        delayMicroseconds(MICRO_STEP);

      // Store the time when the pulse begin
      unsigned long start = micros();
      int max_high = 0;
      while( digitalRead(IR_LED) == HIGH )
      {
        delayMicroseconds(MICRO_STEP);
        max_high += MICRO_STEP;
        if( max_high > IDLE_PULSE )
        {
          exit = 1;
          break;
        }
      }

      unsigned long duration = micros() - start;
      pulses[count++] = duration;
    }

    // Build code from pulses
    int repetitions = 0;
    int bit_position = 0;
    unsigned long bit = 2147483648; // 10000000000000000000000000000000 in binary
    unsigned long new_code = 0;
    for(int i=0; i<count; i++)
    {
      if(pulses[i] > IDLE_PULSE)
      {
        // Ignore very long pulses
        continue;
      }
      else if(pulses[i] > START_PULSE)
      {
        // Start pulse received ... start counting bits
        new_code = 0;
        bit_position = 0;
      }
      else if(pulses[i] > REPEAT_PULSE)
      {
        // Repetition command ... no bit pulses here.
        repetitions++;
      }
      else if(pulses[i] > ONE_PULSE)
      {
        // Receives "1"
        if(DEBUG)
          Serial.print("1");
        new_code |= bit >> bit_position++;
      }
      else if(pulses[i] > ZERO_PULSE)
      {
        // Receives "0"
        if(DEBUG)
          Serial.print("0");

        bit_position++;
      }
    }

    if( new_code )
    {
      // This was not a repeat command
      code = new_code;
    }

    // Display the code received and number of bits or, repetitions.
    if(DEBUG)
    {
      if( !new_code)
      {
        Serial.print("                                ");
      }

      Serial.print("     ");
      Serial.print(bit_position, DEC);
      Serial.print(" bits ");
      Serial.print(repetitions, DEC);
      Serial.print(" repetition(s) code = ");
      Serial.print(code, BIN);
      Serial.print(" (");
      Serial.print(code, DEC);
      Serial.print(")");
      Serial.println("");
    }

    // Flashes the yellow LED for every repeat commands
    if( repetitions > 0 )
    {
      for( int i=0; i<repetitions; i++)
      {
        digitalWrite(YELLOW_LED, HIGH);
        delay(50);
        digitalWrite(YELLOW_LED, LOW);
        delay(50);
      }
    }

    // Toggle red LED when power button command is received
    if( code == 279939191 && bit_position > 0)
    {
      red_led_state ^= 1;

      if(red_led_state)
        digitalWrite(RED_LED, HIGH);
      else
        digitalWrite(RED_LED, LOW);
    }

    // Ready to process an other command
    digitalWrite(GREEN_LED, HIGH);
  }
}