Hallo oberallgeier,
schön, dass du die Zusammenfassung geschrieben hast, die wir am Form vorbei angesprochen hatten.
Zwei Dinge scheinen mir also noch nicht so richtig zu gehen:
1) Die Zeit die du für den Regelvorgang benötigst ist zu lang.
2) Abweichungen auf einer Seite führen zu einem Winkelfehler.
---- Ding 1
Ich denke, dass die Rechenzeit für Problem 1) an der falschen Stelle verbraucht wird.
Nun wird mir auch klar, warum du in diesem Thread nicht auf meinen Hinweis mit den char- bzw. int-Variablen und dem cli(); bzw. sei(); eingehen wolltest. (Jubel, jetzt habe ich deinen Ablauf möglicherweise auch verstanden.)
In deiner oben gemachten Angabe mit
Code:
---C---1---2---3---4---5---6---7---8---9---A---B---C---1---2---3---4--> >
| | v | |
| v AR *) Mot34 | v
v AR Mot 12 v AR Mot 12
Auslesen des ADC/Sharp Auslesen des ADC/Sharp
*) AR: Aufruf der Regelungsroutine
und der ISR(ADC_vect)
Code:
/*
============================================================================== */
/* === Nicht unterbrechbare ISR für ADC3 auf Pin 26/PC3/mega168 =============== */
ISR(ADC_vect) // _VECTOR(21)
{
- - - -
if (adc3_cnt == 4)
rgl_mo_12(); // Aufruf Regeln für mo_12
if (adc3_cnt == 8)
rgl_mo_34(); // Aufruf Regeln für mo_34
- - - -
}
/* ============================================================================== */
liegt das Problem darin, dass du die Rechenzeit in der Interruptfunktion benötigst.
Wie vor langer Zeit mal bei dem "ASURO als Wecker" angesprochen, und von dir ja auch gelesen, solltest du im Interrupt nicht die Reglung durchrechnen, sondern nur eine "Aufforderung" für das Hauptprogramm setzen.
Und diese "Aufforderung" dann im Hauptprogramm bearbeiten.
Aktuell hast du 2 Regler, die gerechnet werden wollen, also benötigst du natürlich auch 2 Variablen für die Aufforderungen.
ISR:
Code:
/* ============================================================================== */
/* === Nicht unterbrechbare ISR für ADC3 auf Pin 26/PC3/mega168 =============== */
ISR(ADC_vect) // _VECTOR(21)
{
- - - -
if (adc3_cnt == 4)
v_rgl_mo_12_knz = 1; // AUFFORDERUNG fuer Regeln für mo_12
if (adc3_cnt == 8)
v_rgl_mo_34_knz = 1; // AUFFORDERUNG fuer Regeln für mo_34
- - - -
}
/* ============================================================================== */
Und im Hauptprogramm:
Code:
main ()
{
Variablen ...
Init ();
while (1)
{
/*
Der AUFFORDERUNG folge leisten ;-)
*/
if (v_rgl_mo_12_knz == 1)
{
v_rgl_mo_12_knz = 0;
rgl_mo_12(); // Aufruf Regeln für mo_12
}
if (v_rgl_mo_34_knz == 1)
{
v_rgl_mo_34_knz = 0;
rgl_mo_34(); // Aufruf Regeln für mo_34
}
}
...
}
Und nun unbedingt in den Funktionen rgl_mo_xx() diese cli(); und sei(); um das "Abholen" der im Interrupt veränderbaren Variablen legen.
Was gewinnst du hierbei?
Du koppelst die Rechenzeit komplett aus den Interruptfunktionen aus. Dein Timer wird nun ohne Probleme seinen Interrupt in kürzester Zeit, ohne Verlust von weiteren anstehenden Interrupts, abarbeiten können.
==> Auch die im Timer-ISR hängende Funktion "Auslesen des ADC/Sharp" solltest du so auslagern.
---- Ding 2
Da wird es bei deiner Geschwindigkeitsreglung schon schwieriger.
Im Asuro werden die Rad-Tiks bzw. die Differenz zwischen ihnen mit nur einem Regler bearbeitet.
Du müsstest 'im Prinzip' eine mittlere Geschwindigkeit regeln und das Ergebnis entsprechend deinen Vorgaben für die rechte bzw. linke Seite verteilen.
Ein anderer Ansatz wäre z.B., dass du doch anfängst zu lügen, wie schon mal in diesem Beitrag angedeutet wurde.
Ich hoffe, nicht allzu viel Verwirrung gestiftet zu haben
Gruß
Sternthaler
P.S: Deine 'klau schau wem'-Aktion hast du gut umgesetzt. Ein bisschen verwirrend ist, dass du die Kp- und Ki-Parameter mit einer Division verrechnest. Ist zwar hier mathematisch i.O., aber eigendlich sollte da das '*'-en hin. Ansonsten musst du jedesmal in 1/K[parameter] denken.
Lesezeichen