Forum: Mikrocontroller und Digitale Elektronik Elektrische Rotorposition mittels optical encoder


von Andreas T. (skycurve)


Lesenswert?

Guten Abend,

ich möchte die elektrische Rotorlage mit einem optischen Encoder 
bestimmen.
Von dem Encoder bekomme ich die Signale A und B (GrayCode) welche ich in 
einem Timer IRQ verarbeite:
1
float angle = 0.0;
2
int limit = 4096;
3
4
int table[4][4]={{0,1,-1,0},{-1,0,0,1},{1,0,0,-1},{0,-1,1,0}};
5
int position=0; // zaehlen wir mal die absolute Position
6
volatile int quadrature_input; // bit 0 und bit 1 sind Quadratureingaenge
7
int new_quadrature_value, last_quadrature_value=0;
8
9
void TIM2_IRQHandler(void)
10
{
11
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
12
  {
13
    quadrature_input = GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2) * 2 + GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_1) * 1;
14
    new_quadrature_value=quadrature_input;
15
    position+=table[last_quadrature_value][new_quadrature_value];
16
    last_quadrature_value=new_quadrature_value;
17
18
    if(position == limit) position = 0;
19
    if(position == -1) position = limit-1;
20
21
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
22
23
  }
24
}

Da der Zähler von dem Encoder pro reale Umdrehung um 4096 erhöht wird, 
setze ich ihn alle 4096 wieder auf null um so eine zyklische Zählung zu 
erhalten (siehe die zwei if's)
Der mit dem Encoder verbundene Motor macht pro reale Umdrehung 7 
elektrische Umdrehungen.
Die Berechnung des elektrischen Winkels (in rad) sieht folgendermaßen 
aus:
1
  float position_p = (float)position;
2
  // 4096 / 7 = 585.1428571
3
  while(position_p > 585.1428571)
4
  {
5
    position_p -= 585.1428571;
6
  }
7
8
  // 2PI / 585.1428571 = 0.01073786552
9
  angle = (position_p)*0.01073786552;

Der BLDC Motor wird mit einem festen, langsamen, Drehfeld gesteuert, 
sprich ich weiß programmintern, welcher elektrischer Winkel gerade 
anliegt.
Der vom Encoder berechnete Winkel driftet allerdings vom fest 
vorgegebenen Winkel langsam ab.
Die Erklärung dazu wäre ja dass meine Float Werte nicht unendlich genau 
sind, aber wie kann der Winkel driften, wenn ich quasi jedes mal mit dem 
inkrementierten Wert (Integer) neu rechne?

Wie berechnet man den Winkel bei so einer Krummen Polzahl korrekt? Die 
ganze Float Sache ist ja nicht besonders schön.
Davor hatte ich einen Motor, welcher 8 elektr. Rotationen pro Umdrehung 
macht, da war es kein Problem, denn 4096 / 8 = 512 (=kein Float, schöner 
runder Wert)

(Es ist mir wichtig, dass der Winkel am Ende als Fließkommazahl in Rad 
vorliegt)

Grüße,
Andreas

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Vielleicht habe ich's nicht verstanden, aber hilft Dir der "Kleinste 
gemeinsame Vielfache" (KgV) weiter, um mit int zu rechenen?

von drama (Gast)


Lesenswert?

Wenn möglich, solltest du die Hardwareunterstützung für Quadraturencoder 
verwenden. Was ist das für ein Mikrocontroller? STM32 oder XMEGA z.B. 
haben das. Softwarelösungen sind prinzipiell sehr empfindlich. Funkt ein 
anderer IRQ kurzfristig dazwischen, verliert man u.U. einen Click und 
Ähnliches...

Drift bei deiner Anwendung hat man aber prinzipiell immer, denn die 
Fertigungsgenauigkeit eines Drehgebers ist begrenzt. Bei nominalen 4096 
CPR hast du vielleicht tatsächliche 4095.8 CPR o.ä. Eventuell ist das 
sogar temperaturabhängig. Die mangelnde Precision von Floats ist das 
kleinste Problem!

Es gibt aber eine Lösung: Encoder mit Indexsignal nehmen und beim 
Nullpunkt den Wert zurücksetzen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

drama schrieb:
> Quadraturencoder

Kann der GrayCode!?

drama schrieb:
> Encoder mit Indexsignal

Was meinst Du damit im Gegensatz zum GrayCode?

drama schrieb:
> Drift bei deiner Anwendung hat man aber prinzipiell immer, denn die
> Fertigungsgenauigkeit eines Drehgebers ist begrenzt.

Eine Umdrehung ist eine Umdrehung! Die GrayCode-Scheibe kann sich doch 
nicht drehen.

Ich denke "Softwarelösungen sind prinzipiell sehr empfindlich" ist der 
richtige Hinweis.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Andreas True schrieb:
> Von dem Encoder bekomme ich die Signale A und B (GrayCode)

Das ist kein richtiger Graycode, sondern schlichte Quadratursignale, hat 
sich aber wohl schon geklärt. Warum adaptierst du nicht PeDas Drehgeber 
Routine auf den STM32? Die läuft sehr zuverlässig und ist auch auf 
verschiedene Quadratursignale anpassbar (1,2 und 4 stufig).

Deine ISR verliert nämlich beim hin- und herdrehen ab und zu mal einen 
Step, das ist der Haken, wenn man nur ein Signal (A oder B) zum 
Auslösen der ISR nimmt.
Beitrag "Drehgeber/Encoder 1-, 2- oder 4-schrittig"

Da hier nur ein Timer benutzt wird, und der STM32 davon mehr als genug 
hat, sollte das ohne Probleme klappen.

: Bearbeitet durch User
von Dispol (Gast)


Lesenswert?

>wenn man nur ein Signal (A oder B) zum Auslösen der ISR nimmt
Er benutzt doch gar keinen Flanke, um die Dekodierung zu triggern, 
sondern einen Timer. Und solange innerhalb dieser Zeitperiode nie 2 
Impulse in die gleiche Richtung kommen wird es kleine Probleme geben. 
Die Auswertung sieht richtig aus.

Allerdings sehen ich auch in der Float Umrechnung kein Problem. Klar 
gibt es kleine Fehler, aber die akkumulieren sich hier doch nicht auf. 
Angenommen, "position" steht nach x Umdrehungen wieder auf 0. Der 
Drehgehen also in der Ursprungslage, dann ist position_p = 0 und auch 
angle.

Kannst Du das testen? Also Drehgeber markieren, Lage 0, Drehgeber bei 
0°.
Lange drehen lassen. Rotor wieder auf 0° drehen.
Steht dann die Variable "position" auch auf (fast)0?

von m.n. (Gast)


Lesenswert?

Matthias Sch. schrieb:
> Warum adaptierst du nicht PeDas Drehgeber
> Routine auf den STM32? Die läuft sehr zuverlässig und ist auch auf
> verschiedene Quadratursignale anpassbar (1,2 und 4 stufig).

Die Aktion kann er sich schenken, da diese Routinen viel zu langsam 
sind.
Entweder nimmt man einen Hardwaredekoder, wovon der STM32 viele hat, 
oder, falls die Pins nicht passen, wertet man per Interrupt aus.

Nachfolgender Link zeigt auf Beispiele mit AVRs, mit einem STM32 geht es 
genauso einfach nur noch viel schneller. 
Beitrag "4-fach Flankenauswertung per Interrupt mit ATmega48/88"

Andreas True schrieb:
> Da der Zähler von dem Encoder pro reale Umdrehung um 4096 erhöht wird,
> setze ich ihn alle 4096 wieder auf null um so eine zyklische Zählung zu
> erhalten (siehe die zwei if's)

Ich weiß nicht, was das soll, aber den Wert mit 4095 zu maskieren ist 
zuverlässiger.
Wie hoch ist denn die max. Drehzahl des Motors?

von spontan (Gast)


Lesenswert?

>falls die Pins nicht passen, wertet man per Interrupt aus

Grad zu Weihnachten ist wieder Glauben angesagt. Aber jeder kann ja 
glauben was er will...

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Matthias Sch. schrieb:
> sondern schlichte Quadratursignale, hat sich aber wohl schon geklärt.

Nein, hatte ich bis eben anders verstanden. Stimmt: Bei "Signal (A oder 
B)" kann es tatsächlich kein GrayCode sein.

drama schrieb:
> Wenn möglich, solltest du die Hardwareunterstützung für Quadraturencoder
> verwenden. Was ist das für ein Mikrocontroller?

Da muss Andreas erstmal antworten, denn beim STM32 macht Interrupt z.B. 
wegen dem eingebauten Quadraturdecoders incl. Entprellung überhaupt gar 
keinen Sinn. Das wäre das nichtmal eine Glaubensfrage.

von Andreas T. (skycurve)


Lesenswert?

Guten Tag,
vielen Dank für die vielen Antworten.

Die interrupt Routine läuft mit 1MHz, also keine Flankentriggerung. Der 
Encoder macht laut Datenblatt max. 100kHz (oder maximal 6k Umrd.), 
sollte also locker passen. Der Interrupt hat auch die höchste Prio. in 
meinem Programm.
Der Encoder hat einen zusätzlichen Z Durchgang rausgeführt, jedoch 
dachte ich dass ich mit A und B auskommen müsste da man ja eig. keinen 
Einlesefehler dank des GrayCodes bekommen sollte oder?

Das mit kgv hört sich nicht schlecht an :)
Position am Encoder Markieren, ein paar mal drehen lassen und schauen ob 
die Variable 'position' danach immer noch an der selben stelle ist, 
werde ich heute nach der Arbeit auch ausprobieren.

