Überlastung Atmega64

#3744888
Lesenswert?

Hallo,

ich entwickle momentan einen FlightController für meinen Quadrocopter.
Ich verwende für die Winkelbrechnung einen itg3205 und einen adxl345.
Der ATmega64 liest diese zwei Bausteine aus und berechnet daraus den 
aktuellen Winkel.
Zusätzlich liest er 4 PWM - Signale vom Empfänger mittels den externen 
Interrupt's aus.
Und schlussendlich erzeugt er 4 PWM - Signale für die 4 ESC's.

Ich habe alles einzeln geschrieben und getestet. Dort hat es immer 
funktioniert, jedoch wenn ich alles gleichzeitig ausführe stimmt der 
berechnete Winkel nicht mehr.
Meine Theorie dazu ist, dass der Interrupt (der von einem TimerOVF 
ausgelöst wird), durch die zusätzlichen Interrupt's, nicht mehr im 
gleichen Zeitabstand aufgerufen wird und das verfälscht den berechneten 
Winkel (den Winkel des Gyro's) sehr.

Stimmt diese Theorie bzw. wie kann ich dieses Problem lösen?
Würde es reichen, wenn ich die PWM Signale mittels einem externen 
Baustein's erzeuge, welcher mit I2C angesprochen wird?

Danke für eure Hilfe
#3744938
Lesenswert?

Steig beizeiten um auf was mit mehr Rechenleistung.
Könnte sein, dass du es rechenzeitmässig noch reingequetscht bekommst, 
bist aber von Anfang an am oberen Limit - nicht gut. Es kommen ständig 
neue Sachen hinzu :-)
Ich habe sowas mal gemacht, allerdings für einen echten Helikopter 
(könnte mir vorstellen, dass ein Quadrokopter etwas einfacher zu steuern 
ist), die erste Version Mit ATMega ging in die Hose...
STM32 war prima.
#3744944
Lesenswert?

ja es ist aber so:
der Winkel stimmt solange die PWM - Signale einen HighPegel von 1.0 ms 
haben. (19 ms low)
erhöhe ich diese Zeit (gebe gas) stimmt er bei weiten nicht mehr.
darum dachte ich, dass das irgendwie zusammenhängt.

ich habe viele FlightController mit einen Atmega daraug gesehen, daher 
denke ich, dass es möglich ist.
aber sobald ich mehr Funktionen einbauen will, muss ich ziehmlich sicher 
alles anders aufbauen.
(Firma: Privat) #3744961
Lesenswert?

Versuch deinen Code um alles was geht zu optimieren. Das reine benutzen 
von Hardware sollte da keine Probleme machen. Wenn du dem Timer sagst 
welchen Wert du haben willst, sollte es alles weitere ohne dein Zutun 
erledigen.

Versuche den Code so zu schreiben, dass du nicht überwachen musst ob du 
Fehler dinn hast. Solche Überwachungen machen meist sehr viel aus. Ich 
hab früher auch in jeder Software ebene überwacht ob ich einen falschen 
Wert habe, wenn es jedoch wirklich darauf ankommt, mache ich das nur 
noch soweit oben wie möglich. Wieso sollte ich einen Wert der nicht 
falsch sein kann überprüfen?

Zeigt doch mal bitte deine Hauptschleife, vielleicht finden wir da noch 
n paar Sachen.
#3744963
Lesenswert?

Marcel,
ich hatte ein sehr ähnliches Problem. Ich würde an deiner Stelle eine 
extra Platine kaufen, durch serial oder I2C angeschlossen, mit der Du 
die Motoren ansteuern kannst. Der CPU wird somit entlastet und die PWM 
Signale der Steurungsplatine delegiert.
Durch diese Entkopplung solltest Du das Problem beseitigen können.

Gruß
#3745124
Lesenswert?

@ Marcel D. V. (dmarcel21)

>Das habe ich auch zusätzlich dazu geplant zu machen.
>ich werde aber auch versuchen den Code zu optimieren.

