Go Down

Topic: Balancing robot for dummies (Read 155609 times) previous topic - next topic

Jon D.

#150
Dec 14, 2010, 01:35 am Last Edit: Dec 14, 2010, 01:40 am by jondaeh Reason: 1
Okay, I actually solved my problem. I had forgotten to set the AutoZero pin to OUTPUT. This probably made it float, and messed up the measurement. Now the integrated angle is right! :)

However, this won't solve the integration problem on the FEZ Domino and the PIC32, as the AZ-pin were set as output there. But as the error in the integrated angle is about the same as I had with the floating pin it may give an idea of where to start looking! I won't discuss more about these microcontrollers in this thread, but if anyone struggles with this problem I will gladly try to help :)



Jon.

kas

@ Jon D
glad to see that you solved your problem
I like your object orientated way of programming, using classes
My bot is currently belly up, I will try your code as soon as I can.
Not sure if the words "FEZ" and "Domino" are allowed on this site  ;)


@ Onions
Hi welcome on the right thread  ;)

Quote
where you got the wheels? (A UK supplier would be nice!)
I got my wheels here
I am not familiar with UK suppliers (only this one , submitted by GuzZzt)
Others may jump in with additional links
- Rubik's cube Robot solver                 forum.arduino.cc/index.php?topic=271827.0
- Android Bluetooth joystick               forum.arduino.cc/index.php?topic=173246.0
- Balancing robot for dummies           forum.arduino.cc/index.php/topic,8871.0

beautifulsmall

Hello, the algorythams used so far give a balance for a fixed vertical but im interested in a way of constantly updating this. ie, not using vertical as the reference but using velocity =0 as a goal, im no mathematition but i can see angle is not fixed as any side load will offset this, and any robot that will be usefull needs to allow for new  uncentered loads..maybee a completely new algorythm is needed like fuzzy??, which i understand is basically a weighted decision tree, which seems to me more like a look up table. but maybee that is what is needed, a learning table that can be overwritten. I know ive spent many hours adjusting parameters which is impractical in a comertial product and the slight variations in a comertial product would dont allow fixed parameters, like wo-wee balancing bot was pulled from the market?? im just guessing because it didnt have the fire power to calibrate in a realistic time. Its nice to look at murata and honda and still see there no better than us amateurs!.im very impressd by the recent micromouse maze solvers in 11 secs. but back to balancing, even my dspic 33 at 1.7dmips runs out of steam when balancing and doing math for mapping / need the blackfin 592 as co pro, then get some visual data , and we are really talking about a bot that can manouver and follow a ball.but blackfin is not accesable !!! to the masses , ive got one and i cant bloody program it .
its a nice data in , data out chip but the sw is $7000 ! stupid company,
Give me the tools and ill build you a pyramid ( dohh, its dark in here) ;D

psychoul

#153
Dec 17, 2010, 07:35 am Last Edit: Dec 17, 2010, 01:13 pm by psychoul Reason: 1
By my understanding, in order to control the velocity (and make it zero according to you) you need a way to measure it or approximate it. The accelerometer/gyro setup gives you angular acceleration and angular velocity which is created because of the rotation of the chassis of the robot around the wheels axis. If I understand it correctly, you cannot get any velocity information out of that.

One sensor that is used for approximating the velocity of a robot is the wheel encoders (mentioned a while back in this thread), where you get revolutions/time which is velocity.

You mentioned fuzzy, I believe that is just a different way of controlling the input. If you don't have the correct feedback you can't control it anyway.

kas

Quote
Hello, the algorythams used so far give a balance for a fixed vertical but im interested in a way of constantly updating this. ie, not using vertical as the reference but using velocity =0 as a goal, im no mathematition but i can see angle is not fixed as any side load will offset this, and any robot that will be usefull needs to allow for new  uncentered loads...
velocity = 0, or for RC control, velocity = "RC's value"
I like your idea of controlling velocity rather than angle.

Thinking twice, in fact, with encoders, PID algorithm is fed with both angle and velocity data:  :-?
Code: [Select]
int updatePid(int targetPosition, int currentPosition)   {
 int error = targetPosition - currentPosition;
 pTerm = Kp * error;
 integrated_error += error;                                      
 iTerm = (Ki/5) * constrain(integrated_error, -GUARD_GAIN, GUARD_GAIN);
 dTerm = Kd * (error - last_error);                            
 last_error = error;
 pTerm_Wheel = Kp_Wheel * count;          
 dTerm_Wheel = Kd_Wheel * (count - last_count);                            
 last_count = count;
 return -constrain(K*(pTerm + iTerm + dTerm + pTerm_Wheel + dTerm_Wheel), -255, 255);
}


