Robot Prototyping 101

robot_101

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

scout_robot

Total Cost: $ 125.77

The Chassis

scout_robot_rotated

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…

About these ads
This entry was posted in 3D Printing, Robots and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s