So, ich hoffe ich habe allen geantwortet, habs nur schnell überflogen, 
da Mitttagspause.

PS: uC ist ein STM32F4, jedoch hätte ich gerne eine Softwarelösung um 
flexibel zu bleiben, wenn es natürlich möglich ist.

Grüße
Andreas

von Dispol (Gast)


Lesenswert?

>sollte also locker passen
Ob es wirklich reicht: Einfach noch den 4. Zustand (Fehler) nicht auf 0, 
sondern auf einen anderen Wert setzen und den dann abfragen.
Es darf nicht gesetzt werden.

von m.n. (Gast)


Lesenswert?

Andreas True schrieb:
> Die interrupt Routine läuft mit 1MHz, also keine Flankentriggerung. Der
> Encoder macht laut Datenblatt max. 100kHz (oder maximal 6k Umrd.),
> sollte also locker passen.

Dann sieh Dir mal das Listing der ISR an! Der Code ist zu groß, um mit 1 
MHz zuverlässig abgearbeitet werden zu können. Der STM32F4 ist sehr 
schnell, verlangt für solche Geschichten aber auch eine passende 
Programmierung. Dazu gehören, PortD mit einem Befehl einzulesen und 
diesen Tabellenquatsch zu unterlassen!

Die Flanken an PortD0 + PortD1 kann man per Interrupt schnell erfassen; 
der µC wird nur belastet, wenn Flanken auftreten. Die 1 MHz Grundlast 
von TIM2 kann vollständig entfallen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Andreas True schrieb:
> jedoch hätte ich gerne eine Softwarelösung um
> flexibel zu bleiben

Ich glaube, Du hast das nicht verstanden: Es geht darum, den 
integrierten Timer zu benutzen. Den kannst Du doch flexibel 
parametrieren. Beispiel:
1
void initQuadrature() {
2
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
3
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
4
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
5
    GPIO_InitTypeDef GPIO_InitStructure;
6
    GPIO_StructInit(&GPIO_InitStructure);
7
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
8
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
9
    GPIO_Init(GPIOA, &GPIO_InitStructure);
10
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
11
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
12
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
13
    TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI2, TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);
14
    TIM_SetCounter(TIM1, 16384);
15
    TIM_Cmd(TIM1, ENABLE);
16
}

Was ist daran unflexibel?

: Bearbeitet durch User
von Dispol (Gast)


Lesenswert?

Kann TIM1 Quadratursignale dekodieren? Beim STM32F407xx geht das doch 
nur mit TIM2-5, oder?

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Dispol schrieb:
> Kann TIM1 Quadratursignale dekodieren?

Falls sich das auf mein Beispiel bezog:
Das war Cut&Paste aus meinem Projekt mit dem STM32F103C8.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Dispol schrieb:
> Kann TIM1 Quadratursignale dekodieren? Beim STM32F407xx geht das doch
> nur mit TIM2-5, oder?

TIM1 und TIM8 ebenso.

von drama (Gast)


Lesenswert?

Flexibilität? Selbst die kleinsten STM32 haben genug Timer und können 
Quadraturdekodierung. Viele andere Mikrocontroller ebenso.

