Over the past few years, the back of my mind has been thinking about a small, quick, camera robot I could drive around. Recently, with the help of a 3D printer I was finally able to print a chassis and put one together quickly.
The Parts
- 2 x GM10 gear motor with wheels – Tiny and quick motors
- 2 x 850mAh LiPo batteries – Small battery packs for power
- 1 x H-bridge Motor Driver – Bi-directional motor driver
- 1 x Arduino Fio v3 – Microcontroller with Xbee socket
- 2 x XBee Series 1 – Wireless modules for communication
- 1 x Thumb Joystick – For controlling the robot (not shown)
- 1 x 3D printed chassis
Total Cost: $ 125.77
The Chassis
Once I had all the parts I could design a chassis for the robot. I took to Solidworks and designed a simple frame with the two motors in the middle, a battery on each end and the Arduino in the center. In the first (red) model I printed, the Arduino was orientated sideways, which made the width almost the same as the length. In the second (blue) design, I rotated the Ardunio so the robot was more long and skinny. Using a 3D printer let me change and test these things super quick!
To control the motors I built a small board for the motor driver chip. There’s a good tutorial here for using the SN754410 chip. However it requires a 5V supply, so I needed to add a small 5V regulator in. The two LiPo batteries are connected in series, and nominally supply 7.4V to the 5V regulator and Vcc on the H-Bridge. The Arduino Fio and Xbee run off only one of the batteries, as they require 3.3V.
The Circuit
On the other side of the aether, I connected the second XBee to a USB to Serial board for the communication to/from a PC. I also used the thumb joystick I had and wired the X/Y outputs to two analog pins on the XBee. The following XBee config commands make the XBee sample the two analog input pins every 50 ms and send the values to the robot. The robot can then decode that information and use it to drive the motors.
XBee Config for Thumbstick Input: D0 = 2 D1 = 2 IR = 0x32 IT = 1
Coding it Up
The only code I needed to write to get things working was for the Arduino. It needed to decode the joystick’s analog X/Y values and translate them into motor commands. Each analog value is sent by the XBee as 10-bits in two bytes along with other information and a packet header. Most of the extra information I did not care about at this stage and I knew some values in the packet would not change so I wrote a simple, hardcoded parser:
// Parse XBee Data
if (Serial1.available() > 0)
{
int c = Serial1.read();
// The start byte is always 0x7E
if (c == 126)
{
char buffer[8];
// Throw away the next 8 bytes
c = Serial1.readBytes(buffer, 8);
if (c == 8)
{
c = Serial1.readBytes(buffer, 2);
// Read two bytes and check the first equals 6
if (buffer[0] == 6)
{
// Read and save ADC values
c = Serial1.readBytes(buffer, 4);
int ADC0 = (byte(buffer[0]) << 8) + byte(buffer[1]);
int ADC1 = (byte(buffer[2]) << 8) + byte(buffer[3]);
SetMotor((ADC0 >> 2) - 127, (ADC1 >> 2) - 127);
}
}
}
}
The SetMotor() function shown below combines the X and Y values from the thumbstick into left and right motor speeds. Before passing the thumbstick’s ADC values, they are divided by 4 and centered around zero. The extra resolution is not really needed and centering each around zero simplifies things.
// Analog and digital pin assignment const byte LMEN = 9; // Left Motor enable PWM (analog out) const byte RMEN = 10; // Right Motor enable PWM (analog out) const byte LM2A = 14; // Left Motor direction 2A const byte LM1A = 16; // Left Motor direction 1A const byte RM2A = 15; // Right Motor direction 2A const byte RM1A = 17; // Right Motor direction 1A const byte MDZ = 8; // Motor dead zone constant void SetMotor(int X, int Y) // X = Fwd/Rev Y = Left/Right { // Work out speed and direction (sign) of each motor int LM = X + (Y/2); int RM = X - (Y/2); if (LM > MDZ) // Check value is outside deadzone { digitalWrite(LM2A, LOW); // Set motor direction digitalWrite(LM1A, HIGH); analogWrite(LMEN, LM); // Set motor speed } else if (LM < -MDZ) { digitalWrite(LM2A, HIGH); digitalWrite(LM1A, LOW); analogWrite(LMEN, LM * -1); } else { analogWrite(LMEN, 0); // Disable motor (within deadzone) } if (RM > MDZ) { digitalWrite(RM2A, LOW); digitalWrite(RM1A, HIGH); analogWrite(RMEN, RM); } else if (RM < -MDZ) { digitalWrite(RM2A, HIGH); digitalWrite(RM1A, LOW); analogWrite(RMEN, RM * -1); } else { analogWrite(RMEN, 0); } }
There’s not much else to the Arduino program to get things running, apart from setting up the I/O pins needed. Plug in the motors, power the thumbstick and XBee, and drive! The SetMotor() function needs improvement as trying to control the robot is a little mad (mad but fun), and I haven’t put a camera on it yet…