Self Balancing Robot

you can use whatever :slight_smile: mine were old pieces i had lying around (i think they're something like 10 years old). They're 100k, standard linear potentiometer.
Here's an example, but i suggest purchasing them at some local store
http://www.maplin.co.uk/Module.aspx?ModuleNo=2205&C=5716&U=shop_FW05F

Hi again after a big interrupt )
well I read the links on PID and got to it, but I have to implement it to see. I started to analyze your code, but some moments are still unclear to me. KF parts are crystal clear, just are following the KF formulation from mathematics. PID has some of your own secrets :wink:
I write them here if you can kindly explain them it greatly helps :wink:

I cant understand these:

  1. please let me know, what calibration here means, and why -4.5, and why added to your myangle (converted to degree? yes?)
  float calibration = -4.5; // read from a pot or something
  float myangle=(angle*57.2957795130823)-90.0 + calibration;
  1. You mean, when time is more than 6 sec. LED goes high? why? (
if ((millis()-startmillis) > 6000 )
  1. why P and I have pot/100, but D has pot/10?
P = (myangle * (pot1 / 100.0)); // pot/10
D = (myangle-oldAngle) * (pot2 / 10.0);
  1. why 128? why 250 and 5?
    float motors = 128.0 - (pid+(sgn(pid)*sqr(pid/18)));
    // cap the value
    if (motors>250.0) motors = 250.0;
    if (motors<5.0) motors = 5.0;
  1. What is this if-block for? else is comming from having info in motorInput, but this if speakc about?
    if ((myangle > 80) || (myangle < -80))

sorry for I'm this much novice )))

hello

I am currently doing a 2 wheeled balancing cart project and i have a few doubts about the IMU. i have a IMU 5DOF frm sparkfun. it has X, Y, Z, XRATE AND YRATE. On reading a few threads here i have understood that the accelerometer gives me the acceleration and hence the tilt angle can be calculated.

what i dont understand is what do i get from the rate gyro?? all i know is when i connect it to the arduino, the serial monitor shows a voltage! how do i convert this into the angular velocity?? and why do we need to calculate this angular velocity?? i read that the rate gyro id used to calculate the angular velocity (angular rate), but dunno how to get it!!
plz help

thank u in advance

Yeswant, I have replied to your PM on this question but to save others the trouble of duplicating answers, here is my response:

The gyro outputs a voltage proportional to yaw rate (rate of rotation), with mid voltage (around 2.5 volts indicating no rotation. So as analogRead values increasing above 512 indicate increasing rotation rates in one direction, and values decreasing below 512 indicate increasing rates in the other direction.

This output is usually fed into a Kalman filter to smooth the data and reduce drift by combining information from the gyro with the accelerometers.

There is a lot of information on how to do this in this thread and other sites linked.
Have fun!

ironbot, here's the explanations:

  1. please let me know, what calibration here means, and why -4.5, and why added to your myangle (converted to degree? yes?)
  float calibration = -4.5; // read from a pot or something

float myangle=(angle*57.2957795130823)-90.0 + calibration;

The calibration is a fixed value that gets added to the angle, it's becouse my accelerometer is not perfectly perpendicular when the robot is in balance. That is, when the center of mass falls exacly in the line of the wheels, my accelerometer does not read 0, it reads something like 4.5. So adding -4.5 corrects the problem.
(now 4.5 is quite a big value, probably i was also messing in the code to get the robot roving around).

  1. You mean, when time is more than 6 sec. LED goes high? why? (
if ((millis()-startmillis) > 6000 )

Well, this is a strange issue: for some reason (read: due to my crappy code), the angle i read starts completely wrong when i turn on the robot. I have to wait about 5 seconds for it to reach a correct value, so i added that pause. That "if" encloses the whole motor control stuff (not just the led), so the robot is basically dead for the first 6 seconds.

  1. why P and I have pot/100, but D has pot/10?
P = (myangle * (pot1 / 100.0)); // pot/10

D = (myangle-oldAngle) * (pot2 / 10.0);

this is pure empirism: the D value is in a smaller range than P (in my specific setup), so, since the two potentiometers have the same range, i used different coefficient.
Calibrating all this stuff require a great deal of trial and error :slight_smile:

  1. why 128? why 250 and 5?
    float motors = 128.0 - (pid+(sgn(pid)*sqr(pid/18)));

// cap the value
   if (motors>250.0) motors = 250.0;
   if (motors<5.0) motors = 5.0;

My motor controller accept values between 0 and 255, where 128 is stop, 0 is full backward, 255 is full forward. So the 128 adjust to the "logical zero". The two "if" avoid the motors going to the max value (i kept 5 lower, probably not necessary, but they're quite fast anyway and i didn't wanted to push them).

  1. What is this if-block for? else is comming from having info in motorInput, but this if speakc about?
    if ((myangle > 80) || (myangle < -80))

This is the dead-man switch :slight_smile: If the robot is fallen horizontal (ie, it is at 90 degree :)), i just stop the motors and give up. Without this ifs, the wheels would keep spinning dragging the robot around.
While the robot is laying, i also stop incrementing the I value to avoid gigantic build-up of the integral component, so that when you manually turn your robot up, it can restart the balancing action.

I hope this clears some of your doubts!

Btw when will you post some pictures of your robot? :slight_smile:

Hi everyone, saw a couple of pid control posts on this thread and figured I throw up a shameless (ok, maybe a bit shameful) plug for the arduino PID library I wrote a few months back: Arduino Playground - PIDLibrary

there's also been some healthy back-and-forth on this thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226431507

the overhead may be a bit high for this application, maybe not. figured I'd let people know it existed.

Cheers

I'm working on a self-balancing robot too.

That RD01 drive system looks nice. I've spent a couple of days tweaking my control system to compensate for the nonlinearity of my motors' acceleration, and I'm wishing I had something like that right about now. Too bad it costs about 80% of what I spent on my entire robot...

Hi,

I'm also using an MD23 for a self balancing robot - but I'm getting very strange behaviour. i can control the speed of the wheels but every 5 seconds it spins teh opposite way for a split second and then continues the correct way.

it also sometimes randomly stops one of the wheels.

is there any chance you can upload wire.h? I understand everything else and i think I may be going wrong with the actual iic interface.

Unless you maybe had this problem? I've tried in modes 2 and 3 and the same thing happens.

OK - mine's going well now I've sorted problems with the MD23.

One thing though - in the PID controller I can't understand this line:

float motors = 128.0 - (pid+ ( sgn(pid) * sqr (pid/18) ) );

the sgn() function just returns 1 or -1 depending on pid (if it's less or greater than zero).

but i don't udnerstand where you get pid/18 from. Anyone know?

that is pure empirism.
the fact is: i noticed that, given the final value of the pid ("pid" in this case), driving the motors with it linearly was good for small values, but was to low for big values (that is, when the robot is very tilted).
So i tought about using an exponential function, that is using pid^2 instead of pid, so that it grew a lot more as the values gets bigger.

The problem is that i'm working with signed values, and the square of a value is always positive. So i multiply the square with the "sgn" function to restore the original sign.

Another problem was that the resulting value was too big, so i scaled down it with random values, ending up with a 18 that suited my needs. Your mileage WILL vary :slight_smile:

I suggest you to skip the line and simply use the "pid" value (almost) directly for the first test, and then eventually play with it as i did.

I'm also using an MD23 for a self balancing robot - but I'm getting very strange behaviour. i can control the speed of the wheels but every 5 seconds it spins teh opposite way for a split second and then continues the correct way.

it also sometimes randomly stops one of the wheels.

is there any chance you can upload wire.h? I understand everything else and i think I may be going wrong with the actual iic interface.

Unless you maybe had this problem? I've tried in modes 2 and 3 and the same thing happens.

About the wheel spinning backward, if i had to guess i'll say it's some problem with signs in your code, possibly and overflow (ie a signed 16-bit int going over 32k or such). Try to debug the values you're using with Serial.print and see if you get near "limit" values when it happends.

wire.h should be included in arduino, i didn't wrote it.

MD23 problem was solved by increasing my timings for the I2C bus
ended up with:

      #define iic_bittime                         250
      #define iic_scl_high_time                   600
      #define iic_scl_low_time                   600
      #define iic_bus_free_time                   470

Here's what I have so far:

I did initially ignore that line you wrote, but then found that it wouldn't work at all. Theory says that the motors can't provide as much torque if they're already moving, and so the speed must be increased relative to the previous speed. In the end I have:

 float motors = 128 - ( pid + oldSpeed * smulti);

smulti in my case is 0.6 (trial and error).
The result is it balancing if it's very still, but once it gets passed about 2 degrees it goes crazy and falls down.

Well compliments, it's quite stable! Try it on a carpet, you'll be surprised how good it will work :slight_smile:

Didn't letsmakerobots.com also make a beat boxing robot that samples itself?

Hi,
I tried to understand this:

q_m= ((float)average)*(1500.0/1024.0)*PI/180 ;  // HAC remove 1.5 mult

and got a little confused, which even increased when I met this (another source of getting gyro output ratio metric):

conversion = 5.0 / 1024.0 * 1000 / 15 / 57.29578;
gyro = analogRead(gyroPin);
gyro = (gyro - 512.0) * conversion;

Then I decided to rewrite it step by step:

conversion = 5.0 * (1/1024.0) * 1000 *(1/15) * (1/57.29578)

Next, I added the dimensions, OMITTING 1000 ADDING m (milli-), getting dimension for (1/15) from the data sheet of gyro, under "Sensitivity":

conversion = 5.0 [v] * (1/1024.0) [1/LSB] * (1/15) [1/mV/deg/s] *(1/57.29578) [1/deg/rad]

Written easier:

conversion = 5.0 [v] * (1/1024.0) [1/LSB] * (1/15) [1/mV] [deg/s] * (1/57.29578) [rad/deg]

Reordering:

conversion = 5.0*(1/1024.0)*(1/15)*(1/57.29578)[1/LSB][v][1/mv][deg/s][rad/deg]

Canceling dimensions:

conversion = 5.0 * (1/1024.0) * (1/15) * (1/57.29578) [1/LSB][1/m][rad/s]

Canceling [1/LSB] and [1/m]:
ADC output: x [LSB], where LSB stands for Least Significant Bit,
Use a multiplier of (1000/1000) for canceling [1/m] as m = 10^(-3), so:
y = x [LSB] * conversion
That is:

y = x [LSB] * 5.0 * (1/1024.0) * (1/15) * (1/57.29578) * (1000/1000) [1/LSB][1/m][rad/s]

FINALLY:

y = x * 5.0 * (1/1024.0) * (1/15) * (1/57.29578) * 1000 [rad/s]

Now y is [rad/s] and ready to integrate to compute the angle, say:
angle [rad] = angle [rad] + y [rad/s] * dt
-----------------------------------------------
radian-degree conversion:
360 [deg] = 2 * PI [rad]
1 = 180/PI [deg/rad]
1 = 57.29578 [deg/rad]
-----------------------------------------------
I hope that this helps a novice like me to fully understand the dimension canceling hided. My IMU is the same as what used for this nice balancing robot of the post.
~~http://www.sparkfun.com/commerce/product_info.php?products_id=9249~~
-----------------------------------------------

Hi,

have build yet another balance bot... well, it dies trying so far...

have a kalman filter and a PID controller.

The kalman works a treat, as I can see on PC. The PID works fine as well, except that I dont seem to get the K values right, everytime it seems to get better, I change a bit and its worth again, it drives me crazy.

has someone a hint how the Kp Ki and Kd values are in relation to each other? Maybe some example values would be nice to have something to compare.

I get a bluetooth chip tomorrow, I plan to controll the values wirelessly... its so timeconsuming to always reflash the arduino with new totally guessed values.

thanks in advanced, Mulder

I have some example code of an MD23.h and MD23.cpp, it's not complete yet, but it is a good start.

I'll try to clean it up in the future, feel free to use and modify it.

I am trying to change the address on one of my MD25 from default to 0x59. not working, is there something U think I may have written wrongly? :-

#include "Wire.h"
#include <LiquidCrystal.h>
// Command byte
#define md25Address 0x58 // Address of the first MD25

int currentDeviceId = 0x58; //Current Address
int newDeviceId = 0xB1; //New Address

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // initialize the library with the numbers of the interface pins

void setup()
{
Wire.begin();
configureDeviceId;
}

void loop()
{

}

void configureDeviceId()
{
Wire.beginTransmission(md25Address);
Wire.send(16);
Wire.send(0xA0);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(md25Address);
Wire.send(16);
Wire.send(0xAA);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(md25Address);
Wire.send(16);
Wire.send(0xA5);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(md25Address);
Wire.send(16);
Wire.send(0xB1);
Wire.endTransmission();
}

Good job :stuck_out_tongue:

can you please state how much the project cost you and huch time it took from you?
thanks