von Horst H. (horst_h44)


Lesenswert?

Ich glaube es gibt hier ein generelles Verständnisproblem was die 
Signale A, B und Z bedeuten und wie A und B codiert ist. A und B sind 
Inkrementelle Signale die in ihrer Phasenlage kodiert haben ob es Vor- 
oder Rückwärts geht. Der Z-Impuls ist der Null-Impuls um den Anfang 
einer 360 Grad Umdrehung zu definieren. Am deutlichsten wird es wenn man 
sich ein Zeitdiagramm des Verlaufen über 360 Grad ansieht 
(http://www.ichaus.de/wp2_encoderanschluss Bild 2 auf Seite drei). Per 
Software müssen dann die Flanken mit Phasenlage vor- oder zurückgezählt 
werden und mit dem Z-Impuls wird der Zähler auf Null gesetzt, bzw. es 
kann überprüft werden ob die Software auch alle Flanken korrekt gezählt 
hat, bzw. welche verloren hat. Sinnvoll ist auch in der Software zu 
prüfen das A/B-Signal keinen Jitter hat, z.B. durch Doppelabfrage des 
Pegels.

von Andreas T. (skycurve)


Lesenswert?

m.n. schrieb:
> Die Flanken an PortD0 + PortD1 kann man per Interrupt schnell erfassen;

Meinst du dass man zB auf steigende und fallende Flanken der Pins einen 
IRQ triggert? Das habe ich anfangs auch so gemacht, und es lief extrem 
schlecht, trotz logischer Überprüfung, dass A nicht zwei mal getriggert 
wird, bevor B getriggert wurde etc. Dann habe ich gelesen, dass man 
Encoder unbedingt mit einer Timer IRQ verarbeiten sollte, ist auch hier 
beschrieben:
http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

@Torsten C: gut, so 'unflexibel' sieht es nicht aus. Ohne mich damit 
bereits beschäftigt zu haben, könntest du mir vielleicht ein paar Fragen 
beantworten?
1. Verstehe ich es richtig, dass der CounterWert dann in TIM1 steht?
2. Bedeutet die "16384", dass der Timer bis 16384 zählt und dann wieder 
bei 1 anfängt?
3. Kann die Funktion auch rückwärts Zählen?
4. Mein Encoder macht auf A und auf B pro Umdrehung jeweils 1024 
versetzte Ticks, durch den GrayCode (fallende und steigende von A und B 
beachten) komme ich so auf 4096 Ticks pro Umdrehung, macht die Funktion 
TIM_EncoderInterfaceConfig(..) das auch so?

Mir hat meine Funktion eigentlich gut gefallen, (siehe auch Link oben) 
schade dass es anscheinend doch nicht so gut ist :(

EDIT:
@Horst H:
Würde es genügen, wenn ich statt meiner zwei IFs einfach so etwas wie
1
if(Z == Low) position = 0;
1
void TIM2_IRQHandler(void)
2
{
3
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
4
  {
5
    quadrature_input = GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2) * 2 + GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_1) * 1;
6
    new_quadrature_value=quadrature_input;
7
    position+=table[last_quadrature_value][new_quadrature_value];
8
    last_quadrature_value=new_quadrature_value;
9
10
    if(position == limit) position = 0;
11
    if(position == -1) position = limit-1;
12
13
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
14
15
  }
16
}
hinzufügen würde? Gibt es eine Lösung wie Torsten C sie vorgeschlagen 
hat, nur dass auch Z beachtet wird?

Ich kann es gerade leider noch nicht ausprobieren.

Grüße
Andreas

: Bearbeitet durch User
von Disco (Gast)


Lesenswert?

Übrigens sind Quadratursignale 2Bit Graycode...

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Andreas True schrieb:
> 1. Verstehe ich es richtig, dass der CounterWert dann in TIM1 steht?
Ja.

> 2. Bedeutet die "16384", dass der Timer bis 16384 zählt und dann wieder
> bei 1 anfängt?

Nein, damit habe ich nur initialisiert. Er geht von 0 .. 32767.

> 3. Kann die Funktion auch rückwärts Zählen?

Klar, das ist doch der einzige Sinn des Quadraturdecoders.

> 4. Mein Encoder macht auf A und auf B pro Umdrehung jeweils 1024
> versetzte Ticks, durch den GrayCode (fallende und steigende von A und B
> beachten) komme ich so auf 4096 Ticks pro Umdrehung, macht die Funktion
> TIM_EncoderInterfaceConfig(..) das auch so?

Ja. Weil der Timer von 0 bis 32767 zählt, verunde mit 0x0FFF, dann hast 
Du da Dein 0 .. 4095.

Du kannst in den restlichen MSBits noch volle Umdrehungen auslesen.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Andreas True schrieb:
> m.n. schrieb:
>> Die Flanken an PortD0 + PortD1 kann man per Interrupt schnell erfassen;
>
> Meinst du dass man zB auf steigende und fallende Flanken der Pins einen
> IRQ triggert? Das habe ich anfangs auch so gemacht, und es lief extrem
> schlecht, trotz logischer Überprüfung, dass A nicht zwei mal getriggert
> wird, bevor B getriggert wurde etc.

Es kommt darauf an, wie fein Du das Encodersignal auswerten möchtest. 
Bei 2-fach Auswertung, braucht man nur eine ISR, die auf positive und 
negative Flanken hin angesprungen wird. In der ISR wird lediglich 
entschieden ob +1 oder -1 zum Zähler addiert werden muß. Nichts mit 
Entprellen oder sonstigen Prüfungen!

Bei 4-fach Auswertung braucht man eine 2. ISR für den anderen Kanal, 
wobei die Fallunterscheidung invertiert wird, sodaß der Zähler 
fortlaufend in-/dekrementiert wird je nach Drehrichtung.

> Dann habe ich gelesen, dass man
> Encoder unbedingt mit einer Timer IRQ verarbeiten sollte, ist auch hier
> beschrieben:

Das schreiben in der Regel Leute, die die Hose sofort gestrichen voll 
haben, sobald das Wort 'Interrupt' auftaucht. Sie kennen nichts anderes, 
haben nie etwas anderes gebraucht bzw. probiert und schreien immer nur 
laut: Verrat! Ignoriere es einfach!

Andreas True schrieb:
> Mir hat meine Funktion eigentlich gut gefallen,

Aber hier sind Dir doch schon Überläufe passiert, die Du kompensieren 
mußtest.
> TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
Wenn Die Routine schnell genug ist, ist dieses Bit nie gesetzt.

Ich zeige Dir ein einfaches Beispiel für 2-fach Auswertung.
(Ich hoffe, ich habe es richtig für den STM32F4 angepaßt.)

#define PHASE_A 0               // an PORTD.0
#define PHASE_B 1               // an PORTD.1
#define MASKE 3                 // vereinfachte Schreibweise

volatile int count;

// nur Interrupt eines Pins wird zur Auswertung verwendet
void XYZ_IRQHandler(void)       // muß für Phase_A angepaßt werden
{
int8_t temp = GPIOD->IDR & MASKE;     // Zustand der beiden Phasen lesen
  if((temp & MASKE) == MASKE ||
     (temp & MASKE) == 0)       // PHASE_A und PHASE_B auswerten
    count++;                    // PHASE_A == PHASE_B: Zaehler + 1
  else
    count--;                    // ungleicher Pegel:   Zaehler - 1
}

Wenig Code, ganz schnell und nur aktiv, wenn sich eine Flanke an Phase_A 
zeigt.

von Dispol (Gast)


Lesenswert?

>Das schreiben in der Regel Leute, die die Hose sofort gestrichen voll
>haben, sobald das Wort 'Interrupt' auftaucht. Sie kennen nichts anderes,
>haben nie etwas anderes gebraucht bzw. probiert und schreien immer nur
>laut: Verrat! Ignoriere es einfach!

Der Nachteil einer Interrupt-bei-Flanke Lösung ist halt: Hast Du ein 
hochfrequentes Signal am Eingang, steht das System.

Der Nachteil einer Lösung mit fester Abtastzeit ist: Man hat immer eine 
fest Auslastung. Auch wenn sich nichts tut.

Eine 3. Lösung wäre eine Interrupt bei Flanke, der jedoch für eine Zeit 
x nach dem Event gesperrt bleibt. Dann hätte man beide Vorteile. Aber 
das wäre etwas komplizierter.

Ideal ist natürlich, ein Hardware zu nutzen (Wenn es eine gibt). Wobei 
ich mir nicht ganz sicher bin, ob beim STM32 wirklich alle 4 Zustände 
gezählt werden. Beim letzten Projekte war ich der Meinung, es waren nur 
2. Das spielte für mich jedoch keine Rolle.

von m.n. (Gast)


Lesenswert?

Dispol schrieb:
> Der Nachteil einer Interrupt-bei-Flanke Lösung ist halt: Hast Du ein
> hochfrequentes Signal am Eingang, steht das System.

Wo, bitte schön, soll denn dieses 'hochfrequente' Signal herkommen? Der 
Drehgeber liefert es nicht!
Dieses 'hochfrequente' Signal taucht als 'Argument' immer dann auf, wenn 
es um Drehgeberauswertung per Interrupt geht. Bei ser. Datenübertragung 
gibt es das wohl nicht; die läuft immer völlig störungsfrei ;-)

Dispol schrieb:
> Eine 3. Lösung wäre eine Interrupt bei Flanke, der jedoch für eine Zeit
> x nach dem Event gesperrt bleibt. Dann hätte man beide Vorteile. Aber
> das wäre etwas komplizierter.

Dafür würden sich Capture-Eingänge von Timern eignen, die selber keine 
Encoderauswertung bieten (TIM9-TIM14). Diese haben wirksame 
Eingangsfilter. Der Timer selbst wird nicht benötigt.

Dispol schrieb:
> Ideal ist natürlich, ein Hardware zu nutzen (Wenn es eine gibt). Wobei
> ich mir nicht ganz sicher bin, ob beim STM32 wirklich alle 4 Zustände
> gezählt werden. Beim letzten Projekte war ich der Meinung, es waren nur
> 2. Das spielte für mich jedoch keine Rolle.

Wenn man das beim Design berücksichtigt, ist es fraglos die beste 
Lösung. Man kann zwischen 2-fach und 4-fach Auswertung wählen; siehe 
Ref.-Manual.

von Martin H. (disjunction)


Lesenswert?

Fall es um ein Design geht, kann ich noch den HCTL-2022 vorschlagen. Ich 
weiß, dass ist zwar antiquiert aber es passt zum Thema. Ich schlage mich 
schon seid 15 Jahren mit diesem Thema rum und habe damals zu einer FPGA 
Lösung gegriffen und bin nie enttäuscht worden. Über den HCTL-2022 bin 
ich mal durch Zufall gestolpert.

Ein Trick habe ich noch genutzt, wenn sich bei der Abtastung ergibt, 
dass sich beide Encodersignale geändert haben, ist die 
Wahrscheinlichkeit groß, dass es zwei Schritte in die gleiche Richtung 
wie beim letzten mal waren.

Die nächste Herausforderung ist die Auswertung von SIN/COS Signalen. Die 
Periodendauer ist oft größer und sie können z.B. mit einem ADC122S706 
simultan samplend werden.

von Andreas T. (skycurve)


Lesenswert?

Guten Abend,

vielen Dank für die zahlreichen Vorschläge, m.n. vielen Dank für den 
Code!

Ich habe es erstmal so wie Torsten es vorgeschlagen, mit einem Timer 
gemacht und verunde das Ergebnis immer mit 0x0FFF. Leider driftet der 
Winkel immer noch ab.


Ich lasse den Motor 300 Umdrehungen fahren, markiere mir zu Sicherheit 
die Rotorposition. Der Timer Counter steht 1723.
Dann lasse ich den Motor weitere 300 Umdrehungen fahren, die markierte 
Position stimmt überein. Der Timer Counter steht nun aber bei 1425.

(1723-1425)/4095 => bedeutet dass die markierte Position um 26 Grad 
abweichen müsste, was nicht Fall ist.

Wie könnte ich am geschicktesten den Timer mit der Z Phase zurücksetzen?
So wie ich das am Scope sehe, gibt Z immer nur einen ganz kurzen 
NegativImpuls, vermutlich ein mal pro Umdrehung.
Wenn ich nun auf Z einen Flanken Interrupt mache und den Timer 
zurücksetze, werde ich ja wieder mit Mehrfachtriggerung zu tun bekommen.

EDIT: Z gibt einen negativen Puls siehe PDF Seite 5 Timingdiagram

http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Robotics/E6B2Encoders.pdf

Grüße
Andreas

: Bearbeitet durch User
von Martin M. (capiman)