Das kommt später. Erstmal musst du MESSEN, um deine Vermutung zu 
untermauern oder zu widerlegen. Das kann man im ersen Schritt im 
Simulator machen. Aber das könnte schwierig werden, wenn man I2C 
Zugriffe simulieren will. Einfacher und schneller ist eine Messung am 
echten System mit einem Testpin, welcher immer dann auf HIGH geht, wenn 
der Controller aktiv was macht und wieder auf LOW, wenn eine Funktion 
etc. beendet ist. Damit kann man in Echtzeit die Rechenzeit der 
einzelnen Funktionen messen. Am Ende deiner Hauptschleife, wenn alle 
zyklischen Aufgaben erledigt sind, muss immer noch etwas Zeit übrig 
bleiben. Wenn nicht, ist dein Controller überlastet.

Man sollte aber nicht vergessen, dass es auch andere Fehlermöglichkeiten 
gibt. Z.B. dass deine Motortreiber deine Sensoren stören. Ein Oszi hilft 
hier auch ungemein.
#3745173
Lesenswert?

@ Marcel D. V. (dmarcel21)

>Das Problem ist das mein ganzer Code in Interrupts ist.

Kann sinnvoll sein. Aber umso einfacher kann man das messen bzw. Prüfen.

http://www.mikrocontroller.net/articles/Multitasking#Ein_einfaches_Beispiel_f.C3.BCr_den_AVR

3.Beispiel mit Timer.

"Es kann leicht im realen System geprüft werden, ob die Laufzeit der 
Tasks klein genug ist, um den Anforderungen des Timers zu genügen. "
Gast #3745179
Lesenswert?

> Das Problem ist das mein ganzer Code in Interrupts ist.
Schön, dass Du es erkannt hast. Das war der wichtigste Schritt. Nun mach 
es besser.

Lies Dich in das Thema "Zustandsautomat" ein und nutze Interrupts 
lediglich dazu, Ereignisse zu erfassen und in irgendwelche Variablen 
abzulegen, damit sie später in der (einzigen) Programmschleife 
abgearbeitet werden.

Sobald Deine Interrupt-Routine aus mehr als 10 Zeilen C besteht, 
solltest Du nachdenklich werden. Folgende Dinge haben in 
Interrupt-Routinen grundsätzlich nichts zu suchen:

- Display Ausgaben
- Divisionen mit Divisor ungleich 2, 4, 8, 16, ....
- Fließkommazahlen
- Wiederholschleifen
- Sleep Befehle

Lass mich raten: Du hast aon allem was dabei, oder?
#3745207
Lesenswert?

Marcel D. V. schrieb:
> Nein ganz so dumm bin jetzt auch wieder nicht.
> Ich habe keine Displayausgaben und Sleepbefehle in meinen Interrupts.
> Jedoch habe ich die Berechnungen vom Gyro in einem.
> Aber wie soll ich eine Berechnung, welche nur benötigt wird, wenn er den
> Gyro ausliest ausliest dann einbinden?

So wie immer
1
volatile uint8_t gyroReady;
2

3
IRS( ... )
4
{
5
  gyroReady = 1;
6
}
7

8
int main()
9
{
10
  ...
11

12
  while( 1 ) {
13

14
    ...
15
    if( gyroReady ) {
16
      gyroReady = 0;
17

18
      ..... mach was mit den Gyro Daten
19
    }
20

21
    ....
22
  }
23
}


und so machst du das mit allem was ein wenig länger dauert.
Die ISR kann kleinere Dinge berechnen, solange sie schnell gehen. 
Ansonsten stösst die nur an, indem sie das Flag setzt. In der 
Hauptschleife werden nacheinander die einzelnen 'Jobs' überprüft, ob sie 
wieder mal anstehen und werden abgearbeitet, wenn es wieder mal soweit 
ist.
Gast #3745218
Lesenswert?

>Aber wie soll ich eine Berechnung, welche nur benötigt wird, wenn er den
>Gyro ausliest ausliest dann einbinden?

Diese Berechnungen da sicher mit Fließkomma dauern ewig aufm Atmega da 
kein Hardwaremultiplizierer für floats oder doubles exestiert. Eventuell 
lässt sich da was optimieren, aber wahrscheinlich brauchst du mehr 
rechen power bzw. andere architektur (32bit).

GRuß Jonas
#3745246
Lesenswert?

