I am using the BMP085. I have now observed the output in different conditions for a while.
- The output is quite noisy
- It has reaction times of 0.5 to 2 seconds (I don't know why, but sometimes it is faster, other times slower)
- Sometimes the altitude jumps 2m for a couple of seconds, the jumps back, when the copter is sitting on the ground
I have now done several things:
1. Average the signal. I am only changing the old value, if I see, there are 10 more samples with the difference in one direction than the other:
Code: Select all
void Baro_update() {
...
switch (bmp085_ctx.state) {
case 0:
if ((itemp++ & 0x3) == 0) { // get Temp only every 4th cycle
i2c_BMP085_UT_Start();
bmp085_ctx.state++;
bmp085_ctx.deadline += 5000;
}
else {
bmp085_ctx.state = 2;
}
break;
case 1:
i2c_BMP085_UT_Read();
bmp085_ctx.state++;
break;
case 2:
i2c_BMP085_UP_Start();
bmp085_ctx.state++;
bmp085_ctx.deadline += 26000;
break;
case 3:
i2c_BMP085_UP_Read();
i2c_BMP085_Calculate();
xalt = (1.0f - pow(pressure/101325.0f, 0.190295f)) * 4433000.0f;
a_alt[ialt++] = xalt;
if (ialt == ALTS) {
ialt = 0;
}
if (xalt >= BaroAlt) {
count++;
}
else {
count--;
}
if (abs(count) > 10) {
BaroAlt = 0;
for (int i = 0; i < ALTS; i++) {
BaroAlt += a_alt[i];
}
BaroAlt /= ALTS;
count = 0;
}
bmp085_ctx.state = 0;
bmp085_ctx.deadline += 2000;
break;
}
}
2. Average the temperature value of the sensor
Code: Select all
void i2c_BMP085_Calculate() {
...
b5 = x1 + x2;
if (mb5 == 0) {
mb5 = b5;
}
mb5 = (5 * mb5 + b5) / 6; // A little averge to remove noise
// Pressure calculations
b6 = mb5 - 4000;
...
3. The P Term now works as follows:
- Increase/Decrease the throttle by a fixed amount (I use the Alt-D for this)
- The increase is done for a time proportional to the altitude error (Scalable with ALT-P)
- Turn off the throttle chnage and wait for one second to get a good sensor value
4. The I-Term is done normal with 300 ms cycle time
Code: Select all
if(BARO) {
if (baroMode) {
if (abs(rcCommand[THROTTLE]-initialThrottleHold)<20) {
if (currentTime > next_itime) {
next_itime = currentTime + 300000;
error = AltHold - EstAlt;
EstAltI += constrain(error, -50, 50);
EstAltI = constrain(EstAltI,-30000,30000);
AltITerm = constrain((int32_t)I8[PIDALT] * EstAltI /20000, -70, 70);
if (pstate == 0) {
abserr=abs(error);
if (abserr > 10) {
pstate = 1;
AltPTerm = D8[PIDALT] * (error/abserr); // Increase/decrease the throttle with a fixed amount
next_ptime = currentTime + 200L * P8[PIDALT] * constrain(abserr,-1000,1000); // Time is proportional to error
}
}
}
if ((pstate > 0) && (currentTime > next_ptime) ) {
if (pstate == 1) {
AltPTerm = 0;
pstate = 2;
next_ptime = currentTime + 1000000; // Now a pause to get a useful baro reading
}
else {
pstate = 0;
}
}
AltPID = AltPTerm + AltITerm;
rcCommand[THROTTLE] = initialThrottleHold + AltPID;
}
}
}
With this, I have a not very elegant, but working altitude hold without increasing oszillation. The advantage for me at the moment is: I have an audible feedback due to the hard throttle changes, where the estimated altitude is.
I have done this on base of 1.9
http://dl.dropbox.com/u/60532252/alt_20120219.diffhttp://dl.dropbox.com/u/60532252/MultiW ... 120219.rar -> Use this only for reference there are some other changes in there, which might not ok for you...
Start with ALT P 3.0, I 0.100, D 30
Maybe this works for you too....
Best regards
Peter