Hallo Beitragsleser, letztes Mal habe ich den folgende Thread eroeffnet. Man muss ihn nich lesen, um mein jetztiges Anliegen zu verstehen. Aber dennoch moechte ich darauf verlinken: Beitrag "Re: PI-Regelschleife fuer Geschwindigkeiteit eines autonomen Roboters" Im alten Thread hat Jan Heynen mir zu Recht unterstellt, dass ich einen Tachogenerator verwenden will fuer meinen Roboter. Diese Annahme ist absolute berechtigt, wenn man sich meinen alten Code ansieht. Da ich damals aber duemmer war als ich jetzt bin, wusste ich nicht, wie ich seine Bemerkung zu verstehen hatte, denn ich wollte und will auch jetzt Wheelencoder benutzen fuer mein jetziges Roboterprojekt. Mein Projekt praegnant zusammengefasst. Ich will einen autonomen Roboter bauen, der zwei unabhaenige Raeder/Motoren auf gleiche Geschwindigkeit regelt. Dafuer nutze ich einen Arduino Mikro mit einem ATmega32U4. Das nur so am Rande. Ich muss jetzt etwas mit C arbeiten, weil ich keine Bibliothek gefunden habe, die mir massgenscheidert weiterhelfen kann. Ich benutze also C in der Arduino IDE, soll angeblich gehen. Es ist also ein Gemsich aus C- und Arudino-Programmierung. Meine eigentliche Frage lautet, ist mein nachfolgender Code richtig? # define F_CPU 16000000 UL //Systemfrequenz 16 MHZ (das gibt der Atmega her) void setup() { TCCR1B |= (0<<CS11) | (1<<CS10); // 16-Bit-Timer 1 Prescaler nimmt Wert 1 an TCCR3B |= (0<<CS32) | (1<<CS30); // 16-Bit-Timer 3 Prescaler nimmt Wert 8 an TCCR0A |= (0<<CS01) | (1<<CS00); // 8-Bit-Timer 0 Prescaler nimmt Wert 1 an sei; } void loop() {;} ISR(Timer1_COMPA_vect) {;} ISR(Timer3_COMPA_vect) {;} ISR(Timer0_COMPA_vect) {;} Was soll der Code bewirken, moechte man jetzt vermutlich wissen? Die Idee dahinter ist, das die Timer 1 und 3 62500 Overflows/s ausloesen und der Timer 0 244,1406 Overflows/s. Ich glaube, dass ich keine weiteren Bits mehr setzen muss, weil ich z.B. den CTC-Modus nicht brauche, glaube ich. In den ISR-nen der Timer 1 und 3 werden jetzt die sogenannten Ticks oder Klicks der Wheelencoder gezaehlt werden und im Timer 0 wuerde die Geschwindigkeit der auf Basis der Klicks/Ticks ermittelt werden. Den Inhalt der Tick Zaehlung und Geschwindigkeitsbestimmung habe ich noch als Datei angehaengt, vollstaendigkeitshalber. Ich habe meinen Code auf das wesentlichste, also das worauf sich meine Frage bezieht, eingeschraenkt. Ich habe also den Systemtakt auf 16 MHz gestellt und die Vorteiler fuer die Timer eingestellt. So muessten die ISR doch jetzt nach jedem Interrupt aufgerufen werden, ist das richtig? Das scheint mir irgendwie zu einfach zu sein. Tut mir Leid, aber ein Teil meines PCs hat eine gewaltige Macke. Ich schicke den Anhang gleich noch hinter her. Ich hab Angst, dass wenn ich den Beitrag jetzt nicht losschicke, dann wird er geloescht. FG, Berus
Claude J. schrieb: > So muessten die ISR doch jetzt nach jedem > Interrupt aufgerufen werden, ist das richtig? Nein, die Timer anzustellen reicht nicht aus. WEnn eine ISR ausgelöst werden soll, wenn der Timer überläuft, musst du den entsprechenden Interrupt in den entsprechenden Registern auch aktivierten. beim Atmega325A wäre das z.B. das Bit TOIE0 (Timer 0 Overflow Interrupt enable) im Register TIMSK0. Dann wäre die ISR aber auch TIMER0_OVF_vect. Oder eben das Bit OCIE0A (Timer 0 Output Compare Match A Interrupt enable) und du kannst die ISR lassen
Hallo an alle Leser, @Ralini: danke fuer deine Hilfe. Fuer dein schnelle Antwort. Ich habe jetzt zwei Dokumente angehaengt, musste gestern erst meinen PC wieder in Gang kriegen. Im ersten Dokument ist der ganze Code, im zweiten nur ein Teil davon, also das, worauf sich meine noch folgenden Fragen beziehen. Ich bin mir ziemlich unsicher, was die Funktionalitaet meines Codes angibt. Syntaktisch ist er einwandfrei, sagt der Debugger. Meine Bedenken sind aber folgende. Ich habe zwei Raeder mit jeweils einen Wheelencoder. Ich will die Ticks von beiden Wheelencodern moeglichst gleichzeitig lesen. Fuer jeden Wheelencoder habe ich eine ISR. Die ISR fuer den rechten Wheelencoder wird vom Timer3 und die ISR fuer den linken Wheelencoder wird vom Timer 1 ausgeloest. Die Inkremente beider Wheelencoder sollen von derjenigen ISR ausgewertet werden, die vom Timer0 ausgeloest wird. Daraus soll sich die Geschwindigkeit ergeben. Diese Geschwindigkeit soll dann im Hauptprogramm innerhalb einer PI- Regelung verwertet werden. Ich bin skeptisch, weil ich mir unsicher bin. Ich habe folgende Bedenken. Momentan verwende ich zwei ISRen, jeweils eine fuer jeden Wheelencoder. Beide ISRen werden mit 62,5 kHz ausgefuehrt bzw. jeder Wheelencoder wird mit 62,5 kHz abgetastet. Bedenken Nummer 1: Kann es sein, dass bei einer solchen hohen Abastrate fuer das Zaehlen der Inkremente eines Wheelencoders eine inkrementeale Drehung des Motors mehrfach erfasst wird. Ich meine, dass ich z.B. drei Inkremente zaehle, obwohl sich der Motor nur um ein Inkrement gedreht hat und somit zwei Inkremente zu viel gezaehlt weren Bedenken Nummer 2: Sollte ich die Inkremente der beiden Wheelencoder nicht besser in einer ISR zaehlen, statt wie bisher in zwei ISR? Bleibe ich bei zwei ISR, dann wuerde ich doch theoretisch die Geschwindikeit des linken Motors zeitlich nach der Geschwindigkeit des rechten Motors erfassen oder umgekehrt, aber nicht gleichzeitig, was ich ja eigentlich erreichen will. Bedenken Nummer 3: Kommt mein Hauptprogramm, was die PI-Regelung sein soll, ueberhaupt zum Zuge, wenn ich die ganze Zeit die ISR am laufen habe? Ich meine, da die ISR durch den Timer getriggert wird, bleibt zwischen zwei Overflows nur eine paar uS Zeit zum Durchlaufen des Hauptprogramms bis die ISR ein naechstes Mal durchlaufen werden kann. Ich glaube, dass ich die Zeit zwischen zwei Interrupt verlaengern muss. Es muesste also so sein, dass das Haupprogramm lange dauert, die ISR fuer die Auswertung der Inkrement bzw. die Bestimmung der Geschwindigkeiten mittel lang dauer und die ISR fuer die Zaehlung der Inkremente kurz dauer. Ist das richtig? Ehrlich gesagt, glaube ich, dass mein Konzept nicht richtig durchdacht ist. Das wird mir beim Schreiben gerade noch deutlicher. Koenntet ihr mir Anregungen und Hinweise geben, wie ich das Konzept verbessern kann? Freundliche Gruesse, Berus
Kann es sein, dass dies gar nicht so geht. Muesste ich nicht eventuell einen zweiten Chip verwenden? Den ersten Chip zum messen der Inkremente der beiden Motoren und zur Auswertung der Inkremente bzw. Bestimmung der Geschwindigkeit und den zweiten Chip zum Durchfuehren des Hauptprogrammes. Das Hauptprogramm wuerde dann ununterbrochen laufen und nur dann auf die Geschwindikeit vom anderen Chip zugreifen, wenn es die Geschwindigkeit zur PI-Regelung wirklich braucht. FG, Berus
Claude J. schrieb: > TCCR1B |= (0<<CS11) | (1<<CS10); // 16-Bit-Timer 1 Prescaler nimmt Wert > 1 an > TCCR3B |= (0<<CS32) | (1<<CS30); // 16-Bit-Timer 3 Prescaler nimmt Wert > 8 an > TCCR0A |= (0<<CS01) | (1<<CS00); // 8-Bit-Timer 0 Prescaler nimmt Wert 1 > an > > sei; > > } > > > Was soll der Code bewirken, moechte man jetzt vermutlich wissen? Die > Idee dahinter ist, das die Timer 1 und 3 62500 Overflows/s ausloesen und > der Timer 0 244,1406 Overflows/s. Wie kommst du auf diese Werte??? 16-Bit-Timer 1 mit Prescaler 1 ergibt 244 OVF/s 16-Bit-Timer 3 mit Prescaler 8 ergibt 244/8 OVF/s 8-Bit-Timer 0 mit Prescaler 1 ergibt 62500 OVF/s Wenn man jetzt davon ausgeht, dass du die ISRs sehr kurz hältst, bist du schon bei 5-6 Mio. Instruktionen (von theoretisch 16 Mio., praktisch natürlich weniger, da einige Instuktionen mehr Cycles brauchen). Fügst du jetzt noch ein paar (float) Berechnungen hinzu oder verwendest die aufgeblähten Arduino Libs, kommt dein MC nicht mehr mit. mfg
Felix F. schrieb: > Wie kommst du auf diese Werte??? Einen Overflow von nem ISR hat nix mit der Anzahl der Instruktionen zu tun! Bei 16MHz und einem 'vollen' Zyklus bei 16bit zählt der µC 244 mal pro Sekunde bis 65535. Also läuft der Zähler da über und erzeugt einen Interrupt.
Nico W. schrieb: > Einen Overflow von nem ISR hat nix mit der Anzahl der Instruktionen zu > tun! Nein, aber du willst mit dem Overflow eine ISR aufrufen, welche eine bestimmte Anzahl an Instruktionen benötigt. Und eine ISR läuft nich parallel ab, sondern blockiert alles andere während der Rechenzeit. > Bei 16MHz und einem 'vollen' Zyklus bei 16bit zählt der µC 244 mal pro > Sekunde bis 65535. Also läuft der Zähler da über und erzeugt einen > Interrupt. Du hast den 16-Bit-Timer mit Prescaler 1 konfiguriert, es liegen also die vollen 16 MHz an. Der Timer zählt bis 65535, dann gibt es einen Overflow. Das passiert genau 244x. Somit wird 244x eine ISR aufgerufen. Der 8-Bit-Timer läuft nur bis 255 und löst dementsprechend über 62000x aus. mfg
Danke fuer deine Antwort. Ich soll also die Overflows pro Sekunde drastisch reduzieren, meinst du. Ich habe bei der Einstellung von 62,5 khz nicht nachgedacht, ehrlich gesagt. Mein letztes uC Projekt ist einige jahre her. Meine Errinnrungn an das schon damals lueckenhafte Wissen ueber uC sind starkt ausgepraegt, wie man sehen kann. Wie bestimme ich die maximal zulaessige Anzahl an Overflows bzw. Interrupts pro Sekunde? Sind es fuer das Hauptprogramm zu viele Interrupts, wenn beide Encoder (jeweils ein Encoder an einem Motor) bei jedem Inkrement einen Interrupt ausloesen? Eine realistische Annahme ist womoeglich, dass ein Encoder pro Sekunde 100 Mal inkrementiert wird. Das waeren dann 200 Interrupts pro Sekunde. Koenntest du mir bitte erklaeren, wie du auf die 5 Millionen Instruktionen gekommen bist? Ist es die Rechnung (16^2*244)*2+62500*8^2 = 4124928? FG, Berus
Oh, da war ich zu langsam. Danke fuer die Erklaerung.
Wie viele Interrupts du in deinem Programm haben darfst, hängt davon ab was du sonst noch machst. Bis jetzt (ohne große Berechnungen) ist alles noch in Ordnung. Aktuell hast du ~63000 INTs/s. Wenn man von ca. 50 Instruktionen pro ISR ausgeht, hast du somit über 3 Mio. Instruktionen. Da nicht jede Instruktion mit 1 Cycle auskommt kannst du das mal grob auf 5 Mio. aufrunden. Kommt letztendlich auch auf dein Programm an. Lese/Schreibbefehle auf Speicher oder Gleitkommaberechnungen brauchen sehr viel länger als z.B. einfache Additionen. Aber da Mechanik sehr langsam ist (im Vergleich zur Elektronik) benötigst du vermutlich keine so hohe Auflösungen. Ich würden den 8-Bit-Timer auf jeden Fall mal um die Hälfte reduzieren, damit gewinnst du schon sehr viel. Und wenn am Ende noch genug Ressourcen übrig sind, kannst du die Timer immer noch hochschrauben. mfg
Claude J. schrieb: > Bedenken Nummer 2: > > Sollte ich die Inkremente der beiden Wheelencoder nicht besser in einer > ISR zaehlen, statt wie bisher in zwei ISR? Bleibe ich bei zwei ISR, dann > wuerde ich doch theoretisch die Geschwindikeit des linken Motors > zeitlich nach der Geschwindigkeit des rechten Motors erfassen oder > umgekehrt, aber nicht gleichzeitig, was ich ja eigentlich erreichen > will. Mit einer ISR bist du vmtl sogar "mehr" parallel als mit 2. Für jede ISR muss der Controller bestimmte Instruktionen durchführen (z.B. sichern von Registerinhalten) bevor er überhaupt mit dem tatsächlichen Code anfängt. Und da 2 ISRs sowieso nie parallel sein können, werden die Encoder sowieso hintereinander eingelesen. Mit einer ISR sparst du dir aber zusätzlichen Code, der lediglich für das Ausführen der ISR gedacht ist und kannst die Encoder in einer ISR direkt hintereinander einlesen.
1 | Mit 1 ISR: |
2 | - Zu ISR springen |
3 | - Register sichern etc. |
4 | - Encoder 1 einlesen |
5 | - Encoder 2 einlesen |
6 | - ISR verlassen |
7 | |
8 | Mit 2 ISRs |
9 | - Zu ISR 1 springen |
10 | - Register sichern etc. |
11 | - Encoder 1 einlesen |
12 | - ISR verlassen |
13 | - Zu ISR 2 springen |
14 | - Register sichern etc. |
15 | - Encoder 2 einlesen |
16 | - ISR verlassen |
mfg
Ok, also nur eine ISR. Ich bitte fuer meine uebertrieben Vorsicht um Nachsicht. Lieber frage ich aber noch Mal nach. Kannst du bestaetigen, dass es fuer das Hauptprogramm keine Schwierigkeiten gibt, wenn ein Inkrement eines jeden Encoders ein Interrupt ausloest? Du meintest bereits, dass Mechanik viel langsamer ist also Elektrotechnik.
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.