Man kann im übrigen Berechnungen, wenn sie wirklich extrem lang sind 
(und sich das auch nicht verkürzen lässt) auch in mehrere Abschnitte 
unterteilen, die sie selbst auf genau die gleiche Art und Weise die 
Freigabe geben.
1
  while( 1 ) {
2

3
    .... YYYY
4

5
    if( performPart4 ) {
6
      performPart4 = 0;
7

8
      ... bearbeite Abschnitt 4
9
    }
10

11
    if( performPart3 ) {
12
      performPart3 = 0;
13

14
      .... bearbeite Abschnitt 3
15

16
      performPart4 = 1;
17
    }
18

19
    if( performPart2 ) {
20
      performPart2 = 0;
21

22
      .... bearbeite Abschnitt 2
23

24
      performPart3 = 1;
25
    }
26

27
    if( doTheJob ) {
28
      doTheJob = 0;
29

30
      .... bearbeite Abschnitt 1
31

32
      performPart2 = 1;
33
    }
34

35
    ... XXXX
36

37
  }

Ziel der Sache ist es, dass die Programmteile XXXX bzw. YYYY während der 
länger andauernden Berechnung auch eine Chance haben, ihr Ding zu 
machen.

Der Schlüssel zu einem Programm, welches mehrere Dinge 'gleichzeitig' 
macht besteht darin, dass alles in kleine Happen aufgeteilt wird und 
sich der Rechner die Happen reihum einzeln vornimmt. D.h. sofern die 
Rechenleistung grundsätzlich ausreicht.

Ein weiterer Schlüssel besteht in der korrekten Verwendung von 
Datentypen. Wer einfach wahllos mit int oder double um sich schmeisst, 
darf sich nicht wundern, wenn sein Mega nicht mehr mitkommt. 
Fleissaufgaben benötigen schliessllich auch Rechenzeit, selbst wenn sie 
unnütz sind.
#3745350
Lesenswert?

Kalman-Filter (wirst du brauchen) schon drin?
Die oben gemachten Vorschläge sind alle gut und richtig - hilft aber 
alles nichts, wenn du es nicht schaffst, innerhalb deiner Zykluszeit 
alle Berechnungen auszuführen.
Dann bleibt dir nur 3 Wege:
-die Zykluszeit erhöhen (schlecht für die Qualität der Regelung)
-die Berechnungen zu vereinfachten (was bei einer 3D-Lageregelng Grenzen 
hat)
-die Berechnungen auf einer schnelleren Maschine ausführen
#3745685
Lesenswert?

Die Winkelberechnung mache ich mittels einem digitalen Hoch- und 
Tiefpass. Das ist zwar nicht so genau, wie der Kalman Filter, jedoch ist 
er weniger aufwendig und benötigt nicht so viel rechenpower.
Und mit dieser kleinen Ungenauigkeit kann ich leben.

Ja ich versuche eben mal meine Codr zu optimieren und so wenig wie 
möglich in den Interrups zu machen.
Gast #3745703
Lesenswert?

Also grundsätzlich kann man bei richtigem Programmierstil schon gut was 
ausm AVR rausholen. Aber irgendwann ist Schluss. Dann muss man sich halt 
mehr Rechenleistung gönnen, z.B. einen Cortex M3/M4.

So schlimm ist die Einarbeitung nicht. Ganz im Gegenteil, durch die 
CMSIS ist die Hardware schnell initialisiert und man kann sich dem 
eigentlichen Problem widmen.



Ingo
Gast #3746319
Lesenswert?

Der ggf. kritische Teil ist die PWM-erzeugung. Wenn man das in Software 
macht, verbraucht es sehr viel Rechenzeit. Auch bei der Erfassung der 
Pulse kann man mit einem nicht so guten Programm viel verschenken. Der 
Trick ist es halt vieles direkt von der Hardware machen zu lassen und 
nicht alles von Hand zu programmieren.

Die Datenerfassung von Gyro und Filterung sollte eher das kleinere 
Problem sein, und ist eher nicht so zeitkritisch. Wenn das Fehler 
auftreten wenn der Code länger wird, ist es eher ein Problem mit dem 
Stack oder nicht atomarem Datenzugriff.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren