Wednesday, March 18, 2015

Arduino based Self-balancing unicycle

This project is arduino-uno based self-balancing unicycle. A self-balancing unicycle is a type of unicycle, that is considered an electric vehicle, that uses sensors, gyros, and accelerometers in conjunction with an electric motor to assist a rider with balancing on a single wheeled vehicle.

Self-balancing Unicycle


 

Connection Diagram for Arduino with MPU6050


 













Motor Driver

Motor Driver Pin Discription





STEPS


* Connect MPU6050 to Arduino as above diagram.
*Connect ground of motor driver connect to ground of arduino.
* Connect pins of arduino 12 TO IN-1 and 13 to IN-2 of motor driver.
* Connect pin 3 (PWM) output of arduino to PWM input of Motor Driver.
*Connect battery and motor to motor driver.

* Download Kalman Filter Library



* Add to arduino IDE library.
*Open Arduino IDE.
* Copy this code to Aurduino IDE.
* Verify and Load to Arduino.







Self-balancing unicycle arduino code


// JAWAHARLAL COLLEGE OF ENGINEERING AND TECHNOLOGY
// felix m philip
// Self balancing unicycle
// µController = ATmega328
// 2 Pololu micro metal gear motors with 60mm wheels + DRV8833 motor controller
// 6DOF MPU6050 sensor
#include <Wire.h>
#include "Kalman.h"


Kalman kalmanX; // Create the Kalman instance
/* IMU Data */
int16_t accX, accY, accZ;
int16_t tempRaw;
int16_t gyroX, gyroY, gyroZ;
float accXangle;//, accYangle; // Angle calculate using the accelerometer
float gyroXangle;//, gyroYangle; // Angle calculate using the gyro
float kalAngleX;//, kalAngleY; // Calculate the angle using a Kalman filter
unsigned long timer;
uint8_t i2cData[14]; // Buffer for I2C data
float CurrentAngle;
// Motor controller pins
const int AIN1 = 3; // (pwm) pin 3 connected to pin AIN1
const int AIN2 = 9; // (pwm) pin 9 connected to pin AIN2
const int BIN1 = 10; // (pwm) pin 10 connected to pin BIN1
const int BIN2 = 11; // (pwm) pin 11 connected to pin BIN2
int speed;
// PID
const float Kp = 4;
const float Ki = 1;
const float Kd = 1;
float pTerm, iTerm, dTerm, integrated_error, last_error, error;
const float K = 1.9*1.12;
#define GUARD_GAIN 10.0
#define runEvery(t) for (static typeof(t) _lasttime;(typeof(t))((typeof(t))millis() - _lasttime) > (t);_lasttime += (t))
void setup() {
pinMode(AIN1, OUTPUT); // set pins to output
pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
Serial.begin(57600);
Wire.begin();
i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
while(i2cWrite(0x19,i2cData,4,false)); // Write to all four registers at once
while(i2cWrite(0x6B,0x01,true)); // PLL with X axis gyroscope reference and disable sleep mode
while(i2cRead(0x75,i2cData,1));
if(i2cData[0] != 0x68) { // Read "WHO_AM_I" register
Serial.print(F("Error reading sensor"));
while(1);
}
delay(100); // Wait for sensor to stabilize
/* Set kalman and gyro starting angle */
while(i2cRead(0x3B,i2cData,6));
accX = ((i2cData[0] << 8) | i2cData[1]);
accY = ((i2cData[2] << 8) | i2cData[3]);
accZ = ((i2cData[4] << 8) | i2cData[5]);
accXangle = (atan2(accY,accZ)+PI)*RAD_TO_DEG;
kalmanX.setAngle(accXangle); // Set starting angle
gyroXangle = accXangle;
timer = micros();
}
void loop() {
runEvery(25) // run code @ 40 Hz
{
dof();
if (CurrentAngle <= 180.2 && CurrentAngle >= 179.8)
{
stop();
}
else{
if (CurrentAngle < 230 && CurrentAngle > 130)
{
Pid();
Motors();
}
else
{
stop();
}
}
}
}
void Motors(){
if (speed > 0)
{
//forward
analogWrite(AIN1, speed);
digitalWrite(12, LOW);
digitalWrite(13, HIGH);
}
else
{
// backward
speed = map(speed,0,-255,0,255);
analogWrite(AIN1, speed);
digitalWrite(12, HIGH);
digitalWrite(13, LOW);
}
}
void stop()
{
analogWrite(AIN1, 0);
analogWrite(AIN2, 0);
analogWrite(BIN1, 0);
analogWrite(BIN2, 0);
}
void Pid(){
error = 180 - CurrentAngle; // 180 = level
pTerm = Kp * error;
integrated_error += error;
iTerm = Ki * constrain(integrated_error, -GUARD_GAIN, GUARD_GAIN);
dTerm = Kd * (error - last_error);
last_error = error;
speed = constrain(K*(pTerm + iTerm + dTerm), -255, 255);
}
void dof()
{
while(i2cRead(0x3B,i2cData,14));
accX = ((i2cData[0] << 8) | i2cData[1]);
accY = ((i2cData[2] << 8) | i2cData[3]);
accZ = ((i2cData[4] << 8) | i2cData[5]);
tempRaw = ((i2cData[6] << 8) | i2cData[7]);
gyroX = ((i2cData[8] << 8) | i2cData[9]);
gyroY = ((i2cData[10] << 8) | i2cData[11]);
gyroZ = ((i2cData[12] << 8) | i2cData[13]);
accXangle = (atan2(accY,accZ)+PI)*RAD_TO_DEG;
double gyroXrate = (double)gyroX/131.0;
CurrentAngle = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros()-timer)/1000000);
timer = micros();
}






6 comments:

  1. Please add me I need help

    facebook.com/smartfelix007

    ReplyDelete
  2. Please add me I need help

    facebook.com/smartfelix007

    ReplyDelete
  3. Please add me I need help

    facebook.com/smartfelix007

    ReplyDelete
  4. I want self balancing arduino code or program for the cycle

    ReplyDelete
  5. Buen dia, me podría ayudar para poder hacer el mismo project personal.

    Gracias

    ReplyDelete
  6. Hi I managed to program using your code thanks.. if anyone needs help on this project msg here

    ReplyDelete