Lesenswert?

Nur so eine Idee:
Du hast die Zahlen 1425, 300 und 1723.

Auf den ersten Blick 1425 + 300 = ~ 1723.

Kann es sein, dass deine Umdrehung irgendwie um 1 zu kurz/zu lange ist?

Wiederhole doch den gleichen Versuch mit 150 oder 600 Umdrehungen,
um zu sehen, ob die obige Berechnung wieder ähnliche Ergebnisse liefert.

von m.n. (Gast)


Lesenswert?

Martin H. schrieb:
> Die nächste Herausforderung ist die Auswertung von SIN/COS Signalen. Die
> Periodendauer ist oft größer und sie können z.B. mit einem ADC122S706
> simultan samplend werden.

So mache ich es, seitdem es den AT90S4433 gibt: 
http://www.mino-elektronik.de/mt12_iic/mt12_iic.htm
Mit einen ATmega48 kommt die Schaltung mit minimaler Hardware aus.

Ein STM32F407 hat drei ADCs und kann ebenfalls simultan abtasten. Damit 
geht es dann noch besser, als mit HCTL-xxx + ADCxxx. Aber ein bißchen 
Hirn braucht man doch noch für eine perfekte Lösung.

Martin Maurer schrieb:
> Wiederhole doch den gleichen Versuch mit 150 oder 600 Umdrehungen,
> um zu sehen, ob die obige Berechnung wieder ähnliche Ergebnisse liefert.

Und vielleicht auch noch rückwärts drehen lassen und beobachten, was 
passiert.

von Disco (Gast)


Lesenswert?

m.n. schrieb:
> So mache ich es, seitdem es den AT90S4433 gibt:
> http://www.mino-elektronik.de/mt12_iic/mt12_iic.htm

Ich verwende wie oben erwähnt eine FPGA Lösung, der hat keinen ADC daher 
das extra Bauelement. Du hast ja auch noch 2 OPV verwendet, diese sind 
im differentiellen ADC schon integriert. Außerdem muss ich 20 um mit 
5m/s erfassen können da brauche ich 1MS um die Quadratur nicht zu 
verpassen.

von m.n. (Gast)


Lesenswert?

Disco schrieb:
> Du hast ja auch noch 2 OPV verwendet, diese sind
> im differentiellen ADC schon integriert.

Die werden für die +/- 11 µA Signale als Strom/Spannungswandler 
benötigt.

> Außerdem muss ich 20 um mit
> 5m/s erfassen können da brauche ich 1MS um die Quadratur nicht zu
> verpassen.

Bei mir geht's mehr um die Auflösung von 0,1 µm UND um die 
Referenzmarke.
Sollen wir die Kosten beider Varianten vergleichen? Für einen ADC122S706 
müßte schon Weihnachten sein, damit ich ihn mir leisten kann ;-)

Aber es ist schon in Ordnung, wie Du es machst!

von Disco (Gast)


Lesenswert?

m.n. schrieb:
> Für einen ADC122S706 müßte schon Weihnachten sein, damit ich ihn mir
> leisten kann ;-)

Zum Glück ist der Weihnachtsmann immer gnädig mit mir. Bauche etwa 60 
Stück im Jahr... Aber ich sollte vielleicht auch mal schauen, dass er 
nicht so tief in die Tasche greifen muss. Trotzdem auch Dir schöne 
Weihnachten, die Lösung sieht auch super aus. Und entscheidend ist ja 
noch die weitere Auswertung... Amplitude, Pahase usw.

von Andreas T. (skycurve)


Lesenswert?

m.n. schrieb:
> Ein STM32F407 hat drei ADCs und kann ebenfalls simultan abtasten

Die ADCs sind bei mir leider schon belegt (Phasenstrommessung für SVPWM, 
muss unbedingt simultan laufen)


Wenn ich den Encoder nicht mit einem Timer Interrupt, wie anfangs 
auswerte, sondern wie Torsten es vorgeschlagen hat, mit 
TIM_EncoderInterfaceConfig(..), bekomme ich pro Umdrehung nicht 4096 
sondern nur noch die Hälfte, was aber von der Genauigkeit her kein 
Problem ist.

Der Code sieht aktuell so aus:
1
    TIM_TimeBaseStructure.TIM_Period = 0x07ff;
2
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
3
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
4
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
5
6
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
7
8
    TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI2, TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);
9
    
10
    TIM_ITConfig(TIM1,TIM_IT_Update , ENABLE);
11
    TIM_Cmd(TIM1, ENABLE);
12
    TIM1->CNT=0;

Martin Maurer schrieb:
> Wiederhole doch den gleichen Versuch mit 150 oder 600 Umdrehungen

Die Counterstände mit dem oberen Code nach jeweils 150 Umdrehungen:

300 - 279 - 259 - 237 - 208 - 166
(der Motor ist dabei jedes mal an der selben Markierung stehen 
geblieben)

Etwas anderes: Laut Datenblatt macht der Encoder nicht 2048 sondern 2000 
Ticks, wenn ich allerdings den Counter weiter zählen lasse:
1
TIM_TimeBaseStructure.TIM_Period = 0xffff;

und per Mausklick eine Umdrehung fahren lasse, ändert sich der 
Zählerstand immer um 2048.

Gibt es eine Möglichkeit den TIM zusätzlich mit der Z Phase zu koppeln?

Grüße,
Andreas

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo "m.n.",

> Dispol schrieb:
>> Der Nachteil einer Interrupt-bei-Flanke Lösung ist halt: Hast Du ein
>> hochfrequentes Signal am Eingang, steht das System.
>
> Wo, bitte schön, soll denn dieses 'hochfrequente' Signal herkommen? Der
> Drehgeber liefert es nicht!

Doch, dass kann ganz schnell gehen. Und zwar wenn der Geber genau an 
einem Hell-Dunkel Übergang der Geberscheibe steht. Bei jeder kleinen 
Vibration bekommst du dann einen ganzen Flankenzug an Pulsen, ohne das 
sich die Position tatsächlich ändert. Bei Abtastung in einem festen 
Zeitraster entgehen einem vielleicht die meisten dieser Pulse, was aber 
keine Rolle spielt. Im nächsten Takt ist man entweder noch in der alten 
Position, oder um +/-1 Inkrement weiter. Das ganze Gezappel auf der 
Leitung kümmert nicht weiter.

Mit freundlichen Grüßen
Thorsten Ostermann

