@martinez:
"Im Ernst, ihr habt es echt drauf!!!".
Ich leider nicht, sonst wäre das Problem gelöst!
@DeaconBlues
Wie sind Deine Erfahrungen mit der "Modifikation im Sinkflug das Pid abzuschwächen" ?
In der Zwischenzeit war ich nicht untätig.
Der Stand der Dinge:
1. Die Auslesegeschwindigkeit von netto 10Hz (100ms) habe ich auf 33Hz steigern können (
0ms) für den BMP. Deswegen gibt es auch keine Bügeleisenkurve mehr. Der Baroauslesecode (BMP&MS) hat eine deutliche Macke, er bezieht seine Zeit von der Variablen "currentTime". Diese wird jedoch nur einmal pro Durchlauf (ca. 4ms) aktualisiert. D.h. die Baro_update() kann nach meiner Auffassung nicht richtig funktionieren, da die Wartezeit (z.B 4,5 ms nach dem Temp Auslesen) dann zu kurz ausfällt, da diese 4,5ms einfach zu currentTime dazu addiert werden, und leider schon eine unbestimmte Zeit unbemerkt von "currentTime" verstrichen ist. Der Sensor wird ggf. zu schnell belagert, was zu Datenfehlern führen kann.
Alternativ kann man micros() benutzen um die tatsächliche Programmlaufzeit in Mikrosekunden zu bekommen. Vorschlag:
Code:
void Baro_update()
{
if (micros() < bmp085_ctx.deadline) return;
TWBR = ((16000000L / 400000L) - 16) / 2; // change the I2C clock rate to 400kHz, BMP085 is ok with this speed
switch (bmp085_ctx.state)
{
case 0:
i2c_BMP085_UT_Start();
bmp085_ctx.deadline=micros()+4500-1;
bmp085_ctx.state++;
break;
case 1:
i2c_BMP085_UT_Read();
i2c_BMP085_UP_Start();
bmp085_ctx.deadline=micros()+13500-1;
bmp085_ctx.state++;
break;
case 2:
i2c_BMP085_UP_Read();
i2c_BMP085_Calculate();
BaroAlt = (1.0f - pow(pressure/101325.0f, 0.190295f)) * 4433000.0f; //centimeter
newbaroalt=1;
bmp085_ctx.state=0;
break;
}
}
2. ACC & Baro
Es ist mir gelungen, schnelle Auf- und Abbewegungen mit dem ACC deutlich zu unterdrücken. Der Code ist nicht besonders kompliziert, aber IN DER HAND sehr wirkungsvoll. Praxistest steht wg d. Wetters aus.
Prinzip: In der Zeit ohne neue Barowerte (20-30ms) werden dauernd die Z Beschleunigungen relativ zur Ruhe (1 G Erdbeschleunigung) gemessen und nur die Extremwerte gespeichert (AccZLowest,AccZHighest). Ein Mittelwert ist nicht so gut, da z.B am Ende einer Beschleunigung die Werte negativ werden. Ich habe mir folgendes überlegt:
A. Wenn man die maximale Negativbeschleunigung als Absolutbetrag von der maximalen Positivbeschleunigung abzieht, sollte die Vorzugsrichtung (bei horizontalem copter) zu erkennen sein d.h. +/- steigen/sinken.
B. Wenn man jetzt die Gesamtamplitude (also einfach beide Absolutwerte addiert) nimmt, hat man die Stärke der Veränderung.
Wenn man A*B*Skalierungsfaktor von den "BaroPIDs" abzieht, kommt das gut hin.
Umsetzung:
Die Schwierigkeit liegt natürlich in der Einstellung des Skalierungsfaktors. Man will nicht immer neu kompilieren müssen um den Wert eben schnell zu ändern. Da ich in der GUI das D von YAW nicht benutze, habe ich es dafür zweckentfremdet. Jetzt kann man über das "D" bei "YAW" in der GUI oder dem LCD diesen Faktor einstellen. Ich skaliere noch um den Faktor 40. D.h. bei 20 kommt die Hälfte des errechneten Wertes durch, bei 40 alles, und bei 80 das doppelte. Setzt man D auf 0 kommt kein ACC Z mehr in die "BaroPIDs". Das echte D von YAW wird im Code auf 0 gesetzt. Die Lösung ist natürlich "dreckig". Ausserdem habe ich die Funktion auf den Levelmode begrenzt d.h. auf einen möglichst horizontal liegenden copter, weil ich den resultierenden Vektor bei Schieflage nicht berechnen kann.
3. Steuerverhalten / Neue Höhe
Das Kämpfen mit dem Throttlestick gegen die BaroPID und den ACC Z müsste jetzt weg/reduziert sein. Der BaroPID müsste jetzt leicht zu übersteuern sein. Variometerfunktion ist nicht umgesetzt.
4. Irgend etwas aus dem RC Code stört weiterhin empfindlichst die Barokurve. Mittlerweile glaube ich fast, dass es ein Hardwareproblem mit meinem Setup ist.
Bei erfolgreichem Praxistest gibts hier natürlich einen Download!
LG
ROB
P.s.: Hoffentlich funktionierts auch in der Luft!
Aktueller Stand der getEstimatedAltitude().
Diesen Code NICHT so einbauen, da im Hauptprogramm noch das YAW D jeweils gerettet werden bzw. auf 0 gesetzt werden muss.
Code:
///////////////////////////////////////////////
//Crashpilot1000 Mod getEstimatedAltitude ACC//
///////////////////////////////////////////////
#define UPDATE_INTERVAL 20000 // Means: Dont be faster (next Gen Sensors?) than this, because ACCZ needs values
#define BARO_TAB_SIZE 40 // 40 Values for moving average
//#define PIDVEL 30 // Strength of ACCZ IS DEFINED BY YAW D in the GUI! DIRTY HACK
void getEstimatedAltitude()
{
uint8_t index;
static uint32_t deadLine;
static int16_t BaroHistTab[BARO_TAB_SIZE];
static int8_t BaroHistIdx;
static int32_t BaroHigh,BaroLow;
static int16_t AccZLowest,AccZHighest; // ACCZ extremes
int32_t temp32;
int16_t last;
last = accADC[YAW]-acc_1G; // So UPacc is +, DWNacc is -
if (last > AccZHighest) AccZHighest=last; // Set new ACC Extremes
if (last < AccZLowest) AccZLowest=last; // Every run till next calc, at least while UPDATE_INTERVAL
if (newbaroalt==1) // Update only, if new Baro-values are available
{
newbaroalt = 0; // Reset Boolean
last = BaroHistTab[BaroHistIdx]; // Do Baro Moving Average & calculate speed for D calculation
BaroHistTab[BaroHistIdx] = BaroAlt/10;
BaroHigh += BaroHistTab[BaroHistIdx];
index = (BaroHistIdx + (BARO_TAB_SIZE/2))%BARO_TAB_SIZE;
BaroHigh -= BaroHistTab[index];
BaroLow += BaroHistTab[index];
BaroLow -= last;
BaroHistIdx++;
if (BaroHistIdx == BARO_TAB_SIZE) BaroHistIdx = 0;
if (currentTime < deadLine) return; // Break, if too fast
deadLine = currentTime + UPDATE_INTERVAL;
EstAlt = BaroHigh*10/(BARO_TAB_SIZE/2);
newestalt=1; // Indicate, new EstAlt RDY
BaroPID = 0; // Calculate new PIDs
//D
temp32 = conf.D8[PIDALT]*(BaroHigh - BaroLow) / BARO_TAB_SIZE;
BaroPID-=temp32;
temp32 = AltHold - EstAlt;
if (abs(temp32) < 10 && abs(BaroPID) < 10) BaroPID = 0; //remove small D parameter to reduce noise near zero position
//P
BaroPID += conf.P8[PIDALT]*constrain(temp32,(-2)*conf.P8[PIDALT],2*conf.P8[PIDALT])/100;
BaroPID = constrain(BaroPID,-150,+150); //sum of P and D should be in range 150
//I
errorAltitudeI += temp32*conf.I8[PIDALT]/50;
errorAltitudeI = constrain(errorAltitudeI,-30000,30000);
temp32 = errorAltitudeI / 500; //I in range +/-60
BaroPID+=temp32; // BaroPID +/-210
// ACCZ
if (rcOptions[BOXACC]){
temp32 = AccZHighest-abs(AccZLowest); // temp32 is neg when dropping
last =abs(AccZHighest)+abs(AccZLowest); // "last" stores the Amplitude
temp32 = temp32*last; // Bigger Amplitude, bigger Correction
BaroPID -= (int32_t)conf.D8[YAW]*(temp32)/40; // conf.D8[YAW] Is scalefactor for ACCZ, if it is = 40 then this is 1:1 Passthrough
BaroPID = constrain(BaroPID,-310,+310); // +/- 100 (for ACC Z)
}
AccZHighest=0; // Reset Values anyway
AccZLowest=0;
}
}
PPS: Hier
http://code.google.com/p/multiwii/downloads/detail?name=MultiWii_dev_20120606.zip&can=2&q=
ist die neu MultiWii_dev_20120606.zip, die vor allem das Magnetometer verbessert. (Leider nicht Baro...)