Drehzahlmessung mit Encoderscheibe

OP #3477724
Lesenswert?

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
Angehängte Dateien:
Gast #3477907
Lesenswert?

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
Moderator (Firma: Titel) Persönliche Seite #3477995
Lesenswert?

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.
Gast #3478250
Lesenswert?

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.
OP #3478266
Lesenswert?

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.
Gast #3478293
Lesenswert?

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! ?
Gast #3478414
Lesenswert?

@ 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?
Moderator (Firma: Titel) Persönliche Seite #3478457
Lesenswert?

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?
OP #3478535
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #3478553
Lesenswert?

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...
Gast #3478581
Lesenswert?

@ 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
Gast #3478825
Lesenswert?

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.
OP #3479560
Lesenswert?

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??
Angehängte Dateien:
Moderator (Firma: Titel) Persönliche Seite #3479582
Lesenswert?

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.
OP #3479646
Lesenswert?

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?
Angehängte Dateien:
Gast #3480811
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #3480868
Lesenswert?

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...
OP #3484014
Lesenswert?

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?
Gast #3484726
Lesenswert?

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.
Gast #3495885
Lesenswert?

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.

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