Sunday, February 19, 2012

Compass Controlled Robot

The the compass breakout HMC6352 from Sparkfun is easy to use and works well to control the direction of a robot. Here is a picture of the test robot used with the compass breakout. The robot robot uses the Arduino UNO with the Adafruit motor shield. External power is supplied to the motor shield with a 7.2v battery.

The compass breakout HMC6352 can be powered with 2.7 to 5.2 volts. The Arduino UNO that was used here operates at 5 volts, but it does have a 3.3 volt supply pin. Unfortunately the motor shield covered up the Arduino 3.3v power supply. There were a few comments about using the compass breakout at 5 volts. Most comments said it is within the stated operating limits and it should work at 5 volts. One comment said their compass breakout ran fine at 5 volts for about 30 minutes, then went up in a puff of smoke.

So as an alternative to using 5 volts, a voltage divider was used. The calculations were done using Hyperphysics Voltage Divider with R1 being 3 parallel 1 k ohm resisters and R2 being a single 1 k ohm resister, using 5 volts this would give a high load resistance voltage of about 3.7 volts. The compass breakout uses about 1 mA of current which at 3.7 volts is equivalent to a resistance of about 3 k ohms. Assuming 3 k ohms as the load resistance gives an operating voltage of about 3.5 volts. This is well within the operating voltage of the compass breakout. The equivalent resistance of the voltage divider is 1.333 k ohms, so at 5 volts it would waste 3.75 mA of current. The compass breakout uses about 1 mA, so that is a total current draw of about 4.75 mA. The Arduino 5 volt pin should not be used to supply more that 30 mA, so this seems well within the limits there too.

The simple BLDR program was used to test the compass breakout. That wiring diagram was also used, except for the voltage divider. After seeing that the compass breakout was working, the motor control was added to control the direction of the robot using the compass. This program has the robot drive using the compass heading of 180 degrees, that is magnetic south. The speed numbers will vary depending on the motors used and the voltage driving the motors.

A jumper switch was added from Arduino A0 to control the motors. When the jumper switch connected to a ground pin, the motors will not run. This allows you to start and stop the motors while testing the movement.


#include
#include
int HMC6352SlaveAddress = 0x42;
int HMC6352ReadAddress = 0x41; //"A" in hex, A command is:

int headingValue;

AF_DCMotor motorR(3, MOTOR12_64KHZ); // create motor #1, 64KHz pwm
AF_DCMotor motorL(1, MOTOR12_64KHZ); // create motor #3, 64KHz pwm

int switchPin = A0; // select the input pin for the potentiometer
int switchValue = 0; // variable to store the value coming from the sensor

int speedL = 190;
int speedR = 200;
int speedD = 50;

void setup() {
// "The Wire library uses 7 bit addresses throughout.
// If you have a datasheet or sample code that uses 8 bit address,
// you'll want to drop the low bit (i.e. shift the value one bit to the right),
// yielding an address between 0 and 127."
// I know 0x42 is less than 127, but this is still required
HMC6352SlaveAddress = HMC6352SlaveAddress >> 1;
Wire.begin();

Serial.begin(9600); // set up Serial library at 9600 bps

motorR.setSpeed(speedL); // set the speed to 200/255
motorL.setSpeed(speedR); // set the speed to 200/255
}


void loop() {
switchValue = analogRead(switchPin); // read the value from the sensor
if (switchValue > 0) {

//"Get Data. Compensate and Calculate New Heading"
Wire.beginTransmission(HMC6352SlaveAddress);
Wire.send(HMC6352ReadAddress); // The "Get Data" command
Wire.endTransmission();

//time delays required by HMC6352 upon receipt of the command
//Get Data. Compensate and Calculate New Heading : 6ms
delay(6);

Wire.requestFrom(HMC6352SlaveAddress, 2); //get the two data bytes, MSB and LSB
//"The heading output data will be the value in tenths of degrees
//from zero to 3599 and provided in binary format over the two bytes."
byte MSB = Wire.receive();
byte LSB = Wire.receive();

float headingSum = (MSB << 8) + LSB; //(MSB / LSB sum)
float headingInt = headingSum / 10;
Serial.print(headingInt);
Serial.println(" degrees");
if (headingInt < 180) {
Serial.println("Right");
motorR.setSpeed(speedR+speedD); // set the speed to 200/255 motorL.setSpeed(speedL-speedD); // set the speed to 200/255
} else if (headingInt > 180) {
Serial.println("Left");
motorR.setSpeed(speedR-speedD); // set the speed to 200/255
motorL.setSpeed(speedL+speedD); // set the speed to 200/255
} else {
Serial.println("Straight");
motorR.setSpeed(speedR); // set the speed to 200/255
motorL.setSpeed(speedL); // set the speed to 200/255
}

motorR.run(FORWARD); // turn it on going forward
motorL.run(FORWARD);
delay(100);
}
motorR.run(RELEASE);
motorL.run(RELEASE);
}

Monday, February 6, 2012

Alternative to Robot Tank Mode Driving

Many people seem to be unaccustomed to robot tank mode driving, where the left stick controls the left motor and the right stick controls the right motor.

Robot Tank Mode Driving
When the stick is moved forward, the corresponding motor speed is increased in the forward direction. When the stick is moved backward, the corresponding motor speed is increased in the backward direction. When the two control sticks are both pushed forward the robot moves forward. When the two control sticks are moved in opposite directions, one wheel rotates forward, the other rotates backward, and the robot turns.

An Alternative to Tank Mode Driving
People that play video games ask about having the controls set up so that the left stick controls speed forward and backward, and the right stick control turning by moving the stick left and right. This alternative method creates some interesting questions about how exactly to make this happen. In playing with this a bit, the following equations were developed. The next step would be to try out these relationships and see how the driving "feels".