Posts Tagged ‘XBee’

Tweetbot … the code

You can now find the code of the twitter robot on my github at: https://github.com/pchretien/tweetbot Feel free to fork … copying is not stealing! :)

Twitter Controlled Robot

I presented this project at the 28th Montréal Python meeting. I posted the slides of the presentation in my previous post here.

The objective of this project was to demonstrate the use of  pyserial and XBee to wirelessly control a robot. This project was also my first attempt at using the Tweepy library. The requirements for the project were the following:

  1. The communication with he robot must be wireless
  2. The connection to the Twitter website is made by a separate computer using the Python library Tweepy
  3. The robot should move according to the messages it receives
  4. In addition to the movement, the robot should have a servo that indicate its direction
Tweeter Controlled Robot

Tweeter Controlled Robot

The code running in the Arduino is a very simple program. The micro-controller read on the serial port to get a char command. The commands are text integers. The robot moves according to the command it receives. You can find the code to drive the robot in my previous post Arduino Motor Controller Using an L293D Chip. The following loop() function of the Arduino program receives commands from a computer trough the serial port. Depending on the nature of the command, the robot will perform different actions.

void loop()
{
  if ( Serial.available())
  {
    char ch = Serial.read();
    switch(ch)
    {
      case '1': // forward
        servo.write(90);
        forward();
        delay(RUN_DELAY);
        stop();
        break;
      case '2': // backward
        servo.write(90);
        backward();
        delay(RUN_DELAY);
        stop();
        break;
      case '3': // right
        servo.write(180);
        right();
        delay(TURN_DELAY);
        forward();
        delay(RUN_DELAY);
        stop();
        break;

        //...
    }
  }
}
Twitter Robot

Twitter Robot

On the computer we are running a Python that connects to Twitter.com, read it’s messages and send commands to the robot that are related to the content of the messages.

import tweepy
import time
import serial

consumer_key=""
consumer_secret=""
access_token=""
access_token_secret=""

ser = serial.Serial('COM8', 19200, timeout=0)

# Initialize the tweepy API
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

api.update_status('Start listening at ' + time.strftime("%Y-%m-%d %H:%M:%S"))
print "Start listening at " + time.strftime("%Y-%m-%d %H:%M:%S")
print

# This is where we should send the command to the robot ...
def process_text(author, text):
  print author
  print text
  print

  if text.lower().find("cmd1") > -1:
    ser.write('1')

  if text.lower().find("cmd2") > -1:
    ser.write('2')

  if text.find("#mpr-bye") > -1:
    quit = True

quit = False
lastStatusProcessed = None
lastMessageProcessed = None

while True:
  for status in tweepy.Cursor(api.friends_timeline, since_id=lastStatusProcessed).items(20):

    if lastStatusProcessed is None:
      lastStatusProcessed = status.id
      break

    if status.id > lastStatusProcessed:
      lastStatusProcessed = status.id

    process_text(status.author, status.text)

  for msg in tweepy.Cursor(api.direct_messages, since_id=lastMessageProcessed).items(20):
    if lastMessageProcessed is None:
      lastMessageProcessed = msg.id
      break

    if msg.id > lastMessageProcessed:
      lastMessageProcessed = msg.id

    process_text(msg.sender.name, msg.text)

    if quit:
      break

  time.sleep(15)

api.update_status('Bye! ' + time.strftime("%Y-%m-%d %H:%M:%S"))
print "Bye!"

The Twitter anti-spam filter will block you to send twice the same tweet to someone. it is then difficult to use specific commands to control the robot since you can’t send it more than once.

The solution is to use common words as commands and to incorporate it into your tweets. That way you can send multiple variations of the same command simply by decorating the command with more text.

A video of the presentation should be available on my Youtube channel soon …

 

Wireless Arduino/XBee Game Controller

For this project, I keep the same controller as in the previous post but, instead of controlling a servo motor  through a second Arduino, I will use it as a game controller.

The game will be played on my desktop computer. Since I am not very good at writing games, I downloaded the PyGame library. This framework comes with tons of samples so I decided to hack one of these samples and replace the keyboard input with my controller. You move the tank left and right by turning the game controller in the vertical position. You can fire bombs by switching the controller horizontally.

PyGame example game aliens.py

PyGame example game aliens.py

The code and the circuit of the game controller are the exact same setup as in my previous post. What I’ll demonstrate here is how to implement a receiver in this Python game.

You will need to connect an XBee wireless module to your computer using a USB adapter board. This will create a new communication port, in our case COM8.

Arduino/XBee controller and XBee USB adapter

Arduino/XBee controller and XBee USB adapter

The idea is to replace the keyboard with the data coming from the controller through the serial port. To maintain compatibility with the original version, I decided to simply override the keyboard values with the wireless controller commands.

