Guten Abend, Community Ich bin gerade dabei, einen PID-Regler für die Fahrtregelung meines kleinen Roboters zu schreiben. Rechenknecht ist ein ATmega32 der einen Maussensor einliest und damit die Motoren regeln soll. Die Motoren werden dabei mit PWM über den T/C1 betrieben. Das Ganze programmiere ich in C. Ich nutze beim Zähler (erstmal) nur 8 Bit. Wenn ich jetzt meine Mausdaten kontinuierlich einsammel und aufsummiere und der Regler mit etwa 10 Hz darauf zugreift, habe ich hardwarebedingt einen Istwert nahe der 600. Also muss ich da mit 16 bit arbeiten. Soweit klar. Wenn ich dann die Abweichung berechne, und diese mit der P-Regler-Konstanten multipliziere, will ich ja einen Wert bekommen, der auf die OCR1n addiert, immer in die 8bit der OCR1n passen muss. (Ja, ich weiß, warum dann nicht den 16bit-Zähler auch als solchen verwenden? Ist geplant, löst aber diese Frage nicht in Luft auf.) Demnach könnte ich diesen Wert ja wieder in eine 8bit-Variable stecken. Ein If-Else-Konstrukt verhindert auch, daß OCR1n mit Überläufen konfrontiert wird. Naja geht irgendwie, der Regler läuft, aber theoretisch ist das ja ziemlich schmutzig, denn 16 bit - 16 bit kann auch 32 bit werden. 32 bit * 8 bit passt auch nicht immer in 32 bit, also müsste ich ja den Wert mathematisch korrekt in 64 bit schreiben. Auf einer 8bit Architektur etwas wild, oder? Wie hält man da die Bitbreiten in einem sauberen Verhältis zwischen Aufwand und Robustheit? Habt Ihr irgendwelche Suchmaschinenparameter für mich oder gibt es dazu bewährte Herangehensweisen? Oder macht der Compiler aus meinem unansehnlichen Stück Code etwas Vernünftiges? Besten Dank schonmal für eure Hilfe.
Ich halte mich bei 8Bit Controllern immer an folgende Regel: - So klein wie möglich, so gross wie nötig Da bei Programmen für Mikrocontrollern in der Regel der Wertebereich definiert ist, sollte es kein Problem sein, den korrekten Datentyp auszuwählen. Ein Beispiel: Ein Temperatursensor liefert Temperaturen im Bereich von -50 bis 150°C in einer Auflösung von 0.1°C. Dann verwende ich einen int16_t als Fixkommazahl => Wertebereich der Variable: -500 bis 1500. Nun schreibe ich die Funktion, die den Sensor ausliest und die Temperatur in das richtige Format bringt:
1 | int16_t ReadTemperature(void){ |
2 | int16_t Temperature; |
3 | |
4 | /* Lese Sensor */
|
5 | /* Formatiere Temperatur */
|
6 | |
7 | if(Temperature>1500){ |
8 | Temperature=1500; |
9 | }
|
10 | if(Temperature<-500){ |
11 | Temperature=-500; |
12 | }
|
13 | }
|
Hier füge ich Prüfungen und Korrekturen ein, die bei einem allfälligen Fehler den Wertebereich der Variable garantiert. So können bei darauf folgenden Berechnungen, die sich auf den Wertebereich der Variable verlassen, keine Überläufe entstehen. Diese Vorgehensweise hat den Nachteil, dass du bei einer Anpassung des Wertebereichs alle betroffenen Codezeilen manuell prüfen und evt. anpassen musst.
:
Bearbeitet durch User
>> denn 16 bit - 16 bit kann auch 32 bit werden.
Ne, 16 Bit - 16 Bit wird höchstens 17 Bit. Zur Speicherung wird dann
eine 32 Bit Variable benötigt, bei der aber 15 Bit unbenutzt sind.
Multipliziert mit 8 Bit sind das jetzt 25 Bit. Dafür wird immer nur noch
eine 32 Bit Variable benötigt, bei der dann immer noch 7 Bit unbenutzt
sind.
Also kein Zwang zu 64 Bit.
@ Per P. (mullwark) >etwa 10 Hz darauf zugreift, habe ich hardwarebedingt einen Istwert nahe >der 600. Also muss ich da mit 16 bit arbeiten. Soweit klar. OK. > Wenn ich >dann die Abweichung berechne, und diese mit der P-Regler-Konstanten >multipliziere, will ich ja einen Wert bekommen, der auf die OCR1n >addiert, immer in die 8bit der OCR1n passen muss. Wieso addiert? Du berechnest doch den PWM-Wert für die Stellgröße. D.h. OCR1n wird mit einem neuen Wert geladen. >löst aber diese Frage nicht in Luft auf.) Demnach könnte ich diesen Wert >ja wieder in eine 8bit-Variable stecken. ??? >Naja geht irgendwie, der Regler läuft, aber theoretisch ist das ja >ziemlich schmutzig, denn 16 bit - 16 bit kann auch 32 bit werden. Nö. Bestenfalls 17 Bit. > 32 bit >* 8 bit passt auch nicht immer in 32 bit, also müsste ich ja den Wert >mathematisch korrekt in 64 bit schreiben. Um Gottes Willen, bloß nicht! Da geht der AVR ganz ordentlich in die Knie! 64 Bit Arithmetik ist nicht sonderlich leistungsfähig auf dem AVR umgesetzt. Man muss es nicht immer übertreiben und mal abschätzen, welche maximalen Zahlen auftreten können. Man wird selten 255 * 2^(32-1) rechnen, sondern die einzelnen Variabeln sind meist deutlich kleiner als der maximale Zahlenbereich. Für einen einfachen PI-Regler kommt man mit 16 oder 32 Bit locker hin. Meistens reichen 16 Bit für die Variablen und casts auf 32 Bit für die Berechnungen. >Oder macht der Compiler aus meinem unansehnlichen Stück Code etwas >Vernünftiges? Das kann hier keiner sehen. Aber Compiler können nicht zaubern, den Überblick muss der Programmierer behalten.
Es gibt auch die Möglichkeit, den Wertebereich auf -1..1 zu normieren und dann Fixedpoint-Typen zu verwenden wie fract (16 Bits) oder long fract (32 Bits) aus stdfix.h.
be stucki schrieb: > Hier füge ich Prüfungen und Korrekturen ein, die bei einem allfälligen > Fehler den Wertebereich der Variable garantiert. So können bei darauf > folgenden Berechnungen, die sich auf den Wertebereich der Variable > verlassen, keine Überläufe entstehen. > > Diese Vorgehensweise hat den Nachteil, dass du bei einer Anpassung des > Wertebereichs alle betroffenen Codezeilen manuell prüfen und evt. > anpassen musst. Gut, also doch Werte im Zweifelsfall eingrenzen, das hatte ich im Ansatz ja überlegt. PittyJ schrieb: > Ne, 16 Bit - 16 Bit wird höchstens 17 Bit. Zur Speicherung wird dann > eine 32 Bit Variable benötigt, bei der aber 15 Bit unbenutzt sind. > > Multipliziert mit 8 Bit sind das jetzt 25 Bit. Dafür wird immer nur noch > eine 32 Bit Variable benötigt, bei der dann immer noch 7 Bit unbenutzt > sind. > > Also kein Zwang zu 64 Bit. Argh, natürlich. Schön daß Du mich mit der Nase drauf stößt, da hatte ich ein Brett vorm Kopf. Danke. Falk Brunner schrieb: >> Wenn ich >>dann die Abweichung berechne, und diese mit der P-Regler-Konstanten >>multipliziere, will ich ja einen Wert bekommen, der auf die OCR1n >>addiert, immer in die 8bit der OCR1n passen muss. > > Wieso addiert? Du berechnest doch den PWM-Wert für die Stellgröße. D.h. > OCR1n wird mit einem neuen Wert geladen. Ja, doch ich addiere da, erreiche aber dabei das Gleiche, was Du meinst. Ich habe die Abweichung, die um 0 schwankt, mal positiv, mal negativ. Die mit meiner Konstanten multipliziert ergibt meine Veränderung des PWM-Wertes, nicht den PWM-Wert selber. Die Veränderung wird also auf den aktuellen Wert in OCR1n angewand. Falk Brunner schrieb: > Um Gottes Willen, bloß nicht! Da geht der AVR ganz ordentlich in die > Knie! > 64 Bit Arithmetik ist nicht sonderlich leistungsfähig auf dem AVR > umgesetzt. Genau, das hatte ich auch gelesen, deswegen kam ich ja auch ins Grübeln. Aber dank der Antworten habe ich jetzt gesehen, was ich falsch gemacht habe und wo noch Lernbedarf herrscht. Falk Brunner schrieb: > Man muss es nicht immer übertreiben und mal abschätzen, welche maximalen > Zahlen auftreten können. Man wird selten 255 * 2^(32-1) rechnen, sondern > die einzelnen Variabeln sind meist deutlich kleiner als der maximale > Zahlenbereich. Für einen einfachen PI-Regler kommt man mit 16 oder 32 > Bit locker hin. Meistens reichen 16 Bit für die Variablen und casts auf > 32 Bit für die Berechnungen. Japp, danke, das ist eine klare Antwort, die hilft weiter. Also tatsächlich muss ich nicht den theoretisch möglichen Mathematischen Raum abdecken, es reicht, sich vorher vernünftig zu überlegen, welche Werte überhaupt mit der gegebenen Hardware auftreten können. Johann L. schrieb: > Es gibt auch die Möglichkeit, den Wertebereich auf -1..1 zu normieren > und dann Fixedpoint-Typen zu verwenden wie fract (16 Bits) oder long > fract (32 Bits) aus stdfix.h. Danke für den Tipp, auch wenn ich glaube, daß ich in meinem konkreten Fall keine Normierung anwenden werde, die stdfix.h sollte ich mir bald ansehen. :-)
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.