von m.n. (Gast)


Lesenswert?

Thorsten Ostermann schrieb:
> Doch, dass kann ganz schnell gehen. Und zwar wenn der Geber genau an
> einem Hell-Dunkel Übergang der Geberscheibe steht. Bei jeder kleinen
> Vibration bekommst du dann einen ganzen Flankenzug an Pulsen, ohne das
> sich die Position tatsächlich ändert.

Es tut mir Leid, wenn Du jemals solche Probleme gehabt haben hätten 
solltest.
Halbwegs brauchbare Geber machen so etwas nicht. Die haben intern zum 
einen eine Hysterese und sind zum anderen elektrisch und mechanisch 
intern so 'träge', daß die erdichteten Impulsströme garnicht entstehen 
können.
Tu mir den Gefallen und schreibe diese Geschichten ins Märchenbuch.

Andreas True schrieb:
> Der Encoder macht laut Datenblatt max. 100kHz

Die von mir gezeigte Interruptroutine schafft rund 3 MHz ;-)
Selbst, wenn die Auswertung nicht so schnell wäre, gäbe es 1000 
Möglichkeiten, die Bandbreite zu begrenzen!

Andreas True schrieb:
> Wenn ich den Encoder nicht mit einem Timer Interrupt, wie anfangs
> auswerte, sondern wie Torsten es vorgeschlagen hat, mit
> TIM_EncoderInterfaceConfig(..), bekomme ich pro Umdrehung nicht 4096
> sondern nur noch die Hälfte, was aber von der Genauigkeit her kein
> Problem ist.

(Gemeint ist hier ein anderer Torsten!)
Dann wird nur 2-fach Auswertung verwendet; das kann man umprogrammieren. 
Siehe: Ref. Manual.
Mit dem Hardwaredekoder muß der Zählerstand immer stimmen, sonst stimmt 
etwas mit Deinen Signalen nicht. (Vielleicht OC-Ausgang und Pullup zu 
groß?)

Kannst Du u.U. TIM2 oder TIM5 verwenden? Deren Register sind 32 Bit 
breit. Lasse sie unverändert und errechne die eff. Position erst dann, 
wenn sie benötigt wird und kläre, ob es 2048 oder 2000 Schritte/U sind!
Anzahl Umdrehungen = TCNTx / 2000
aktuelle Position = TCNTx % 2000

Beim STM32F407 kannst Du auch auf float verzichten und gleich double 
rechnen. Es ist affenschnell!

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo "m.n.",

> Thorsten Ostermann schrieb:
>> Doch, dass kann ganz schnell gehen. Und zwar wenn der Geber genau an
>> einem Hell-Dunkel Übergang der Geberscheibe steht. Bei jeder kleinen
>> Vibration bekommst du dann einen ganzen Flankenzug an Pulsen, ohne das
>> sich die Position tatsächlich ändert.
>
> Es tut mir Leid, wenn Du jemals solche Probleme gehabt haben hätten
> solltest.
> Halbwegs brauchbare Geber machen so etwas nicht. Die haben intern zum
> einen eine Hysterese und sind zum anderen elektrisch und mechanisch
> intern so 'träge', daß die erdichteten Impulsströme garnicht entstehen
> können.
> Tu mir den Gefallen und schreibe diese Geschichten ins Märchenbuch.

Da ich Encoder-Auswertung schon immer per Timer mache, bin ich nie in 
die Verlegenheit gekommen. Die vielen Fragen und Probleme die hier in 
Zusammenhang mit Encoder-Auswertung aufkommen zeigen aber, dass das ein 
schwieriges Thema ist.

Wo die mechanische Trägkeit in einem Encoder herkommen soll musst du uns 
mal genauer erklären. Bei den offenen Avago-Gebern ist ja z.B. nicht mal 
ein Lager integriert. Den mechanischen Anbau macht dann der OEM. Auch 
das mit der Hysterese halte ich für ein Gerücht. Das würde ja alles die 
Messung verfälschen. Hysterese gibt es höchstens, wenn man aus einem 
Rohsignalgeber (1Vss oder 20mA analog) digitale Signale per 
Interpolationseinheit erzeugt.

Mit freundlichen Grüßen
Thorsten Ostermann

von m.n. (Gast)


Lesenswert?

Thorsten Ostermann schrieb:
> Da ich Encoder-Auswertung schon immer per Timer mache, bin ich nie in
> die Verlegenheit gekommen.

Dann wiederhole doch bitte nicht die vorgeschobenen Argumente, die hier 
andere Leute zu diesem Thema abgeben. Was ich von ihnen halte, hatte ich 
ja weiter oben kommentiert.
Zeig mir reale, 'zitternde' Signale. Wenn sie tatsächlich auftreten 
sollten, können wir gerne darüber diskutieren, wie man mit ihnen umgeht.
Vorweg: es ist kein Problem!

> Die vielen Fragen und Probleme die hier in
> Zusammenhang mit Encoder-Auswertung aufkommen zeigen aber, dass das ein
> schwieriges Thema ist.

Dabei geht es in der Regel doch um Drehgeber mit mechanischen Kontakten. 
Da tauchen dann die 'PeDa-Glaubenskrieger' auf, unfähig über den 
Tellerrand zu sehen und auf Alternativen einzugehen.
Da geht es dann aber auch nicht um Signale mit einigen 100 kHz, sondern 
um solche im 100 Hz-Bereich: das ist doch langweilig!

Thorsten Ostermann schrieb:
> Den mechanischen Anbau macht dann der OEM. Auch
> das mit der Hysterese halte ich für ein Gerücht. Das würde ja alles die
> Messung verfälschen.

Die Umformung analog->digital erledigt in der Regel ein Komparator; 
dabei ist eine Hysterese Pflicht. Dadurch wird die Messung nicht 
verfälscht sondern erst ermöglicht. Im einfachsten Fall hat der 
verwendete µC diesen schom am Eingang integriert.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

m.n. schrieb:
> Tu mir den Gefallen und schreibe diese Geschichten ins Märchenbuch.

Ich hoffe, Thorsten Ostermann tut das nicht, ist ja auch kein Märchen.

@All: Hier geht es nicht um einen trollenden Gast und nicht ums "recht 
haben wollen", sondern um einen Rat an Andreas True. Wir würden ihm 
einen schlechen Rat geben, wenn wir hier was falsches behaupten.

