Tuesday, December 10, 2013

Arduino Compass Bearing Following Robot

Build a robot that automatically tracks a user provided compass heading.  Create a proof of concept indoor model and then scale up for outdoor use.

If you are not interested in the build details and just want to see the result take a look at the video below.  Basically, we are using an Arduino Nano and a LM303DLHC Micro Electro Mechanical (MEMs) compass sensor to read and track a compass bearing.

Rev 2.0: Uses the battery for the mounting chassis:

As shown in the videos, the robot continuously reads it's current compass bearing and adjusts to track the desired user direction.  It does this by turning the wheel motors on or off.  To keep things simple, the two motors are powered at full speed (no PWM).  The two motors are never on at the same time.
Modern technology keeps the BOM small and puts the magic in the software that is shown later.

Ardunio Nano microcontroller for the brains.  About $10USD if you shop around.

LM303DLHC MEMs sensor provides the magnetic compass reading input for the Arduino.  The LM303DLHC is has tilt compensation and accelerometers on board that can be used to detect hitting obstacles.  About $7USD shipped from "eBay China".

754410NE H-Bridge to drive the motors.  (The Ardunio can't source enough current to drive the motors.)  At is stands now the project only powers the drive wheels to move forward, however; we selected the 754410NE because with just a few wires and lines of code it can drive both motors forward and reverse. About $3USD.
Get the above parts, a breadboard, two DC motors, wheels, a power source, etc. and hook it all up.  In the diagram below I tried to closely mimic the breadboard setup in the pics:

Scaling Up:
We have a few APEX PA74 op amps that are capable of driving VERY high current loads.  We are in the process of scaling the build for outdoor use with strong 12VDC motors.  Here is a quick demo vid of the platform in action:

If you are still with us, here is the Arduino Nano code.  This is the most simple example.  Other options include using the accelerometers to detect obstacles and drawing patterns (triangle, square, out and back, etc.)

 ***** www.WhiskeyTangoHotel.Com  *****
    Project Name: LM303DLHC Compass Robot
    Start Date:  Nov 2013
    Program Rev History and Notes:
      Special thanks to pololu.com!  See their GitHub site.
      Point robot in desired direction then press reset button.
      Put robot on ground.  After 5 sec delay the robot will track the desired bearing.
      This version moves the robot on the user desired bearing forever.
      Other versions detect objects (bump) and draw patters (out and return, box, triangle)


// Define Variable Types and include.h
#include <Wire.h>
#include <LSM303.h>

int LeftWheel = 11;         //left motor on output D11
int RightWheel = 10;       //right motor on output D10


LSM303 compass;

int gotoheading;  //global var for the initial robot direction.  Or Press reset button...

void setup() {
   pinMode(LeftWheel, OUTPUT);      // sets the digital pin as output
   pinMode(RightWheel, OUTPUT);      // sets the digital pin as output
   digitalWrite(LeftWheel, LOW);
   digitalWrite(RightWheel, LOW);
   Serial.begin(9600);  // Used for debug only

  //read the direction that you want the robot to go.  LM303 Header pins point to direction
  gotoheading = compass.heading((LSM303::vector){0,-1,0});

  delay(5000);  // dealy xx mSecs after power up before doing anything

  // Calibration values. Use the pololu.com Calibrate example program to get the values for your compass.
  compass.m_min.x = -872; compass.m_min.y = -757; compass.m_min.z = -212;
  compass.m_max.x = +461; compass.m_max.y = +511; compass.m_max.z = 844;


void loop() {
  int heading = compass.heading((LSM303::vector){0,-1,0});

 ///*  Print to the PC monitor.  Debug only.
  Serial.print(" Current is: ");

//*/  //End Serial print to PC comment block
  if (heading > gotoheading)    //turn the bot left by turning on right motor
      digitalWrite(LeftWheel, LOW);
      digitalWrite(RightWheel, HIGH);
      Serial.println("   OFF  --  ON");
  if (heading <= gotoheading)  //turn the bot right by turning on left motor
    digitalWrite(LeftWheel, HIGH);
    digitalWrite(RightWheel, LOW);
    Serial.println("   ON --  OFF");

  delay(0);   //in mSecs

}  //void loop