Hi Leute, habt Ihr vielleicht einen Tipp, wie ich die Drehzahl eines Motor mittels einer Encoderscheibe ermittel? Die Encoder Signale kann ich bereits auslesen und bekomme eine Reihe von Impulsen. Wie kann ich jetzt aus diesen Impulsen die Drehzahl ermitteln? Dank für eure Hilfe. Gruß Chillymu
Du brauchst dann noch einen Zähler für die Tor-Zeit, innerhalb dieser zählst du die Pulse und wenn die Zeit abgeleuafen ist, übertägst du den Zählerstand in ein Register, was dann auslesbar ist und setzt den Zähler zurück.
Nachdem die Drehgeschwindigkeit Winkel/Zeit ist und ein Impuls einen bestimmten Winkel repräsentiert, hast du zwei Möglichkeiten: Entwder für eine feste zeit die Anzahl der Pulse zählen oder die Dauer zwischen zwei Pulsen auswerten. Dazu reicht das Auswerten einer Spur. Die zweite Spur liefert Pulse, die 90° versetzt zu der anderen Spur sind. Wenn du die auch auswertest, kannst du zum einen eine höhere Auflösung erzielen und zum anderen die Drehrichtung. Das erfolgt dann sinnvollerweise über einen Zustandsautomaten
Andreas Müller schrieb: > Wie kann ich jetzt aus diesen Impulsen die Drehzahl ermitteln? In welcher Einheit und mit welcher Genauigkeit willst du die Drehzahl ermitteln? > Die Encoder Signale kann ich bereits auslesen und bekomme eine Reihe von > Impulsen. Naja, die Impulse kommen ja schon von dem Encoder selber. Oder was meinst du mit dieser "Reihe von Impulsen"? Schlumpf schrieb: > die Dauer zwischen zwei Pulsen auswerten. Ist ungünstig, weil der erhaltene Wert reziprok zur Drehzahl ist.
Lothar Miller schrieb: >> die Dauer zwischen zwei Pulsen auswerten. > Ist ungünstig, weil der erhaltene Wert reziprok zur Drehzahl ist. Ist aber günstig, wenn man sehr geringe Drehzahlen noch einigermaßen genau erfassen will ;-) Die Wahl der Methode hängt halt vom Anwendungsfall ab. Aber ich gebe dir recht: In den typischen Fällen wird man sicher die Anzahl der Impulse in einem Zeitfenster auswerten. Dem TO möchte ich aber noch empfehlen, beide Spuren auszuwerten, auch wenn er die Drehrichtung nicht benötigt. Falls bei Stillstand die Achse genau um einen Decoderstrich hin und her wackelt, würde er beim Auswerten nur einer Spur eine Frequenz erhalten, also "Drehzahl" messen. Diese Fehlinterpretation lässt sich durch Plausibilisierung beider Spuren besser beherrschen.
Lothar: Als Einheit dachte ich Impulse pro ms. Da es 1600 impulse pro Umdrehung sind, ergibt das 0.225 Grad pro Impuls. So kann ich das in Grad pro s umrechnen und dadurch auch auf Weg pro Sekunde umrechnen. Also ist die Grundsätzliche Einheit Impulse/ms. Das die Impulse vom Encoder kommen stimmt, aber wie zähle ich diese Impulsflanken und kann diesen Wert dann in einem Register speichern? Dieser soll sich aber nur jede ms ändern.
Dann noch ein ms Timer der einen FIFO mit dem Zählerstand füttert und ein Subtrahierer. Das Ergebnis ist dann die Impulsdifferenz pro ms. Allerdings wird das nicht sonderlich funktionieren. Evtl das Abtastintervall größer machen und das Ergebnis noch etwas filtern! ?
@ Andreas: Beantworte doch mal bitte die folgenden Fragen: 1.) Du hast ganz am Anfang einen Block angehängt. Willst du diesen Block mit "Leben" füllen, oder hast du den bereits und willst die Informationen die dieser ausspuckt, weiterverarbeiten? 2.) Suchst du nach einer prinzipiellen Methode, wie man aus Impulsen zu einer Drehzahl kommt? --> Das wäre ja jetzt bereits beantwortet 3.) Kennst du dich in VHDL oder Verilog aus? Also weisst du, wie man Register, Counter, Timer etc in einer HDL beschreibt und sind dir Schlagworte wie "synchrones Design", "Eingänge einsynchronisieren", etc ein Begriff, oder bist du absoluter FPGA/VHDL-Neuling?
Andreas Müller schrieb: > Lothar: > dadurch auch auf Weg pro Sekunde umrechnen. Willst letztlich die lineare Geschwindigkeit von irgendwas? Dann würde ich dir empfehlen, die Abtastzeit so zu wählen, dass gleich die Geschwindigkeit in der endgültigen Einheit herauskommt. Denn > die Grundsätzliche Einheit Impulse/ms. in in Hardware in irgendwas anderes umzurechnen ist und aufwendig. > Das die Impulse vom Encoder kommen stimmt, aber wie zähle ich diese > Impulsflanken und kann diesen Wert dann in einem Register speichern? > Dieser soll sich aber nur jede ms ändern. Siehe die Fragen vom Schlupf... Dazu 4.) welche Hardware hast du für diese Auswertung?
Hallo. Schlumpf: Zu 1): Ja der Block ist bereits fertig und funktioniert super. Er liefert mir aus den beiden Encodersignalen eine Reihe von Impulsen. Diese möchte ich weiter verarbeiten um später vielleicht ein Regelung zu erarbeiten zur genauen Positionierung. Zu 2) Ja. Vorerst suche ich nach einer Methode um aus Impulsen eine Drehzahl zu ermitteln. Das werde ich morgen gleich mal versuchen. Im Prinzip suche ich nach einer Regelung zur genauen Positionierung und dachte dies wäre ein erster Schritt bevor es an die Regelung geht. Da bräuchte ich ebenfalls einen Denkanstoß. Zu 3) In Vhdl kenn ich mich schon ganz gut aus. Hab auch schon einiges gemacht, doch derzeit steh ich etwas auf dem Schlauch um zur Lösung zu kommen. Wie würde ich prinzipell vorgehen wenn ich einen DC-Motor mit Encoderscheibe hätte und möchte damit eine Position anfahren. Ich dachte da an einen PID-Regler oder wie seht ihr das? Die Hardware ist ein Cyclone II Board von mir entwickelt, mit einem Nios II drin. Funktioniert einwandfrei.
Andreas Müller schrieb: > Wie würde ich prinzipell vorgehen wenn ich einen DC-Motor mit > Encoderscheibe hätte und möchte damit eine Position anfahren. Ich dachte > da an einen PID-Regler oder wie seht ihr das? WEnn die Strecke das mitmacht... ;-) PID sagt ja noch nichts über die Verhältnisse zwischen P, I und D aus. Worauf soll denn der Regler laufen? Auf dem NIOS? > Das die Impulse vom Encoder kommen stimmt, aber wie zähle ich diese > Impulsflanken Das ist doch ganz einfach: du willst keine Geschwindigkeit, sondern eine Position ermitteln. Und genau das ist mit einem Inkrementalgeber ein leichtes Spiel: http://www.lothar-miller.de/s9y/categories/46-Encoder Und diese Position speicherst du dann einfach jede ms (diese Zeit wird einfach mit einem Zähler aus der Quarzfrequenz hergeleitet) in ein Register. Fertig ist die Laube. Mit deutlich weniger als 50 Zeilen VHDL bist du am Ziel...
@ Andreas: zu 1) Prima! dann gehe ich jetzt mal stillschweingend davon aus, dass die Ausgangssignale des Blocks bereits synchron zu deinem Systemtakt im FPGA sind. zu 2) Die Drehzahl könntest du dann ermitteln, indem du einen Timer und einen Counter baust. Der Timer läuft immer schön im Kreis Während der Timer läuft, zählst du die Impulse (entweder vorzeichenbehaftet, wenn du die Position willst, oder eben ohne, wenn du nur die Drehzahl willst) Kommt der Timer durch den Nulldurchgang, dann kopierst du die Werte des Counters (Anzahl der Impulse im letzten Messintervall) in ein Register und setzt den Counter zurück. Parallel dazu machst du noch einen Triggerimpuls für deine Regelung, dass ein neuer Messwert vorliegt. zu 3) Wenn dem so ist, dann sollte die Umsetzung von 2) kein Problem darstellen, nehme ich mal an. Andreas Müller schrieb: > Wie würde ich prinzipell vorgehen wenn ich einen DC-Motor mit > Encoderscheibe hätte und möchte damit eine Position anfahren. Ich dachte > da an einen PID-Regler oder wie seht ihr das? Richtig. ABER, so einfach, wie es vielleicht grad erscheint, ist es nicht. Die Regelparameter für P-, I- und D-Anteil müssen so ermittelt werden, dass der Motor nachher nicht Tango tanzt. Vorallem brauchst du dazu meines Erachtens einen geschachtelten Regler. Einen Regler für die Geschwindigkeit und einen anderen für die Position. Oder willst du Vollgas bis zur Sollposition fahren, dann über´s Ziel hinausschießen, dann wieder vollgas zurück usw.. ich meine, so parken manche Leute ein, aber schön ist das nicht gg
Alles klar. Ich werde den Tipp von Lothar morgen mal versuchen und gebe Bescheid. Danke.
Worüber Du auch noch nachdenken musst, ist eine Filterung der Daten, damit Du keine digitalen Abtastfehler in die Geschwindigkeit miteinrechnest, sowie eine Totzeit-Vorberechnung, damit Du keine falschen Beschleunigungswerte miteinrechnest und eine Linearitätskorrektur, die die Ungleichmässigkeiten der Encoderscheibe vorkompensiert.
Hi Lothar, ich habe im jetzt deine Positionsermittlung genommen und entsprechend meinen Bedürfnissen modifiziert. Das ist dabei herausgekommen:
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | use IEEE.NUMERIC_STD.ALL; |
4 | |
5 | entity Encoder_Pos is |
6 | Generic(Clock_Counter : INTEGER := 81920 |
7 | );
|
8 | Port ( clk : in STD_LOGIC; |
9 | A : in STD_LOGIC; |
10 | B : in STD_LOGIC; |
11 | Up_Dn : out STD_LOGIC; |
12 | Position_ms : out STD_LOGIC_VECTOR (31 downto 0); |
13 | Position_act : out STD_LOGIC_VECTOR (31 downto 0); |
14 | Position_ms_dif : out STD_LOGIC_VECTOR (31 downto 0)); |
15 | end Encoder_Pos; |
16 | |
17 | architecture Behavioral of Encoder_Pos is |
18 | type zustaende is (Z00, Z01, Z11, Z10); |
19 | signal z : zustaende := Z00; |
20 | signal p : integer := 0; |
21 | signal p2 : integer := 0; |
22 | signal p_old : integer := 0; |
23 | signal p_dif : integer := 0; |
24 | signal i : std_logic_vector(1 downto 0); |
25 | signal e : std_logic_vector(1 downto 0); |
26 | signal clock_ctr : integer := 0; |
27 | signal pos_reg : std_logic_vector(31 downto 0) := (OTHERS => '0'); |
28 | signal up_dn_reg : std_logic := '0'; |
29 | begin
|
30 | process begin -- Eintakten der asynchronen Signale |
31 | wait until rising_edge(clk); |
32 | i <= A & B; -- Zusammenfassen der Eingänge A und B |
33 | e <= i; |
34 | end process; |
35 | |
36 | process -- Weiterschalten und Zählen |
37 | variable cu, cd : std_logic := '0'; |
38 | begin
|
39 | wait until rising_edge(clk); |
40 | cu := '0'; -- lokale Werte |
41 | cd := '0'; |
42 | case z is |
43 | when Z00 => if (e = "01") then z <= Z01; cu := '1'; |
44 | elsif (e = "10") then z <= Z10; cd := '1'; |
45 | end if; |
46 | when Z01 => if (e = "11") then z <= Z11; cu := '1'; |
47 | elsif (e = "00") then z <= Z00; cd := '1'; |
48 | end if; |
49 | when Z11 => if (e = "10") then z <= Z10; cu := '1'; |
50 | elsif (e = "01") then z <= Z01; cd := '1'; |
51 | end if; |
52 | when Z10 => if (e = "00") then z <= Z00; cu := '1'; |
53 | elsif (e = "11") then z <= Z11; cd := '1'; |
54 | end if; |
55 | end case; |
56 | if (cu='1') then |
57 | p <= p+1; |
58 | up_dn_reg <= '1'; |
59 | elsif (cd='1')then |
60 | p <= p-1; |
61 | up_dn_reg <= '0'; |
62 | end if; |
63 | end process; |
64 | |
65 | process begin -- Takt Zählen |
66 | wait until rising_edge(clk); |
67 | clock_ctr <= clock_ctr + 1; -- Zählt den Takt |
68 | if (clock_ctr=1) then |
69 | if (up_dn_reg='1') then p_dif <= p - p_old; |
70 | elsif (up_dn_reg='0') then p_dif <= p_old - p; |
71 | end if; |
72 | end if; |
73 | if (clock_ctr=Clock_Counter-1) then |
74 | p_old <= p2; |
75 | end if; |
76 | if (clock_ctr=Clock_Counter) then |
77 | pos_reg <= std_logic_vector(to_signed(p,32)); |
78 | p2 <= p; |
79 | clock_ctr <= 0; |
80 | end if; |
81 | end process; |
82 | Position_ms <= pos_reg; -- Position gemessen je Zähleinheit |
83 | Position_act <= std_logic_vector(to_signed(p,32)); -- Position ausgeben |
84 | Position_ms_dif <= std_logic_vector(to_signed(p_dif,32)); -- Impulse pro Taktzähler |
85 | Up_Dn <= up_dn_reg; -- Richtung |
86 | end Behavioral; |
Dabei ist der Ausgang Position_ms_dif der Berechnete Wert für Impulse pro ms. Funktioniert super. Ich habe dies an meinen NIOSII angeschlossen und kann nun die Impulse pro ms lesen.(siehe Bild) Freu, Freu. Habt ihr jetzt vielleicht eine Idee wie ich das mit der Positionierung mache. Ich müsste ja rein theoretisch eine Art Trapezfahrt ausführen. D.h. langsam anfahren auf die Zielgeschwindigkeit und kurz vor dem erreichen des Ziels langsamer werden. So wie Schlumpf schon sagt: Einparken alla vor zurück ist nich sonderlich schön. Irgend einen Vorschlag??
Andreas Müller schrieb: > Ich müsste ja rein theoretisch eine Art Trapezfahrt ausführen. D.h. > langsam anfahren auf die Zielgeschwindigkeit und kurz vor dem erreichen > des Ziels langsamer werden. Da müsste man mehr über die Strecke wissen. > So wie Schlumpf schon sagt: Einparken alla vor zurück ist nich > sonderlich schön. Ein PID Regler muss nicht zwingend überschwingen... Das hatte ich befürchtet:
1 | if (cu='1') then |
2 | p <= p+1; -- warum nicht gleich hier und ... |
3 | up_dn_reg <= '1'; |
4 | elsif (cd='1')then |
5 | p <= p-1; -- ... hier zählen |
6 | up_dn_reg <= '0'; |
7 | end if; |
8 | end process; |
9 | |
10 | process begin -- Takt Zählen |
11 | wait until rising_edge(clk); |
12 | clock_ctr <= clock_ctr + 1; -- Zählt den Takt |
13 | if (clock_ctr=1) then |
14 | if (up_dn_reg='1') then p_dif <= p - p_old; -- und stattdessen kompliziert zurückrechnen? |
15 | elsif (up_dn_reg='0') then p_dif <= p_old - p; |
Warum rechnest du erst eine Strecke aus und daraus wieder einen
Zählerwert?
Mit ein wenig Nachdenken siehst du, dass das irgendwie doppelt gemoppelt
ist...
> signal clock_ctr : integer := 0;
Bitte nicht mit solchen Schlampereien anfangen! Wozu brauchst du hier
einen 32-Bit-Zahl? Schränke gleich zu Beginn den Zähler so ein, dass dir
der Simulator auf die Finger klopfen kann, wenn der Zähler Amok läuft.
:
Bearbeitet durch Moderator
Die Beschränkung des Integerwerts habe ich gemacht. Da hast du recht. Bei dem anderen Punkt muss ich mir überlegen wie ich das zusammenfasse. Wäre bestimmt eleganter. Nochmal zum Drehzahlregler: Wenn ich eine P-Regler nehme(abgesehen davon ob das Sinn macht oder nicht), wie würde der Theoretisch aussehen? Eine Regel Strecke sieht im allgemeinen so aus wie im Bild. Dabei ist w = Soll-Drehzahl(z.B. 6 Imp/ms) x = Ist-Drehzahl(z.B. bei Start 0 Imp/ms) e = w-x(z.B. 6 Imp/ms) y = Kp * e Wo fließt jetzt mein PWM-Wert ein. Bei dem ich den duty-cycle ändere? y müsste doch in diesem Fall der duty-cycle wert sein, oder?
Könnt Ihr mir nochmal kurz erklären wie ich eine einfachen P-Regler in VHDL erstellen würde bei dem ich Kp einstellbar machen würde. Gibt es da vielleicht schon einen fertigen Block für den P-Regler?
Lothar Miller schrieb: > Ein PID Regler muss nicht zwingend überschwingen... Richtig, das stimmt. Aber Der TO will auf eine Position regeln, nimmt aber als Eingangsgröße für seinen Regler die Drehzahl und das geht schief. Andreas Müller schrieb: > Könnt Ihr mir nochmal kurz erklären wie ich eine einfachen P-Regler in > VHDL erstellen würde bei dem ich Kp einstellbar machen würde. Kp könnte in einem Register liegen, welches du von "außen" über einen µC, Dipswitches, Poti oder sonstwas veränderbar machst.
Andreas Müller schrieb: > eine einfachen P-Regler in VHDL Das ist m.E. der falsche Ansatz, wenn du >>> mit einem Nios II regeln könntest... :-/ Sowas schnarchlangsames wie eine Positionsregelung eines Motors ist doch in C einfacher zu debuggen als in VHDL. > Könnt Ihr mir nochmal kurz erklären wie ich eine einfachen P-Regler in > VHDL erstellen würde bei dem ich Kp einstellbar machen würde. Wie würdest du das denn in C machen? > Gibt es da vielleicht schon einen fertigen Block für den P-Regler? Sowas kannst du sicher irgendwo kaufen, aber ein P-Regler ist ja nichts weiter als eine Subtraktion (für e) und eine Multiplikation (mit kp), das dürfte nicht allzu schwer sein. Ich würde sagen, mit höchstens 30 Zeilen VHDL-Code bekommt man ein eigenes VHDL-P-Regler-Modul...
:
Bearbeitet durch Moderator
Da hast du schon recht. Ich werde die Drehzahlregelung jetzt im c-Code des Nios machen. Das ist fürs erste einfacher uns schneller zu realisieren. Dennoch ist immernoch die Frage ob ich bei der anschließenden Positionierung etwas beachten muss un da so genau wie möglich zu werden?
Andreas Müller schrieb: > Dennoch ist immernoch die Frage ob ich bei der anschließenden > Positionierung etwas beachten muss un da so genau wie möglich zu werden? Ja, musst du. Wenn du auf eine Position regeln willst, dann musst du als Eingangsgrößen für deinen Regler die Soll-Position und die Ist-Position nehmen und nicht die Drehzahl.
Noch ein paar Tips aus jahrelanger Encoder-Auswerte-Raxis: - Das Einsynchronisieren der Eingänge zum FPGA-Takt ist wirklich sehr wichtig (siehe Lothars Homepage)! - Es kann passieren, daß der Encoder im (scheinbaren) Stillstand prellt, d.h. ein Signal (A oder B) "wackelt herum", obwohl sich eigentlich nichts bewegt. Aus diesem Grund ist es nicht verkehrt, einen Positionsänderung erst dann zu übernehmen, wenn sich beide Signale (A und B) geänderten haben. - Jenachdem wie Dein Encoder mechanisch an den Motor angeschlossen ist, mußt Du ggf. Schlupf beachten.
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.