Hallo, Am STM32F407 will ich 2 Motoren mit Quadraturencoder betreiben. (Lageregelung). Um die Drehzahl zu erfassen brauche ich ja InputCapture. Beim Quadratur-Encoder ist der Timer ja die Zählbasis, also muss ich mit allen Signalen noch zusätzlich auf andere Pins, und auf andere Timer ? JanK.
Einfach A und B signal von Encoder anschliessen an die richtige timer pins, Timer configurieren und das soll functionieren. Der Timer counter entspricht dan genau die erfasste pulsen von Encoder.
Ja. Das Zählen geht. Aber für die Drehzahlerfassung brauche ich doch den Zeitpunkt der Flanken. Also zusätzlich InputCapture. Oder nicht ?
@JanK. (Gast) >Ja. Das Zählen geht. Aber für die Drehzahlerfassung brauche ich doch den >Zeitpunkt der Flanken. Also zusätzlich InputCapture. Oder nicht ? Oder nicht. Du musst mit einem (sowieso benötigte) Timer in regelmässigen Abständen deinen Quadraturdecoder auslesen. Die Differnz der Zählerstände geteilt durch die Zeitspanne ist deine Drehzahl. Nix mit Input Capture.
Na dann hab ich doch keine Auflösung mehr. Wenn so ein Encoder bei max. Drehzahl vielleicht 3kHz hat (4-fach Auswertung). Dann hätte ich in einer Regelung in der 1ms Task Drehzahlen von 0 bis 3 Einheiten (bei vmax). Bei kleineren 0 oder 1.
was du brauchst ist keine Encoder Auswertung sondern eine PWM-Input Messung wobei ich mir nicht sicher bin, ob das mit quadraturencoder funktioniert
:
Bearbeitet durch User
JanK. schrieb: > Na dann hab ich doch keine Auflösung mehr Das Problem ist doch alt wie die Welt (der Elektronik). Wenn die Frequenz zu niedrig ist um zu zählen, schaltet man um auf Periodendauermessung. Georg
>was du brauchst ist keine Encoder Auswertung >sondern eine PWM-Input Messung Ich will eine Lageregelung (unterlagerte Drehzahlregelung). Dazu brauch ich den Encoder. PWM ist immer 50%, da es ja 2 um 90% phasenverschobene Signale mit 50% Tastverhältnis sind. >Das Problem ist doch alt wie die Welt (der Elektronik). Wenn die >Frequenz zu niedrig ist um zu zählen, schaltet man um auf >Periodendauermessung. Ja. Will ich ja machen. Mit InputCapture. Die Frage war, muss man dazu beim STM32 alle Signale auf 2 unterschiedliche Timer mit jeweils 2 unterschiedlichen Pins legen ?
JanK. schrieb: > muss man dazu beim STM32 alle Signale auf 2 > unterschiedliche Timer mit jeweils 2 unterschiedlichen Pins legen ? Ich kenne den STM nicht. Aber wenn da ein Encoder drin ist, dann ist das nächste Problem, dass du den Encoder-Ausgang als Capture-Eingang brauchst. Ich weiss nicht ob man da dran kommt. Georg
JanK. schrieb: > Ja. Will ich ja machen. Mit InputCapture. > für was brauchst du denn dann noch den Encoder ? du hast doch selbst gesagt, das er zu langsam für deine Zwecke ist falls du nicht noch die Richtung auswerten musst, genügt ein Eingangspin auf einen Input-Capture Eingang von einem Timer damit kannst du die Frq und den Duty-Cyle (der immer 50% ist) messen und diese Betriebsart des Timers wird im RefManual von ST als "PWM input mode" beschrieben einfach dort mal nachlesen Gruss Uwe
Hi,
> Um die Drehzahl zu erfassen brauche ich ja InputCapture.
eher nicht weil du beim Pendeln falsche Drehzahlen bekommen würdest.
Was du aber machen kannst ist beim Auftreten eines Inc im
Quadraturencoder
einen Timer auslesen (fast wie Input-Capture)und beim Auftreten des
nächsten Inc mit der selben Richtung die Diff bestimmen... müsste
eigentlich gehen.
Viel Erfolg, Uwe
Also ich will die Quadratur-Dekodierung nicht im Interrupt machen.
Ich will nicht bei jedem Event ein Interrupt auslösen.
Sondern den Quadratur-Encoder vor sich hin zählen lassen und in jeder
(1ms) Task auslesen. Dort findet auch die Regelung statt.
Gleichzeitig will ich die Zeit der letzten Flanke wissen (Input
Capture).
Dann weiss ich, in der letzten Task stand der Zähler bei 3. Jetzt bei 5.
Bei 3 war der Zeitstempel noch 1000µs. Jetzt bei 5 steht er bei 1024µs.
Dann hat der Motor also eine Drehzahl von 2Steps/24µs*K.
>weil du beim Pendeln falsche Drehzahlen bekommen würdest.
Nein. warum ?
Man muss allerhöchstens nach dem lesen des InputCapture Wertes nochmals
prüfen, ob sich inzwischen nicht die Position verändert hat, da man
nicht beides gleichzeitig lesen kann.
Eine Drehzahl Erfassung mit einen update jeden ms ist wenig Sinnfoll : Drehzaehlen aendern sich nicht schlagartig jeden ms. Die Periodendauer messen ist auch nicht so genau : meistens ist die duty cycle nicht exact 50%, und das versatz zwischen A/B spur ist auch nicht exact 90°. Damit hat men verschiedene Periodendauer bij gleiches Drehzahl ! Auch wen die Periode laenger ist als 1 ms, muss die Regelung die vorher gemessene Periode nutzen ! Einfachste Lösung : Nur jeden 25 oder 50 ms einen Update machen, oder hochauflosende Encoder nutzen (1024 Polungen/Umdrehung). Uebrigens functioniert eine Positionsregelung nicht nur auf basis von Drehzahlregelung : da wird eine vergleich gemacht zwischen Ist und Soll Position, diesen Wert wird dan mit eine P-regelung auf die Motor gegeben.
>Drehzaehlen aendern sich nicht schlagartig jeden ms. Also Servomotoren haben mechanische Zeitkonstanten von etwa 1ms. Und DC Getriebemotoren liegen auch um 10ms Bereich. >Die Periodendauer >messen ist auch nicht so genau : meistens ist die duty cycle nicht exact >50%, und das versatz zwischen A/B spur ist auch nicht exact 90°. Damit >hat men verschiedene Periodendauer bij gleiches Drehzahl ! Auch wen die >Periode laenger ist als 1 ms, muss die Regelung die vorher gemessene >Periode nutzen ! Das stimmt. Aber die kann (während des Betriebes) gelernt werden. Mann muss für Phase 0,1,2 und 3 einen Korrekturwert hinterlegen. >Uebrigens functioniert eine Positionsregelung .. Ja. Ich wollte einen Kaskadenregler mit unterlagerter Drehzahlregelung machen.
meine Geschwindigkeitserfassung ist auch viel langsamer als 1mSec. Eine solche Beschleunigung halte ich vielleicht theoretisch für möglich. In der Praxis hat der Motor aber wahrscheinlich mechanische Massen zu bewegen ...
JanK. schrieb: > Also Servomotoren haben mechanische Zeitkonstanten von etwa 1ms. In 1ms aus dem Stand auf 63% der Maximaldrehzahl? Hast du da mal einen Link auf ein Datenblatt?
>In 1ms aus dem Stand auf 63% der Maximaldrehzahl? >Hast du da mal einen Link auf ein Datenblatt? Leider nicht. Es war in der Vorlesung "Servomotoren". Da hatten wir das Modell eines Servomotors und mussten den Regler dazu entwerfen.
Egal. Da sich meine Frage hier nicht eindeutig beantworten ließ: Ich hab alle Quadraturencodersignale jetzt doch noch auf einen 2. Input Capture Eingang gelegt. Morgen mach ich das Layout und wenn ich in 2-3 Wochen dann die Software habe postes ich es hier nochmals. (Oder schreib einen Artikel.)
>Hast du da mal einen Link auf ein Datenblatt? Zum Beispiel: http://www.moog.com/literature/ICD/Moog-ServoMotors-MDSeries-Catalog-en.pdf
Aber das grundlegende Problem bleibt noch : wass machts du bei eine Periodedauer laenger dan 1 ms ? Auch das Regelinterval aendern ? Dan wird ihre Regelung auch langsamer ! In Praxis ist das auch so das sehr niedrige Drehzaehlen von ein DC-Getriebemotor sich nicht schon regelen lassen : Das Drehmoment wird dan abhangig von stand von die Achse (brushed motor). Damit hat man kein Lineaires Verband zwischen PWM-Wert und Drehmoment. Die besten Motoren sind dan diese mit eine Eisenlose Anker (Maxon, Faulhaber...).
Der Thread ist zwar schon etwas älter, aber ich stehe gerade vor dem gleichen Problem wie der Ersteller und eine schöne Lösung wurde ja noch nicht gefunden... Für das Verfahren gibt es sogar ein Paper: http://www.diegm.uniud.it/petrella/Azionamenti%20Elettrici%20II/Tesine/Petrella%20et%20al.%20-%20Speed%20Measurement%20Algorithms%20for%20Low-Resolution%20Incremental%20Encoder%20Equipped%20Drives_a%20Comparative%20Analysis.pdf Dort wurde ein TMS320F24x von TI verwendet, so wie ich das verstehe mit 2 Timern. Ein Timer (T1) ist wohl mit einer Clock der MCU verbunden, der zweite (T2) läuft im Encoder-Modus und zählt Pulse. Bei jeder Änderung von T2 wird dann ein Capture Event bei T1 ausgelöst, sodass man immer den Zeitpunkt der letzten Flanke abrufen kann. Die Frage ist, kann man das irgendwie beim STM32 nachbilden? Ich habe mal ins Reference Manual geschaut, aber keinen Weg gefunden, ein Capture Event durch einen anderen Timer zu triggern. Die Lösung, den Encoder hardwareseitig an beide Timer anzuschließen, ist irgendwie aber auch nicht das Gelbe vom Ei.
Der Drehzahlmessbereich ist mit einer Messung der Positionsänderung immer schlecht. Jage die Positionsistwerte durch eine PLL die der Motorposition folgt. Dann hast du eine saubere Drehzahl.
Servus, so wie ich das verstanden haben: Kaskadenregelung, wobei nur ein Encodersignal vorhanden ist. Nun gut, nur so nebenbei es gibt auch Tachogenerator fürn Motor. Das Problem ist die Zusatzkosten + wo kommt der Encoder hin. Mit den Encoder misst man doch nur den Winkel. Dann gilt: omega=d_pfi/dt. Hier schließt sich heraus, dass man nur eine Differenzenbildung machen muss und diese durch die Abtastzeit teilen. WorstCase: Motor hat mehrere Umdrehung gemacht wärend der Abtastzeit. Wie bestimmt man das? Ich würde die Encoder Register auf volle 16bit setzen, dann kann sowas nicht passieren. Bei jeder Abtastung Differenz bilden und Register wieder Rücksetzen. Ganz einfach. Eventuell noch ein Tiefpass verpassen. Eine andere Möglichkeit wäre: Viele Encoder geben ein zusätzliches Signal bei einer bestimmten Umdrehung, k.A etwa 90° oder bei voller Umdrehung. Ja, die könnte man mit einen Interrupt auch anzpfen. Ist aber meiner Meinung nach unnötig. mfg
Ach ja, wenn die das KnowHow vorhanden ist, dann kann man Luenberger Beobachter anwenden. Steht ja in den Paper alles drin. Dadurch läuft der Motor schön geschmeidig. :P
Kaskadenregelung ist schon richtig, wobei ich im sehr kleinen Drehzahlbereich, d.h. ca. 0-250 rpm, unterwegs bin und aus Platzmangel leider nur einen Encoder habe. Eine PLL und sin/cos-basierte Kalmanfilter kommen daher wohl weniger in Frage. Am liebsten würde ich ohne Systemmodell arbeiten, da die Störgrößen bei mir dominieren. Aufgrund der geringen Drehzahl könnte man in diesem Fall sicher noch mit Interrupts arbeiten und sich die Zeit dazu abspeichern. Bei 4 Umdrehungen pro Sekunde und einem üblichen Encoder (2048 Flanken) würde die Interrupt-Frequenz im Höchstfall rund 8 kHz betragen. Schön wäre es natürlich trotzdem, wenn sich das ohne große CPU Belastung realisieren ließe. Folgende Frickelei habe ich mir jetzt mal für den STM32 überlegt: - Timer 1 läuft im Encoder-Modus und resettet sich bei einem Wert von 1 - Timer 2 läuft im Normalbetrieb durch eine Clock der MCU getaktet - Timer 2 ist Slave von Timer 1 und wird durch dessen Reset selbst resettet, also nach jedem Encoder-Tick - Timer 3 ist Slave von Timer 2 und zählt bei einem Reset von Timer 2 eins hoch Dann hat man in Timer 3 die aufsummierten Encoderticks und in Timer 2 kann man immer nachschauen, wie lange der letzte Tick zurückliegt. Funktioniert aber natürlich nur in einer Drehrichtung und verbraucht doch recht viele Timer...
Dino H. schrieb: > Kaskadenregelung ist schon richtig, wobei ich im sehr kleinen > Drehzahlbereich, d.h. ca. 0-250 rpm, unterwegs bin und aus Platzmangel > leider nur einen Encoder habe. Eine PLL und sin/cos-basierte > Kalmanfilter kommen daher wohl weniger in Frage. Am liebsten würde ich > ohne Systemmodell arbeiten, da die Störgrößen bei mir dominieren. Ah was bitte? Gerade bei niedrigen Drehzahlen bekommst du doch gerade wenig Impulse rein. Und mit der Timer Methode hast du dann eine untere Grenzfrequenz, ab der du die Drehzahl als null an sehen musst! Wenn von einem Abtastzeitpunkt zum nächsten sich die Encoder Position nicht geändert hat und sich diese erst im 2. Abtastschritt ändert. Das sorgt für Vibrationen im Regler und auf der Welle. Und was bitte kostet dich eine PLL? 2 Parameter und 2 Multiplikationen und 3 Additionen uhhhh und das bei 1ms Abtastfrequenz dafür braucht man sicher einen i7 mit 5GHz???? Ich kann verstehen das du keinen Lunenberger oder n Kalmanfilter dimensionieren möchtest, OK. Aber einen PI Regler und ein Integrator sollten bei der Anwendung schon drin sein. Und du hast ein F4 also ne FPU, dann mach sie auch an! Und nutze die Auflösung die dir das Ding liefert. Dino H. schrieb: > Folgende Frickelei habe ich mir jetzt mal für den STM32 überlegt: > - Timer 1 läuft im Encoder-Modus und resettet sich bei einem Wert von 1 > - Timer 2 läuft im Normalbetrieb durch eine Clock der MCU getaktet > - Timer 2 ist Slave von Timer 1 und wird durch dessen Reset selbst > resettet, also nach jedem Encoder-Tick > - Timer 3 ist Slave von Timer 2 und zählt bei einem Reset von Timer 2 > eins hoch Super du hast einen Frequenzzähler gebaut, das ist ein halbwegs sinnvoller Ansatz. Frage: Was passiert wenn der Antrieb ganz langsam weg driftet um sagen wir 10 Steps pro Sekunde? oder noch weniger? Gruß Tec
:
Bearbeitet durch User
Also beim PIC µC habe ich das über Timer und VELxCNT gemacht. Das ist jetzt eine Berechnung für ein Motor mit Encoder 8192 Puls je Phase pro Umdrehung:
1 | /********************************************************************************
|
2 | * 1,831 ms Timer Interrupt, fuer Speed Berechnung
|
3 | * 10000 Upm / 60 sekunden = 83,3333 Umdrehung/Sekunde
|
4 | * 166,67 Umdrehung/Sekunde * 32768 schritte (8192pulse*4) = 5461442,56 Schritte pro Sekunde
|
5 | * Interuppt: 1831µs = 5000UpM (max Motor) / 5461442,56 Schritte pro Sekunde
|
6 | * 70000000 MIPS / 1000000µs * 1831µs = 128170 (0x1F4AA)
|
7 | *********************************************************************************/
|
8 | void __attribute__((__interrupt__,no_auto_psv)) _T7Interrupt(void) |
9 | {
|
10 | IFS3bits.T7IF = 0; //Clear Timer7 interrupt flag |
11 | |
12 | velocity_tmp = VEL1CNT; |
13 | |
14 | if (velocity_tmp<0) |
15 | {velocity_positiv = velocity_tmp* (-1);} |
16 | else
|
17 | {velocity_positiv = velocity_tmp;} |
18 | }
|
Hallo zusammen, auch ich messe die Drehzahl mit einem Encoder. Ich habe einen Timer (TIM1) der für die Erzeugung von PWM zuständig ist. Dieser ist in Center-Aligned-Mode konfiguriert. Bei jedem Überlauf bzw. wenn der max. Wert von 2047 erreicht wird, wird ein Interrupt ausgelöst. In der ISR wird der Zählerstand des Encoder-Timers abgespeichert (in der Variable zaehlerstand_neu). In einer zweiten Variable (zaehlerstand_alt) ist am Anfang eine 0 gespeichert. Als nächstes berechne ich die Differenz dieser zwei Variablen. Hiermit weiß ich, um wieviel Encoderschritte der Rotor sich bewegt hat. Da das ganze in einer ISR berechnet wird, weiß ich auch die Zeit. Ich habe also den Weg und die Zeit(die Sample Time), die zwei Sachen die man benötigt um eine Geschwindigkeit(Drehzahl) zu berechnen. Ich hier nicht viel zu viel erklären weil es dann zu viel wird. Hier mein Code:
1 | void Encoder_TimerInit(void) |
2 | {
|
3 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); |
4 | |
5 | GPIO_InitTypeDef GPIO_InitStructure; |
6 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; |
7 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; |
8 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
9 | GPIO_Init(GPIOB, &GPIO_InitStructure); |
10 | |
11 | GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // siehe s.178 ReferenceManual |
12 | |
13 | |
14 | // Timer-Peripherietakt aktivieren
|
15 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); |
16 | |
17 | // Modus einstellen
|
18 | TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge, TIM_ICPolarity_BothEdge); |
19 | |
20 | // Maxwert setzen
|
21 | TIM_SetAutoreload(TIM3, 3999); |
22 | |
23 | // Timer aktivieren
|
24 | TIM_Cmd(TIM3, ENABLE); |
25 | |
26 | RCC_ClocksTypeDef RCC_Takte; |
27 | RCC_GetClocksFreq(&RCC_Takte); |
28 | |
29 | f_TIM1 = RCC_Takte.PCLK2_Frequency; |
30 | f_T_CA = ((int64_t)(f_TIM1))/((int64_t)4094); |
31 | x = ((((int64_t)4000)<<20))/((f_T_CA)); |
32 | }
|
33 | |
34 | |
35 | |
36 | /*** Drehzahlberechnung *****************/
|
37 | |
38 | int16_t drehzahl(void) |
39 | {
|
40 | direction = (TIM3->CR1 & TIM_CR1_DIR)>>4; |
41 | |
42 | zaehlerstand_neu = TIM_GetCounter(TIM3); |
43 | |
44 | if (direction == 0) /********************************** hochzählen **************/ |
45 | {
|
46 | if(zaehlerstand_neu >= zaehlerstand_alt) |
47 | {
|
48 | ups = (int16_t)((((int64_t)(zaehlerstand_neu - zaehlerstand_alt)<<40)/x)>>20); |
49 | }
|
50 | else
|
51 | {
|
52 | ups = (int16_t)((((int64_t)(zaehlerstand_neu + 4000 - zaehlerstand_alt)<<40)/x)>>20); |
53 | }
|
54 | }
|
55 | else /****************************** herunterzählen **************/ |
56 | {
|
57 | if(zaehlerstand_alt >= zaehlerstand_neu) |
58 | {
|
59 | ups = (zaehlerstand_alt - zaehlerstand_neu)/4 ; |
60 | }
|
61 | else
|
62 | {
|
63 | ups = (zaehlerstand_alt + 4000 - zaehlerstand_neu)/4 ; |
64 | }
|
65 | }
|
66 | |
67 | |
68 | zaehlerstand_alt = zaehlerstand_neu; |
69 | |
70 | |
71 | return ups; |
72 | }
|
Hinweise: Mein Encoder liefert mir 4000 Schritte pro Umdrehung. Die Auflösung der Drehzahl ist 2 und besser gehts leider nicht. Gruß
Der Wunsch ist klar. 2 Pins liefern das Encoder Signal und ein Timer ist als QuadraturEncoder eingestellt. Ein zweiter Timer wird als InputCapture verwendet und misst die Dauer zwischen zwei Pulsen. So bekommt man die Vorteile beider Welten - Position plus Zeit zwischen zwei Puls in Hardware gemessen. Ohne Overhead von Interrupts, Genauigkeit etc. Die Lösung dafür ist Master Slave. Den Encoder Timer konfiguriert man als Master, der immer einen Puls ausgeben soll MMS=0b011 (TIM_TRGO_OC1). Und der zweite Timer ist ein normaler InputCapture, nur dass er als Input Signal nicht einen Pin annimmt, sondern den Master. Dazu muss man nachsehen welcher Timer der Master ist, welcher Slave diesen auswerten kann und wie dessen interne Verbindung heißt, z.B. sSlaveConfig.InputTrigger = TIM_TS_ITR1; Soweit so gut. Jetzt muss ich es nur noch zum Laufen bringen. PS: Wegen Genauigkeit... Rein über die Pos-Änderung, muss man die Position periodisch auslesen. Je öfter, um so genauer ist die Geschwindigkeit. Was aber wenn die Position gleich, weil z.B. alle 20ms die Positionsänderung ausgewertet wird, aber das Rad sich so langsam dreht? Gut, die Lösung dafür ist sich zu merken wann die letzte Positionsänderung war, so kommt man auch auf Geschwindigkeiten wie 0.5. Aber nur noch mit einer Genauigkeit von +-20ms. Alles nicht optimal....
:
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.