@Andreas: Hat Dein Sensor eine Hysterese? Falls Du flexibel sein willst, 
würde ich mich nicht darauf verlassen.

: Bearbeitet durch User
von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Ich habe einen Artikel gefunden, der das Problem ganz gut beschreibt. 
Wichtig ist vor allem der Hinweis auf elektrische Störungen. Die werden 
nämlich gerne vernachlässigt, was bei Motorsteuerungen mit PWM oft nicht 
zulässig ist. Vor allem dann nicht, wenn man einen Encoder ohne 
Linedriver verwendet.
http://quantumdevices.wordpress.com/2009/04/15/what-is-hysteresis-and-how-is-it-used-in-optical-encoders/
Der Artikel geht auch darauf ein, das eine größere Hysterese zu einem 
größeren Messfehler führt.

Mit freundlichen Grüßen
Thorsten Ostermann

von m.n. (Gast)


Lesenswert?

Thorsten Ostermann schrieb:
> Vor allem dann nicht, wenn man einen Encoder ohne
> Linedriver verwendet.

Wer schlampige Elektronik verwendet, der soll sich über Fehler nicht 
wundern.

> 
http://quantumdevices.wordpress.com/2009/04/15/what-is-hysteresis-and-how-is-it-used-in-optical-encoders/
> Der Artikel geht auch darauf ein, das eine größere Hysterese zu einem
> größeren Messfehler führt.

Ich habe ihn überflogen und insbesondere die Bildchen angesehen. 
Unskalierte Kurven sind ja ganz nett, aber für eine differenzierte 
Betrachtung völlig daneben. Haben die gezeigten Sinuskurven nun 50 Hz 
und ist ein 1 ms Impuls auszufiltern, oder sind es 1 MHz und die Störung 
10 ns breit?

Daß eine größere Hysterese zu einem höheren Fehler führt, ist ja leicht 
dahergesagt. Aber wie sieht es denn mit den Fehlern aus, wenn (wie oben 
ausgeführt) ein 400 kHz Signal mit 1 MHz abgetastet wird? Erfolgt die 
Abtastung etwa synchron im Nulldurchgang? Eben nicht, sondern mit völlig 
wackelnder Phasenlage. Und das ergibt keine Fehler?

Wäre hier ein analoges Signal zu messen, würde jeder sofort auf die Idee 
kommen, die Störungen per RC wegzufiltern. Sobald digitale Signale 
vorliegen darf man aber anscheinend beliebige Störungen, sei es durch 
mangelnde Abschirmung oder viel zu hochohmige Datenleitungen, zulassen.

Ich denke, ich lasse es sein, gegen Vorurteile zu argumentieren.
Da Andreas True die Hardwaredekoder entdeckt hat, liegt er auf der 
sicheren Seite, sofern der Rest der Elektronik nicht 'verschlampt' ist.

von Andreas T. (skycurve)


Lesenswert?

m.n. schrieb:
> Mit dem Hardwaredekoder muß der Zählerstand immer stimmen, sonst stimmt
> etwas mit Deinen Signalen nicht. (Vielleicht OC-Ausgang und Pullup zu
> groß?)

Ich habe den Motor jetzt 20000 Umdrehungen laufen lassen mit ca 1400rpm. 
Der Drift vom elektrischen Winkel beträgt ca 85 Grad. Bei 7 elektrischen 
Rotationen pro reale Umdrehung habe ich also 85 / 7 = 12 Grad Drift an 
der Encoderwelle.

m.n. schrieb:
> Da Andreas True die Hardwaredekoder entdeckt hat, liegt er auf der
> sicheren Seite, sofern der Rest der Elektronik nicht 'verschlampt' ist

Ich muss zugeben dass die Elektronik dazu (noch) nicht schön ist. Auf 
Lochraster, Spannung des Encoders billig mit Spannungsteiler auf 3 Volt 
runtergeteilt, ca 50cm Leitungen zusammen mit PWM Zuleitungen. Da 
könnten sich vllt. auch falsche Signal einschleichen.

Torsten C. schrieb:
> @Andreas: Hat Dein Sensor eine Hysterese? Falls Du flexibel sein willst,
> würde ich mich nicht darauf verlassen.

Ist Hysterese so etwas wie eine Plausibilitätsprüfung zwischen aktuellem 
und letzten Wert? Habe dafür Google bemühen müssen :D
Bin mir nicht sicher ob der Encoder das hat.

Ich verwende jetzt den Hardware Encoder (mit TIM1) und zusätzlich 
externe Interruptroutine für den Nulldurchgang in der ich den Timer auf 
null setze. Bis jetzt habe ich keinen Drift festgestellt (geht ja auch 
nicht wenn der Counter immer an der selben phys. Position zurückgesetzt 
wird).
Allerdings:
ich gebe mir den Winkel mit dem ich den Motor künstlich füttere und den 
Encoder Winkel jeweils als Sägezahnsignal am Scope aus, und ab und zu 
zuckt der Encoderwinkel.
Entweder ist es Ablesefehler (Scope Trigger springt kurz etc.) oder die 
Nulldurchgang Routine wird mehrmals ausgeführt.

Ich könnte mir vorstellen dass der Motor dann auch zucken wird.

Aber erstmal muss ich es hinbekommen, beim Start den Encoder Offset zum 
Elektrischen Winkel des Motors richtig zu berechnen und zu beachten. Ist 
wohl auch nicht ganz einfach da ich nach dem Einschalten ja nicht weiß 
ob der Counter "bald" wieder durch den Nulldurchgang Interrupt 
zurückgesetzt wird.

Grüße
Andreas

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Andreas True schrieb:
> Ist Hysterese so etwas wie eine Plausibilitätsprüfung zwischen aktuellem
> und letzten Wert?

Beim Übergang von Schwarz und Weiss gibt es zwei Schaltschwellen: Eine 
für 1->0 und eine andere von 0->1. Dadurch kann man Störungen etwas 
verringern, also solche wie hier:

http://quantumdevices.files.wordpress.com/2009/04/extra-pulses1.jpg?w=630

Welchen STM32 hast Du? Der STM32W108C8 hat z.B. 
Schmitt-Trigger-Eingänge. Du könntest für eine Hysterese auch diskrete 
Schmitt-Trigger ergänzen.

> Habe dafür Google bemühen müssen :D

Anderes Suchwort: Schmitt-Trigger

> Bin mir nicht sicher ob der Encoder das hat.

