Self-Balancing Wheelie Car:

The video to the right and the photos below show the RC controlled wheelie vehicle built by Prof. Bobrow for classroom demonstrations.

The Arduino uses angle and roll rate data supplied by the IMU.

If the RC driver pops a wheelie greater than 45 degrees, the feedback controller kicks in and attempts to hold the vehicle in the wheelie.

While doing a wheelie, the RC commands are interpreted as small changes in the balance point. This allows the driver to move forward or backwards while the feedback controller holds the wheelie.

The Arduino code can be found below.

Wheelie Car Arduino Program:

#include <SPI.h>
#define CS 8 // Chip select: pin 8
#define ImuToDeg(x) (((float)x)/100.0)
#define ImuToVel(x) (((float)x)/10.0)
#define M1pwm 9
#define M2pwm 10
#define Reset 4

int roll, pitch, yaw, rolldot, pitchdot, yawdot;
int accel_x, accel_y, accel_z;

volatile int Ch1=0, Ch2=0;

void setup()
{
attachInterrupt(0, getpulse0, CHANGE);
attachInterrupt(1, getpulse1, CHANGE);
pinMode(CS, OUTPUT);
SPI.begin();
TCCR1B = 0x01; // Timer 1: PWM pins 9 & 10 @ 32 kHz
pinMode(M1pwm, OUTPUT);
pinMode(M2pwm, OUTPUT);
pinMode(Reset, OUTPUT);
analogWrite(M1pwm, 127);
analogWrite(M2pwm, 127);
delay(500);
digitalWrite(Reset, HIGH); // Turn on amp
}

void loop() {
ReadIMU(0);
if( (ImuToDeg(roll) > 40.0) && (fabs(ImuToVel(rolldot))< 200.0 ) ) balance(58.0);
else if ( (abs(Ch1)<400) && (abs(Ch2)<400) ){
float u1 = (float)( Ch1/2 );
float u2 = (float)( Ch2/4 );
motors(u1,u2);
} else motors(0.0,0.0);
}

void balance(float equilib){
static unsigned long t1=0, t2, dt;
const float kyawdot=0.1, kproll=4.0, kvroll=0.4, kv=-0.07;
t2 = micros();
dt = t2-t1;
if ( dt > 4000 ){ // do the control update, nothing otherwise
t1=t2;
float Ts = ((float)(dt))/1000000.0;
float velocity = (float)(analogRead(A7) - analogRead(A6)); //tach signals
ReadIMU(0);
float Rollerr = ImuToDeg(roll) - equilib + 0.03*((float)Ch1);
float u1= -kproll*Rollerr - kvroll*ImuToVel(rolldot)-kv*velocity;
float u2 = -kyawdot*(ImuToVel(yawdot) - 3.0*((float)Ch2) );
motors(u1,u2);
}
}

void motors(float u1,float u2){
int f1 = constrain(((int)(u1+u2)+127), 0, 255);
int f2 = constrain(((int)(u1-u2)+127), 0, 255);
analogWrite(M1pwm, f1);
analogWrite(M2pwm, f2);
}

void getpulse0(){
volatile static unsigned long t0=0;
volatile unsigned long t=micros();
if( t-t0 > 10000 ){
t0 = t;
return;
}
Ch1 = t-t0-1500;
return;
}

void getpulse1(){
volatile static unsigned long t0=0;
volatile unsigned long t=micros();
if( t-t0 > 10000 ){
t0 = t;
return;
}
Ch2 = t-t0-1500;
return;
}

int getSPIint(int command){
byte byte0 = SPI.transfer(command);
byte byte1 = SPI.transfer(command);
int result = ( ((int)byte1 << 8) | (int)byte0 );
return(result);
}

void ReadIMU(byte cmd) {
digitalWrite(CS, LOW); // select device
byte byte0 = SPI.transfer(cmd); // start it
roll = getSPIint(cmd);
pitch = getSPIint(cmd);
yaw = getSPIint(cmd);
rolldot = getSPIint(cmd);
pitchdot = getSPIint(cmd);
yawdot = getSPIint(cmd);
accel_x = getSPIint(cmd);
accel_y = getSPIint(cmd);
accel_z = getSPIint(cmd);
digitalWrite(CS, HIGH); // deselect device
}
www.000webhost.com