A4WD Sabertooth XBee Project

This post will attempt to explain my A4WD-1 Rover project. I bought my Rover w/o electronics and outfitted it with GHM-16 Gear Head Motors, TRC-01 Off Road Tires, BAT-06 12V Battery and DE-05 (Sabertooth 2x12 Motor Controller).

Wireless communication between the A4WD and my Gateway Notebook is via XBee Series 1 RF modules operating at 9600 baud. Line of sight range is about 300 feet.

Testing at this point has been limited to sending commands to control the wheel drive motors, including combination commands to achieve skid steering. I have Sharp Range Sensors, Motor Encoders and a Pan & Tilt Servo ready to become this project’s phase 2.

The remote XBee’s serial data out pin is connected directly to the Sabertooth’s S1 connection. The XBee is a 3.3V device. Since the Sabertooth is operating in one-way communications receive only mode, 3.3V is more than sufficient to be interpreted as High (TTL Serial). This XBee is plugged into a SparkFun Regulated board (WRL-09132) which uses the Sabertooth’s 5V output to supply 3.3V to the XBee.

The base XBee is plugged into a SparkFun Explorer USB board (WRL-08687). This board contains a USB to Serial adapter which creates a virtual com port on my Gateway Notebook, as well as 5V to 3.3V converter for the XBee.

C# was used to create a 20 button on-screen pad capable of sending the 4 byte packets necessary to the Sabertooth operating in Mode 4.

The code is simple and was intended to test most of the A4WD drive motions. Combining left and right commands achieves skid steering. Feel free to modify it in any way you choose.

The Sabertooth’s address is set to 0x82 (130), mode 4 packetized serial by turning dip switches 3, 4 and 6 on. For this application both XBee’s are programmed to factory default.

ISSUE #1: the Sabertooth Motor Controller keeps performing the same function until it receives a new command. Should XBee transmission go out of range, the A4WD will keep going wherever it was headed. The Sabertooth can use connection S2 as a kill switch, but this project will require more intelligence at the remote end to use it. Perhaps phase 2 should be a remote Arduino.

ISSUE #2: One of my early experiments was a X10 wireless camera mounted to the A4WD. However it soon became apparent 2.4ghz cameras interfere with XBee 802.15.4 commuications. Bluetooth devices also operate in the 2.4ghz band and would probably also have communication problems. I suspect the issue lies more with the low cost of a X10 camera.

20 button control pad code:

[code]using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace SerialPort
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

        serialPort1.PortName = "COM4";
        serialPort1.BaudRate = 9600;
        serialPort1.DataBits = 8;
        serialPort1.Parity = Parity.None;
        serialPort1.StopBits = StopBits.One;
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {           
        //left fwd stop
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x00, 0x02 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();

    }

    private void button2_Click(object sender, EventArgs e)
    {            
        //left fwd 1/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x20, 0x22 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button3_Click(object sender, EventArgs e)
    {
        //left fwd 1/2 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x40, 0x42 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button4_Click(object sender, EventArgs e)
    {
        //left fwd 3/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x60, 0x62 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button5_Click(object sender, EventArgs e)
    {
        //fwd full speed
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x7F, 0x01 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        //delay
        Thread.Sleep(100);
        byte] bytesToSend = new byte[4] { 0x82, 0x04, 0x7F, 0x05 };
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button6_Click(object sender, EventArgs e)
    {
        //left rev 1/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x01, 0x20, 0x23 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button7_Click(object sender, EventArgs e)
    {
        //left rev 1/2 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x01, 0x40, 0x43 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button8_Click(object sender, EventArgs e)
    {
        //left rev 3/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x01, 0x60, 0x63 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button9_Click(object sender, EventArgs e)
    {
        //left rev full speed
        byte] bytesToSend = new byte[4] { 0x82, 0x01, 0x7F, 0x02 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button10_Click(object sender, EventArgs e)
    {
        //left rev stop
        byte] bytesToSend = new byte[4] { 0x82, 0x01, 0x00, 0x03 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button20_Click(object sender, EventArgs e)
    {
        //right fwd stop
        byte] bytesToSend = new byte[4] { 0x82, 0x04, 0x00, 0x06 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button19_Click(object sender, EventArgs e)
    {
        //right fwd 1/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x04, 0x20, 0x26 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button18_Click(object sender, EventArgs e)
    {
        //right fwd 1/2 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x04, 0x40, 0x46 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button17_Click(object sender, EventArgs e)
    {
        //right fwd 3/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x04, 0x60, 0x66 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button16_Click(object sender, EventArgs e)
    {
        //right fwd full speed
        byte] bytesToSend = new byte[4] { 0x82, 0x04, 0x7F, 0x05 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button15_Click(object sender, EventArgs e)
    {
        //right rev 1/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x05, 0x20, 0x27 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button14_Click(object sender, EventArgs e)
    {
        //right rev 1/2 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x05, 0x40, 0x47 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button13_Click(object sender, EventArgs e)
    {
        //right rev 3/4 speed
        byte] bytesToSend = new byte[4] { 0x82, 0x05, 0x60, 0x67 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button12_Click(object sender, EventArgs e)
    {
        //right rev full speed
        byte] bytesToSend = new byte[4] { 0x82, 0x05, 0x7F, 0x06 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button11_Click(object sender, EventArgs e)
    {
        //right rev stop
        byte] bytesToSend = new byte[4] { 0x82, 0x05, 0x00, 0x07 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

}

}[/code]




Here is some shorter C# code that sets up a two button test panel. It is an example of extreme skid steering. The left motors are given a command for full forward power, while the right motors are given a command for full reverse power. This causes the A4WD to spin clockwise.
This code also shows that it isn’t necessary to have a delay between two back to back commands, at least at 9600 baud.

[code]using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace quick_serial_1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        //configuring the serial port
        serialPort1.PortName = "COM4";
        serialPort1.BaudRate = 9600;
        serialPort1.DataBits = 8;
        serialPort1.Parity = Parity.None;
        serialPort1.StopBits = StopBits.One;

        //left fwd full speed
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x7F, 0x01 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);

        //right rev full speed
        bytesToSend = new byte[4] { 0x82, 0x05, 0x7F, 0x06 };
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        //configuring the serial port
        serialPort1.PortName = "COM4";
        serialPort1.BaudRate = 9600;
        serialPort1.DataBits = 8;
        serialPort1.Parity = Parity.None;
        serialPort1.StopBits = StopBits.One;

        //left fwd stop
        byte] bytesToSend = new byte[4] { 0x82, 0x00, 0x00, 0x02 };
        serialPort1.Open();
        serialPort1.Write(bytesToSend, 0, 4);

        //right fwd stop
        bytesToSend = new byte[4] { 0x82, 0x04, 0x00, 0x06 };
        serialPort1.Write(bytesToSend, 0, 4);
        serialPort1.Close();
    }
}

}[/code]

If you set the Sabertooth’s 6th dip switch to ON, it will enable timeouts on the Sabertooth.

Yes, you have a good point with RC Mode 2, but I am using my Sabertooth in the Mode 4 Serial Packetized mode. In this case dip switches 4, 5 and 6 set the address. I could put one of my Arduinos on the A4WD and run the Sabertooth in RC Mode 2. I’m not sure though. The documentation sounds like I would need to put sw 6 down, which disables the timeout function, to connect a microprocessor. I’m not familiar with RC receivers. I wonder if I could emulate one with an onboard Arduino and leave sw 6 up? Or even better emulate one at the netbook end through the XBee’s.

Oh, sorry about that. You’re right. I didn’t notice that you were using the non-rc mode.

Lots of options, if you put on Arduino into your rover. You can run in either mode, it is your choice of which mode. I have some rover code running on an Arduino in the thread: viewtopic.php?f=48&t=7806

Currently I am using RC mode as I was also connecting servos to my Arduino and found that SoftwareSerial disables interrupts for the duration of sending or receiving a byte of data, which can cause glitches in the servo stream. Obviously if you can hook up to a Mega or the like with a USART that is not a problem. Likewise if you are not interested in Servos that won’t be a problem either.

How to handle losing connection.
a) Easiest way. Keep the time of the last valid data you received, if in your loop you find that the current time - that time is greater than some threshold assume you lost contact.

b) If I remember correctly you can also query the xbee for its connection status (or some such thing). Been awhile since I looked at this…

c) Have some form of communications handshaking. This is what I do with my code. My Robots ask the controller (either the PC or our DIY remotes), for data, and wait for a response. I have the XBees running in packet mode, so I have a couple of options. Timeout is still valid option. Another option is when I send a packet, you get an ACk type packet back, which will have an ACK or a NACK…

Kurt

hi,

i need visual basic 2010 express code to control xbee io pins.

i have two xbees one connected via usb cable to my computer and the other one is supply via a 3.3V battry and has an led connected through the pin 20.

i need a code that sends data to switch the led on and off

i tried this code but its not working.

SerialPort1.Write (“20, 4”) ’ suppose to switch on the led
SerialPort1.Write (“20, 5”) ’ suppose to switch off the led

if the code i wrote is good then maybe its the config of the xbee which is wrong.

what shoud the D0 (pin 20 ) be ; high, low, enable…?

thanks for helping me out