The first step is to load the proper modules and open a connection through the serial port. I will use two global variables to replace the keyboard commands: one for the firing command and the other for the tank direction.

#
# Serial port communication with the Arduino/XBee
#
import serial
import thread
arduinoFiring = 0
arduinoDirection = 0
ser = serial.Serial('COM8', 19200, timeout=0) # Change COM[number] for ttyUSB[number]

Once this is defined, we need to override the keyboard values. To replace the spacebar fire command, we override the value with:

  firing = keystate[K_SPACE]
  firing = arduinoFiring # <-- Override the keyboard with the game controller data

To replace the arrows direction commands, we are add the following lines:

  direction = keystate[K_RIGHT] - keystate[K_LEFT]
  direction = arduinoDirection # <-- Override the keyboard with the game controller value

Finally, we have to feed these two values with the data received from the game controller. The best way to do this is by starting a new thread to listen on the serial port, read incoming data and convert it to game usable values.

def processArduino(buffer):
	global arduinoFiring
	global arduinoDirection

	if len(buffer) == 0:
		return
	if buffer[0] != '<':
 		return
 	if buffer[len(buffer)-1] != '>':
		return

	tokens = buffer[1:len(buffer)-1].split(':')
	if len(tokens) < 4:
 		return
 	for i in range(4):
 		if len(tokens[i]) == 0:
 			return
	#print(buffer)
 	c = int(tokens[0])
 	x = int(tokens[1])
 	y = int(tokens[2])
 	z = int(tokens[3])
 	if y > 550:
		arduinoDirection = 1
	elif y < 450:
 		arduinoDirection = -1
 	else:
 		arduinoDirection = 0
 	if z > 575:
		arduinoFiring = 1
	else:
		arduinoFiring = 0

def readArduino():
	buffer = ''
	while 1:
		b = ser.read()
		while b:
			if b == '<':
 				buffer = ''
 			buffer += b
 			if b == '>':
				processArduino(buffer)
			b = ser.read();

def main(winstyle = 0):
    ...
    thread.start_new_thread(readArduino, ())

We have two functions here. The readArduino() function is the thread entry point that contains the code reading on the serial port. A buffer is built of bytes received from the game controller. When the ‘<’ character is read, the buffer is cleared to receive a new command. When the character ‘>’ is received, the command stored in the buffer is processed.

The data is processed in the  function processArduino(buffer). The data buffer is received as a parameter. The function reads the three axis and the compass values. Then, it determines if the direction is -1, 0 or 1 and if the tank fires a bomb. The values of the axis range from 400 to 600. The constants used in the function to determine the position of the controller can be adjusted to match your game requirements.

 

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, Netduino Plus and XBee Radio

I just received two XBee wireless modems with an Arduino shield and an USB adapter board. I bought all these parts from Sparkfun.com. I followed the instructions from the Lady Ada website to configure both modems so they can talk to each other.

Arduino, Netduino Plus and XBee modems

Arduino, Netduino Plus and XBee modems

Once I finished soldering the XBee shield stackable headers I tried the simple “serial echo sample” from the Sparkfun website. I modified it to turn a LED on and off depending on the data received.

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

void loop() {
  if (Serial.available()) {
    char c = (char) Serial.read();
    if(c == 'h')
      digitalWrite(13,HIGH);
    if(c == 'l')
      digitalWrite(13,LOW);
    Serial.print(c);
    delay(10);
  }
}

I connected an XBee board to the USB adapter connected to my computer and the other on the Arduino mocro-controller powered by a 9V battery. No mater where I hided the Arduino board in my house, the communication between both XBee modems was perfect.

I then decided to give it a try using my new Netduino Plus. I replicated the exact same behavior as on the Arduino to compare both platforms. It took me less then 30 minutes to port the code to the Netduino Plus.

using System;
using System.Text;
using System.IO.Ports;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;

namespace NetduinoPlusXbeeEcho
{
    public class Program
    {
        private static bool pin13Value;
        private static OutputPort pin13 = new OutputPort(Pins.GPIO_PIN_D13, false);

        public static void Main()
        {
            byte[] buffer = new byte[32];

            SerialPort port = new SerialPort("COM1", 19200);
            port.ReadTimeout = 0;
            port.Open();

            while(true)
            {
                int count = port.Read(buffer, 0, buffer.Length);
                if(count > 0)
                {
                    char[] chars = Encoding.UTF8.GetChars(buffer);
                    if (chars[0] == 'h')
                        pin13Value = true;
                    if (chars[0] == 'l')
                        pin13Value = false;

                    pin13.Write(pin13Value);
                    port.Write(buffer, 0, count);
                }
            }
        }
    }
}

The code is a bit longer but it has more to do with the structure of the program than the complexity of the code. The Netduino Plus has a direct advantage over the Arduino because it can connect to the net through its Ethernet port.