I am not too familiar with fuzzy logic; do you have code snippets to submit??



Quote
By my understanding, in order to control the velocity (and make it zero according to you) you need a way to measure it or approximate it. The accelerometer/gyro setup gives you angular acceleration and angular velocity which is created because of the rotation of the chassis of the robot around the wheels axis. If I understand it correctly, you cannot get any velocity information out of that.
One sensor that is used for approximating the velocity of a robot is the wheel encoders (mentioned a while back in this thread), where you get revolutions/time which is velocity.

psychoul, you are right, you cannot get any velocity information out of a Gyro/Acc combo.
Without at least one encoder you get only basic balance.
Encoder is definitly needed to remove foward/backward drift

- Rubik's cube Robot solver                 forum.arduino.cc/index.php?topic=271827.0
- Android Bluetooth joystick               forum.arduino.cc/index.php?topic=173246.0
- Balancing robot for dummies           forum.arduino.cc/index.php/topic,8871.0

Jon D.

#155
Dec 19, 2010, 05:22 pm Last Edit: Dec 19, 2010, 05:23 pm by jondaeh Reason: 1
@beautifulsmall
A way to make a balancing robot stand still, is to use a state-feedback controller. Basiclly, what you do is to decide what "goals" you want to have for the system, like angle=0, (angle d/dt)=0, (angle-integrated)=0 and motorspeed=0. By measuring or estimating these values(or states) you make a proposional-controller for each of them, and sum up the result from each term and use this as the controlinput for the motors. This is essentially what kas has done when feedbacking the encoder data and the (estimated) derivative for it.

Usually, you want to take base in a mathematical model for the dynamics of the robot when using this approach, as the correct amplificationfactors can be hard to find. With this model you can use pole-placement or LQR-design and decide how you want the robot to react, and then(with a lot of luck) get it that way. If someone is interested, this side gived a good desciption of this methods. I also think there is an example of how to make model of a inverted pendulum(essentially a balancing robot).  

http://wikis.controltheorypro.com/

This method(also called modal-controller) was our plan to use when making the balancingrobot at school. The problem is that we didn't have encoders on the motors, and therefor we tried to assume that the speed of the motors were equal to the input to the motorcontroller(speedservo principial). But as it turned out that the motors had a much bigger time-to-rise than we thought, this wasn't good enough. A solution could have been to use a estimator(as proposed here by psychoul) to estimate the speed of the motors. This again requires a mathematical model for the motors, which we didn't have.

The last update for this robot is that I have shortened is down to make it look more like a "normal" balancing robot, and I have now got it pretty stable using PID controller. Then I know it works :) The plan for this christmas is to update the mathematical model for the shortened version, try to find a how the motors behave and make some sort of an estimator for the motorspeed, to come around the lack of encoder. Can be interesting to see if it will work!

However, when reading your post, I get the impression that what you want the robot to do is to make it a goal to stand still, and then make it "discover" that this can only be achived by making the angle equal zero(or rather equalibrium). To achive this my guess is you will have to use some sort of a neural network or(as you mentioned) fuzzy logic or other adaptable algorithm. This is basiclly something that continuous udates the controller parametres and the equalibrium-angle based on how the system seems to act. This makes it possible to put a weigth on top of the robot, and thereby change the equalibrium angle and the dynamic of the robot, and the controller will automaticlly be tuned to cope with the change. Really cool! The arthour of this youtube video seems to be using a kalmanalgorithm to obtain dynamic equalibrium angle.
http://www.youtube.com/watch?v=dQWATsLa30g
and another video of a inverted pendulum controlled using some sort of adaptive algorithm:
http://www.youtube.com/watch?v=Ci_y14y3DU4
But as I have no experince with adaptive algorithms, what I have said on these few lines is pretty much all I know. Hope someone can jump in and write some complementary lines about this intriguing field :D!

Well, again I managed to do a lot of talk here. Hope someone can find some of it interesting. I have been working on projects like this for quite a time now, and I have made myself a lot of thoughts about the field of system control :P

@kas -> beautifulsmall
Yes, a codensnippet of some fyzzylogic would be great! :D


cheers!
Jon, Norway

kas