Vermutlich nicht. Ich kenne keine Encoder mit Hysterese, lerne aber gern 
welche kennen.

m.n. schrieb:
> Halbwegs brauchbare Geber … haben intern zum einen eine Hysterese …

Ach. Welcher?

: Bearbeitet durch User
von Andreas T. (skycurve)


Lesenswert?

Ich habe noch ein Problem mit dem Offset des Encoders.

Berechnet wird der Winkel Folgendermaßen:
1
int t_pos;
2
Angle = ( ( (t_pos) * 7 ) & 0x07FF ) * 0.003067961576;

Erklärung:
Der Timer zählt 0..2047:
1
TIM_TimeBaseStructure.TIM_Period = 0x07ff;
Das entspricht genau einer Umdrehung der Encoderwelle
Der Motor macht 7 elektrische Rotationen pro WellenUmdrehung.
Durch
1
( ( (t_pos) * 7 ) & 0x07FF ) / 7

erhalte ich die Anzahl der Zählerpulse seit der letzten vollen 
elektrischen Umdrehung des Motors.

Es wird über kgV gerechnet um eine while(float > float) Schleife zu 
sparen.

Ein Zählerpuls entspricht 0.0214 rad elektrisch.

(2048 / 7) = 292.5714   entspricht  2PI elektrisch
2PI / 292.5714 = 0.0214

Ergibt Folgendes:
1
Angle = ( ( (t_pos) * 7 ) & 0x07FF ) / 7 * 0.0214
gekürzt:
1
Angle = ( (t_pos) * 7 ) & 0x07FF ) * 0.003067961576;

Ich hoffe es ist bis jetzt nachvollziehbar, es kommen auch plausible 
Winkel raus.
Jetzt muss in diese Rechnung ein Offset integriert werden da der Encoder 
mit der Motorwelle Winkelmäßig nicht übereinstimmt.
Dazu lasse ich den Motor am Anfang 2 volle, langsame Umdrehungen fahren, 
damit der Encoder-Timer mit dem Nulldurchgang synchronisiert wird.
Jetzt steht der Motor auf Winkel_elektrisch == 0; und der Zähler hat 
einen bestimmt Wert.
1
encoder_offset = ((t_pos * 7) & 0x07ff)/7;

Dann bei der Winkelberechnung immer Offset berücksichtigen
1
t_pos = TIM1->CNT;
2
3
t_pos -= encoder_offset;
4
if(t_pos < 0) t_pos += 2047;
5
if(t_pos > 2047) t_pos -= 2047;
6
Angle = ( (t_pos) * 7 ) & 0x07FF ) * 0.003067961576;

Am Ende kommt allerdings immer noch ein Falscher Winkel raus und die 
Abweichung ist nach jedem Start nicht einmal konstant.
Ich hoffe, ihr habt in meiner Rechnung einigermaßen durchblicken können 
und habt einen Fehler gefunden :)

Grüße
Andreas

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Andreas True schrieb:
> Ich hoffe, ihr habt in meiner Rechnung einigermaßen durchblicken können
> und habt einen Fehler gefunden :)

1. Mach doch erst einmal den ersten Schritt und sorge dafür, daß der 
Zähler richtig zählt. Wie ich bislang verstanden habe, gibt der Encoder 
1000 Impulse/Spur/Umdrehung aus. Mit der 2-fach Auswertung sind es dann 
2000 Impulse/U, die sich der Zählerstand ändern muß.
Vergiss daher alle von Dir ins Spiel gebrachten Zahlen 2047, 2048, 4095 
und 4096!

2. Vergiss den Z-Impuls, der sich in dieser Form nicht als 
Rücksetzimpuls eignet, und laß den Zähler frei weiterzählen. Dann 
vergleiche Position und Zählerstand. Sofern hier Differenzen auftreten, 
brauchst Du nichts weiter auszuwerten.

Sollten hier hingegen stabile Werte vorliegen, werte diese aus und laß 
den Zähler unverändert.

Um weiter oben erwähnte 'Fehler' oder Hysteresen kümmere Dich nicht. Der 
Encoder liefert Rechtecksignale und hat daher schon interne Hysteresen 
samt dem daraus resultierenden 'Fehler', den Du getrost ignorieren 
kannst!

von Andreas T. (skycurve)


Lesenswert?

Hallo m.n.

jetzt weis ich sicher, dass der Encoder 1024 Pulse macht, tolles 
Datenblatt!

Der Encoder läuft jetzt stabil, der Timer wird in der Z Phase - 
Interrupt Routine auf Null gesetzt. Warum eignet sich dieses Signal 
nicht dafür? Am Oszi ist es ein schöner Rechteck (negativaktiv).

Allerdings habe ich den Aufbau gerade wieder ohne der Z Routine 
ausprobiert und der Motor läuft sehr gut mit dem Winkel, keine Ahnung 
was vorgestern mit dem Ding los war :/
EDIT: es kann sein, dass es vorgestern ohne Z nicht funktioniert hat, 
weil ich den Minus des uC nicht mit dem Minus der restlichen Elektronik 
verbunden hatte, diese waren quasi nur über Steckdose und PC USB 
verbunden.

Mir ist es lieber wenn die Pulse immer vom gleichen realen Punkt aus 
zählen. Nennt man sowas AbsolutEncoder? Ich brauche das ganze um einen 
Winkelbeobachter für FOC mit SVPWM zu entwickeln und zu optimieren.

Ich habe es aber leider immer noch nicht geschafft, den Offset 
rauszurechnen und richtig zu integrieren. Gibt es bessere 
Vorgehensweisen, als die, die ich oben beschrieben habe?

Grüße
Andreas

: Bearbeitet durch User
von Michi (Gast)


Lesenswert?

Andreas True schrieb:

> bekomme ich pro Umdrehung nicht 4096
> sondern nur noch die Hälfte
>
>     TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI2,
> TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);

Für 4x Auswertung:

TIM_EncoderMode_TI12 anstatt TIM_EncoderMode_TI2

von Horst H. (horst_h44)


Lesenswert?

Für ne schnelle Erfassung ist eine spezielle Hardware unschlagbar: 
Positionsänderungen schnell und einfach erfassen: 
http://www.ichaus.de/wp2_encoderanschluss

von Dispol (Gast)


Lesenswert?

@Horst.
Ja. Der STM32 hat genau sowas schon eingebaut.
Davon haben wir es hier in diesem Thread.

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
Noch kein Account? Hier anmelden.