Balancing Rover
Overview
This two-wheeled rover is designed to balance and stay upright even on tilted surfaces. It runs on 4 AA batteries and uses a dual H-Bridge to control the wheel motors. Feedback control balancing is implemented using data gathered from Hall effect encoders and an LSM9DS1 IMU. In addition, there is a speaker on the robot that gives auditory feedback to the user. The further the robot is from level, the louder that speaker buzzes.

Members
- Neil Hardy
- Madeleyne Vaca
Parts
- Dual H-Bridge
- LSM9DS1 IMU
- 4 AA batteries with pack
- barrel connector
- 2 DC motors
- Encoder kit
Wiring
| mbed | LSM9DS1 |
|---|---|
| p27 | SDA |
| p26 | SCL |
| VDD | VOUT |
| GND | GND |
| mbed | Dual H-Bridge | Left Motor | Right Motor |
|---|---|---|---|
| p22 | PWMA | - | - |
| p20 | AIN2 | - | - |
| p19 | AIN1 | - | - |
| p16 | ^/STBY | - | - |
| p18 | BIN1 | - | - |
| p17 | BIN2 | - | - |
| p21 | PWMB | - | - |
| VOUT | VCC | - | - |
| VU | VMOT | - | - |
| GND | GND | - | - |
| - | AO1 | pos | - |
| - | AO2 | neg | - |
| - | BO1 | - | pos |
| - | BO2 | - | neg |
| mbed | Left Encoder | Right Encoder |
|---|---|---|
| VOUT | pwr+(red) | pwr+(red) |
| GND | pwr-(black) | pwr-(black) |
| p15 | data (white) | - |
| p16 | - | data (white) |
include the mbed library with this snippet
#include "mbed.h"
#include "LSM9DS1.h"
#define PI 3.14159
#define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA.
#include "motordriver.h"
#include "MAF.h"
//Debugging
Serial pc(USBTX, USBRX);
//For data
//LSM9DS1 IMU(p9, p10, 0x6B, 0x1E);
LSM9DS1 IMU(p28, p27, 0xD6, 0x3C);
Motor lmotor(p22, p19, p20, 0);
Motor rmotor(p21, p18, p17, 0);
int count = 0;
//data
float roll;
MAF avg;
PwmOut speaker(p23);
float printAttitude(float ax, float ay, float az, float mx, float my, float mz)
{
float roll = atan2(ay, az);
float pitch = atan2(-ax, sqrt(ay * ay + az * az));
// touchy trig stuff to use arctan to get compass heading (scale is 0..360)
mx = -mx;
float heading;
if (my == 0.0)
heading = (mx < 0.0) ? 180.0 : 0.0;
else
heading = atan2(mx, my)*360.0/(2.0*PI);
//pc.printf("heading atan=%f \n\r",heading);
heading -= DECLINATION; //correct for geo location
if(heading>180.0) heading = heading - 360.0;
else if(heading<-180.0) heading = 360.0 + heading;
else if(heading<0.0) heading = 360.0 + heading;
// Convert everything from radians to degrees:
//heading *= 180.0 / PI;
pitch *= 180.0 / PI;
roll *= 180.0 / PI;
if (count > 10) {
roll = avg.update(roll);
} else {
count++;
avg.update(roll);
}
pc.printf("Pitch: %f, Roll: %f degrees\n\r",pitch,roll);
pc.printf("Magnetic Heading: %f degrees\n\r",heading);
return roll;
}
int main() {
//Calibrate IMU
IMU.begin();
if (!IMU.begin()) {
pc.printf("Failed to communicate with LSM9DS1.\n");
}
IMU.calibrate(1);
IMU.calibrateMag(0);
speaker.period(1.0/200.0); // 500hz period
while(!IMU.magAvailable(X_AXIS));
IMU.readMag();
while(!IMU.accelAvailable());
IMU.readAccel();
while(!IMU.gyroAvailable());
IMU.readGyro();
roll = printAttitude(IMU.calcAccel(IMU.ax), IMU.calcAccel(IMU.ay), IMU.calcAccel(IMU.az), IMU.calcMag(IMU.mx),
IMU.calcMag(IMU.my), IMU.calcMag(IMU.mz));
float prevRoll = roll;
float pGain = 1.0/15.0;
float dGain = 1.0/10.0;
while(1) {
while(!IMU.magAvailable(X_AXIS));
IMU.readMag();
while(!IMU.accelAvailable());
IMU.readAccel();
while(!IMU.gyroAvailable());
IMU.readGyro();
/*pc.printf(" X axis Y axis Z axis\n\r");
pc.printf("gyro: %9f %9f %9f in deg/s\n\r", IMU.calcGyro(IMU.gx), IMU.calcGyro(IMU.gy), IMU.calcGyro(IMU.gz));
pc.printf("accel: %9f %9f %9f in Gs\n\r", IMU.calcAccel(IMU.ax), IMU.calcAccel(IMU.ay), IMU.calcAccel(IMU.az));*/
roll = printAttitude(IMU.calcAccel(IMU.ax), IMU.calcAccel(IMU.ay), IMU.calcAccel(IMU.az), IMU.calcMag(IMU.mx),
IMU.calcMag(IMU.my), IMU.calcMag(IMU.mz));
/*
For differential control create another variable that stores the previous
roll value. Subtract it from the current to get the difference. Currently, speed
is equal to pgain*roll+dgain*(roll difference)*/
float lmotorSpeed = roll*pGain + (roll - prevRoll)*dGain;
float rmotorSpeed = roll*pGain + (roll - prevRoll)*dGain;
//adding extra power close to the balancing point to overcome friction.
//without this the robot isn't moving fast enough to cover the last tiny distance to balance
if (fabs(lmotorSpeed) < .1) lmotorSpeed*=1.2;
if (fabs(rmotorSpeed) < .1) rmotorSpeed*=1.2;
//set speaker loudness and motor speeds
speaker = fabs(lmotorSpeed/20.0);
lmotor.speed(lmotorSpeed);
rmotor.speed(rmotorSpeed);
}
}
Please log in to post comments.