@beautifulsmall
@Jon D.
Now, this thread is getting interesting   :P :P
- Rubik's cube Robot solver                 forum.arduino.cc/index.php?topic=271827.0
- Android Bluetooth joystick               forum.arduino.cc/index.php?topic=173246.0
- Balancing robot for dummies           forum.arduino.cc/index.php/topic,8871.0

kas

Quote
Hi.

Great guide to balancing robots. Its nice of you to share detailed "how to" info. i especially like your zeroing out imu.

that said, i also have critisizm. Your explanation of the PID regulator is thurough, but faulty. The theory is right, but in your implementation, its all messed up. you forgot a critical part of the regulator.

Let me explain:

P = E, where E is the error, and Kp is the propotional gain.
I = I + E*dt, where dt is time between your samples(looptime).
D = (E - last_E)/dt, which gives you the change with respect to time.

BUT, earlier, you define your looptime as 10ms, so, if your looptime is always 10ms, the above is not nessesary. another BUT, is that if youre looptime exeeds 10ms, the above will work better.

I dont intend to be a knowitall, i'm just trying to help.

Btw, i also used tom pycke's guide to kalman. there i also have a trick that might help. I used serial to log accangle, gyrorate and dt, and then wrote the filter in matlab. there i could tune the filter using the samples(imported as an array of data to matlab). worked great. super fast tuning. you probably dont need to know, but if others use different sensors with different noise, its a really great way to test and tune.

again, thanks for sharing. lots of great info in your tutorial.

Hi danielaaroe, thanks for your comments

Quote
P = E, where E is the error, and Kp is the propotional gain.
I = I + E*dt, where dt is time between your samples(looptime).
D = (E - last_E)/dt, which gives you the change with respect to time.
That the way it should be
I use the actual looptime (lastLoopTime) to feed the Kalman function
for the PID, I opted for speed optimization
Looptime is fixed, so dt is omitted and included in the Ki and Kd values
Pro:
- faster code
Cons:
- changing Loop time implies to modify both Ki and Kd values
- One as to make sure that lastLoopTime does not exceed STD_LOOP_TIME (10ms)

Code: [Select]
void loop() {

 ................................


// *********************** loop timing control **************************
 lastLoopUsefulTime = millis()-loopStartTime;
 if(lastLoopUsefulTime<STD_LOOP_TIME)         delay(STD_LOOP_TIME-lastLoopUsefulTime);
 lastLoopTime = millis() - loopStartTime;
 loopStartTime = millis();
}

Within my specific implementation lastLoopUsefulTime is 4ms, so I am safe
Problem could arise at the debugging stage, with several Serial.print() statements within the loop.
- Rubik's cube Robot solver                 forum.arduino.cc/index.php?topic=271827.0
- Android Bluetooth joystick               forum.arduino.cc/index.php?topic=173246.0
- Balancing robot for dummies           forum.arduino.cc/index.php/topic,8871.0

kas

Hi beautifulsmall,

I have "off" discussions with Jon D. via PM
He purchased those motors (w/o encoders)

Quote
Yes, applying encoders is definitely the easiest and most accurate solution.
If beautifulsmall succeeds with this I'm absolutely interested in it!
The reason I want to make a estimator is mostly to use some of the theory we have learned at school in practice.
I just think it's very fascinating when these things actually works Having both an estimator for motorspeed and
encoders would be really cool, to be able to compare the result! Well, that project will have to wait until next step

I mentioned your ADNS-7550 project
Any possibility to include Jon D. as another beta tester ??  ;)
- Rubik's cube Robot solver                 forum.arduino.cc/index.php?topic=271827.0
- Android Bluetooth joystick               forum.arduino.cc/index.php?topic=173246.0
- Balancing robot for dummies           forum.arduino.cc/index.php/topic,8871.0

Paul02

#159
Dec 23, 2010, 05:01 pm Last Edit: Dec 23, 2010, 05:04 pm by Paul02 Reason: 1
Thanks for all the great information here!  I'm new to using motor drivers and have a question on how to choose the correct power supply for this application.  I'm using the same 29:1 Pololu gearmotors with a dual motor driver capable of 2.5A continuous and 5A peak output per channel.

My original thought was to use a 12V 5A power supply, but after some forum searching I've read that the motors could draw up to twice the stall current if commanded to switch from full forward to full reverse (for a total of 10A between the two motors).

When picking a power supply for the balancing bot is that 10A the current capacity I need to be accounting for (so then a 12V 10A source?) or since that maximum will probably not be experienced would the 12V 5A work fine?

My other source of consternation is in regards to using a battery to power the unit.  I've found many 12V 3800mah batteries from ebay sellers, but no maximum current is listed for them.  Is it just safe to assume any 3800mah rating means the battery would be able to discharge 10A for 3.8hours?

Thanks to anyone for help with these newbie questions.  I'll edit this with a link to the specific battery / power supply that I'm looking at when I can post a link.

Jon D.

@Paul2
Yes, you are right. The biggest load the motors can pull is 5A each. However, as you are not(hopefully) planning to hold them from turning, they will never pull this much more than for an very short moment. Assuming then you are gonna use them in a balancing robot, which weight isn't of to big dimensions.

You don't say what type of battery you are gonne use, Nicd/NiMh or LiPo. I have always used LiPo for my projects, as they deliver very stable voltage as they don't drop so much as they get charged out, and they are quick to recharge. Drawback is that they can not be completely emptied, as they then will be damaged.

I have no experience with NiCd/NiMh batteries, but what you are gonna look for on a LiPo-battery is a rating "C". It says many amperes it is able to deliver, respective to it's capacity. For example, if the battery you are reffering to is rated with 10C, it is able to deliver 3800mah * 10 = 38A continusly. Usually the battery also got a peak-rating,  wich works the same way only that this current can only be delivered for a short amount of time.

If you are new to these kind of batteries it is worth noting that the 2-cell LiPo(2S) is 7.4V and 3-cell(3S) is 11.1V. However, fully charged they measure about respecitve 8.4V and 12.6V, so the last works great on 12V motors.

On my robot a use a battery similar to this one for driving the motors:
http://hobbycity.com/hobbyking/store/uh_viewItem.asp?idProduct=9163
And something like this one to supply the Arduino, Xbee etc.
http://hobbycity.com/hobbyking/store/uh_viewItem.asp?idProduct=9170

The reason I'm using two separate battrypack for driving the motors and the electronics, is to try to avoid noise. The negative pole for both batteries is connected through a 100K resisitor to provide common "ground". Don't know if the motordrivers produces so much noise that this is necessary, though..

Well, good luck Paul2, and merry christmas to you all!


Jon, Norway.

richiereynolds

#161
Dec 24, 2010, 01:53 pm Last Edit: Dec 24, 2010, 01:55 pm by richiereynolds Reason: 1
Folks, hoping for some tips. I've built a balancing robot using an IMU 5DOF, the MD25 motor controller and EMG30s but the motors simply don't seem to respond quickly enough.
I've pretty much used the code being discussed on this thread with a few exceptions -
I'm using an arduino mega so have used the internal ref voltage of 2.56V and the amplified gyro outputs on the IDG500 so my gyro conversion looks like this:

Code: [Select]

int getGyroRate()
{    
   return int(sensorValue[GYR_Y] * 0.781440781);  // in quid/sec:(1024/360)/1024 * 2.56/0.0091)
}


I'm using I2C for the motor controller which needs a 0 to 255 where 128=stopped so to get my drive value I do:
Code: [Select]

int updatePid(int targetPosition, int currentPosition)  
{  
   int error = targetPosition - currentPosition;
   pTerm = Kp * error;
   integrated_error += error;
   iTerm = Ki * constrain(integrated_error, -GUARD_GAIN, GUARD_GAIN);
   dTerm = Kd * (error - last_error);
   last_error = error;
   
   int x = -constrain(K*(pTerm + iTerm + dTerm), -255, 255);
   x /= 2;
   x += 128;  
   return x;
}


When calibrating my sensors and getting readings I disregarded any outliers:
Code: [Select]

int compare (const void * a, const void * b)
{
   return ( *(int*)a - *(int*)b );
}

void calibrateSensors()
{
   int allVals[50];  
   long v;
   
   for(int n=0; n<3; ++n)
   {
       v = 0;
       for(int i=0; i<50; ++i)      
       {
           allVals[i] = readSensor(n);          
       }
       qsort(allVals, 50, sizeof(int), compare);
       
       for(int i=5; i<45; ++i)
       {
           v+= allVals[i];
       }
       sensorZero[n] = v/40;
   }
   sensorZero[ACC_Z] -= 137;
}

void updateSensors()
{
   int allVals[5];
   long v;
   for(int n=0; n<3; ++n)
   {
       v = 0;
       for(int i=0; i<5; ++i)      
       {
           allVals[i] = readSensor(n);
       }
       qsort(allVals, 5, sizeof(int), compare);
       
       for(int i=1; i<4; ++i)
       {
           v+= allVals[i];
       }
       sensorValue[n] = v/3 - sensorZero[n];
   }
}


I also timed my loop over 1000 iterations and found it took about 3.5ms per iteration so I've tried setting the STD_LOOP_TIME to 5 but it didn't help.

My angles look pretty good and if I print out the time, angle and drive as they change they look ok though the time is slowed down by the printing.
However, if I let the robot go from vertical I can see it's almost beyond the point of no return before the motors kick into life.
If I stop it falling too far on each side by hand I can see that the motors are doing the right thing, just not quick enough.
I've mainly just tried increasing the P val for pid so far, I and D are 0, though I've tinkered there too with no joy.

I don't know much about I2C, could it be just to slow for this task? Surely the EMG30s are up to it?

Appreciate any advice!

Jon D.

@richiereynolds
Quote
I don't know much about I2C, could it be just to slow for this task? Surely the EMG30s are up to it?

I'm sure I2C is fast enough, it's used widely in gyros and accelerometers with success, so it should work the other way(as output, that is) too. The motors seem pretty similar to pololu motors, and looking at the specifications they should be good for the purpose.

Quote
However, if I let the robot go from vertical I can see it's almost beyond the point of no return before the motors kick into life.
If I stop it falling too far on each side by hand I can see that the motors are doing the right thing, just not quick enough.

I have noticed that these motors typically have some delay before they actually starts turning. That means they doesn't start when you apply "1" to the motordriver, but not until you apply "5" or something. This implies that the robot has to "fall" longer until a standalone P-val will get a big enough value to start turning the motors. I solved this by making a offset, so that when the PID-controller puts out "1", the motors will start turning. This is the code I use for driving the motors:

Code: [Select]
void MotorDriver::setMotor(signed int setting)
{
  if(setting > 0) setting += 4;//Increase for bigger offset on the + side
  else if(setting < 0) setting -= 4;//Increase for bigger offset on the - side
 
  if(setting > 100) setting = 100;
  else if (setting < -100) setting = -100;
 
  setting = setting * 1.27;
  analogWrite(5, -setting + 127);
  analogWrite(6,  setting + 127);
  analogWrite(9,  setting + 127);
  analogWrite(10,-setting + 127);
}


Try experiment with different offsets, the weight of the robot and size of the wheels can make the dynamic differ.  

The argument for this function should here be -100 -> +100, but you get an idea for what I'm doing :)

@All
I have now hosted my balancerobot code, if anyone is interested :)
http://code.google.com/p/veltobot/


Jon, Norway


richiereynolds

Thanks! I'll give those ideas a go and let you know how I get on.

beautifulsmall

Kas, Jon-D, theres a good few links there i need to look up, thanks. as for fuzzy i have not tried it but there is a pic app note i will try to post the link for.
RE ADNS-7550 laser optical mouse encoder as a velocity encoder:
so far i have placed the encoder over a flat belt which is connected to a motor which has a heds slotted disk encoder fitted  therefore i get quadrature encoder data to compare with the optical .
1. at constant velocity the two encoders give an average velocity which is comparable within roughly 10%.
2. the optical encoder gives an erratic reading , over and under the heds encoder.
3. for zero velocity both read zero
4. for very low velocity, 1mm/sec the optical reads zero !
5. for absolute position , ie step changes, the optical very quickily has a large error. this can be tested with a pc mouse, just try to move it repeatedly back to a fixed position and see where the arrow ends up!

I emailed AVAGO with these findings and asked if the sensor has a high pass filter, they said they dont spec low speed, also the absolute accuracy is only 20-30% ! shock. also (area of image is < 2mmsq)
despite this im not giving up hope.
it is possible to read the pixel image data, if a pattern is used where the absolute dimensions are known then surely a more accurate calculation can be done. and don't call me shirley.
I asked if the ADNS-9500 super gaming sensor was any better but no mention was made in their reply, and you cant get one for love or money, same family anyway but it does need a firmware download so theres hope for a special version ?
It may be that my 7550  just didnt have the right surface but one register reports surface quality , i never got better than 75%, i tried
black htd M3 belt- raw - 0%
lightly sprayed with gold xmas metallic - 75%
any colored card 50%
aluminium foil - rubbish
embossed plastic metallized sheet - 30 %
white card with very fine black fibers - 30 %  
I still need to test a lumpy dull surface. Ill try it on my brothers wife .

RE motor drivers, check that acceleration control is turned off, current limit, all the saftey features!, im just building with a new one, vn??
merry xmas everyone, :) :)


Go Up