Forum: Mikrocontroller und Digitale Elektronik Drehgeber und Schrittmotor- 2 Riesenbaustellen im Programm


von Stephan (Gast)


Lesenswert?

Hallo!

Ich beiße mir an einem (vmtl. zwei) Problemen die Zähne aus:

Gegeben ist eine maschinelle Kabeltrommel mit Getriebemotor, der die 
Trommel antreibt und einem Schrittmotor, der mittels Trapezspindel eine 
Kabelführung so vor der Trommel positioniert, dass die Führung stets auf 
Höhe der aktuellen Kabelbahn steht.
Die Steuerung baut auf einen Atmega1284 bei 20MHz.


Also, pro 30 Getriebemotorumdrehungen (1 Trommelumdrehung)
- gibt ein Drehgeber am Motor (1024 Imp * 30) = 30720 Impulse aus und
- verfährt die Führung um eine Kabeldicke von 10mm indem die
- Trapezspindel (Steigung 6mm) etwa 1,67 Umdrehungen, angetrieben vom
- Schrittmotor, der (1,67U * 3200 Step pro U), also 5333 Steps macht.

Oder besser, machen sollte.


Baustelle 1: Auslesens des Drehgeber
Basierend auf den Artikel 
http://www.mikrocontroller.net/articles/Drehgeber
wird die Veränderung des Drehgeber wie folgt ermittelt:

1
volatile int8_t enc_delta;   // -128 ... 127
2
static int8_t last;          //
3
volatile int val;            // globale Variable fuer Encoder
4
float motorumdrehung_f;      // globale Variable fuer Motorumdrehung
5
6
void encode_init( void )
7
{
8
  int8_t new;
9
  new = 0;
10
  if( PHASE_A )
11
  new = 3;
12
  if( PHASE_B )
13
  new ^= 1;              // convert gray to binary
14
  last = new;            // power on state
15
  enc_delta = 0;
16
   
17
  TCCR0A = (1<<WGM01);   // CTC Modus
18
  TCCR0B = (1<<CS00);    // prescaler 0
19
  OCR0A = 180;           // rechnerisch ausreichend: 720    
20
  TIMSK0 = (1<<OCIE0A);  // interrupt enable
21
    
22
  TCCR2A = (1<<WGM21);   // CTC Modus
23
  TCCR2B = ((1<<CS20)|(1<<CS22));  // prescaler 1024
24
  OCR2A = 80;            // rechnerisch ausreichend: 80
25
  TIMSK2 = (1<<OCIE2A);  // interrupt enable
26
 }
27
 
28
ISR( TIMER0_COMPA_vect ) // schnelle Abfrage 
29
{
30
  int8_t new, diff; 
31
  new = 0;
32
  if( PHASE_A )
33
    new = 3;
34
  if( PHASE_B )
35
    new ^= 1;             // convert gray to binary
36
  diff = last - new;      // difference last - new
37
  if( diff & 1 )          // bit 0 = value (1)
38
  {            
39
    last = new;           // store new as next last
40
    enc_delta += (diff & 2) - 1;      // bit 1 = direction (+/-)
41
  }
42
}
43
44
ISR( TIMER2_COMPA_vect )      //langsame Abfrage zum Auslesen der Enc-Diff
45
{
46
    motorumdrehung_f += encode_read4() * (1.0/1024);  /*Multiplikation des Geberwertes mit 1/Aufloesung des Encoders*/
47
}    
48
 
49
int8_t encode_read4( void )
50
{
51
  int8_t val; 
52
  cli();
53
  val = enc_delta;
54
  enc_delta = val & 3;
55
  sei();
56
  return val >> 2;
57
}

Problem 1: bei Höchstgeschwindigkeit (1450U/min) muss die "schnelle" 
Abfrage (TIMER0_COMPA_vect) so oft ausgeführt werden, dass kein Impuls 
verschluckt werden kann; bei 25U/s und 1024Impulsen/U sind das gut 
25kHz. Bei 20MHz Takt sollten daher OCR0A=720 (bzw OCR0A=90 mit 
prescaler=8) (entspr. 36µs oder 27,7kHz) genügen- tut es aber nicht. 
Oberhalb von OCR0A=130 (entspr. 6,5µs oder 153kHz) werden Impule 
verschluckt.

TIMER2_COMPA_vect hingegen wird nur etwa um Faktor 100 seltener 
ausgelöst, um die in TIMER0_COMPA_vect beschreibene Variable auszulesen.


Baustelle 2:

Aus der sich ergebenen Motorumdrehung wird über einige 
Multiplikationen/Divisionen die Kabelführungs-Sollposition "Sollschritt" 
ausgerechnet. Bei Differenz zwischen Soll- und Istschritt wird Timer1 
gestartet, der direkt auf den STEP-Eingang des Schrittmotors wirkt.
1
volatile long step_ist;
2
volatile long step_soll;
3
#define F_CPU 20000000
4
5
int main(void)
6
{
7
  init_sys();
8
  while(1)
9
  {
10
     step_soll = (2 * motorumdrehung_f * STEP_PER_U_ANTR); /*STEP_PER_U_ANTR= ca. 177*/
11
     if(step_soll != step_ist)   /*bei Differenz Soll/Ist*/
12
     {
13
        TIMSK1 |= (1 << OCIE1A);  /*Schrittmotorverfahren zulassen*/
14
     }
15
     else 
16
     {
17
        TIMSK1 &= ~(1 << OCIE1A);   /*ansonsten sperren*/
18
     }  
19
  }
20
}

Die Frequenz dieses Timers richtet sich nach der Differenz Soll/Ist: je 
größer diese ist, desto kürzer die Pulsfolge (P-Regler). Bei Erreichen 
des Solslchrittes stoppt der Timer.
1
ISR(TIMER1_COMPA_vect)
2
{    
3
    PORTA ^= (1 << STEPPER_STEP)); /*invertieren des STEP-Einganges = halber Schritt*/
4
    step_ist++;
5
    if (step_soll == step_ist)  
6
    {
7
       TIMSK1 &= ~(1 << OCIE1A);  /*interrupt disable: weiteres Schrittmotorverfahren verhindern*/
8
    }
9
    else
10
    {
11
       OCR1A = F_CPU / ((step_ist - step_soll) * 10); Frequenz neu berechnen
12
    }
13
}


Problem 2:
Wenn diese Nachführfunktion aktiv ist, fängt der Drehgeber an, Schritte 
zu verschlucken, sprich, die Kabelführung fährt zwar exakt an die 
errechnete Stelle, allerdings geht sie davon aus, dass die Trommel 
langsamer dreht als sie es tatsächlich tut.

Wäre über Tipps und Tadel heilfroh.

Grüße
Stephan

von Falk B. (falk)


Lesenswert?

@Stephan (Gast)

>Also, pro 30 Getriebemotorumdrehungen (1 Trommelumdrehung)
>- gibt ein Drehgeber am Motor (1024 Imp * 30) = 30720 Impulse aus und

Reichlicher Luxus für so eine Kabeltrommel.

>- verfährt die Führung um eine Kabeldicke von 10mm indem die
>- Trapezspindel (Steigung 6mm) etwa 1,67 Umdrehungen, angetrieben vom
>- Schrittmotor, der (1,67U * 3200 Step pro U), also 5333 Steps macht.


>wird die Veränderung des Drehgeber wie folgt ermittelt:


volatile int8_t enc_delta;   // -128 ... 127
static int8_t last;          //
>volatile int val;            // globale Variable fuer Encoder
>float motorumdrehung_f;      // globale Variable fuer Motorumdrehung

MÖÖÖP! Macht man nicht. Besser Festkommaarithmetik.


>ISR( TIMER2_COMPA_vect )      //langsame Abfrage zum Auslesen der Enc-Diff
>{
>    motorumdrehung_f += encode_read4() * (1.0/1024);  /*Multiplikation des 
Geberwertes mit 1/Aufloesung des Encoders*/
>}

MÖÖP. Auch hier besser Festkommaarithmetik, ist auch schneller. 
Ausserdem verballerst du hier zusätzlich Zeit, weil du eine Funktion 
aufrufst. Besser ist es, hier den Code der Funktion direkt 
reinzuschreiben.

>Oberhalb von OCR0A=130 (entspr. 6,5µs oder 153kHz) werden Impule
>verschluckt.

Optimierung des Compilers nicht eingeschaltet? Oder deine andere ISR ist 
zu langsam und bremst deine schnelle ISR periodisch aus.
Lösung: Keine langsame ISR sondern periodisch per Flag in der 
Hauptschleife abfragen.

>TIMER2_COMPA_vect hingegen wird nur etwa um Faktor 100 seltener
>ausgelöst, um die in TIMER0_COMPA_vect beschreibene Variable auszulesen.

val ist bei dir int, also 16 Bit, da kann man DEUTLICH langsamer 
abfragen, nämlich Faktor 32768.

>Aus der sich ergebenen Motorumdrehung wird über einige
>Multiplikationen/Divisionen die Kabelführungs-Sollposition "Sollschritt"
>ausgerechnet. Bei Differenz zwischen Soll- und Istschritt wird Timer1
>gestartet, der direkt auf den STEP-Eingang des Schrittmotors wirkt.

Da muss man nix multiplizieren und dividieren. Mit Festkommaarithmetik 
und ggf. Bresemhamalgorithmus kriegt man das spielend und schnell hin.

>Wenn diese Nachführfunktion aktiv ist, fängt der Drehgeber an, Schritte
>zu verschlucken, sprich, die Kabelführung fährt zwar exakt an die
>errechnete Stelle, allerdings geht sie davon aus, dass die Trommel
>langsamer dreht als sie es tatsächlich tut.

Deine 3. ISR ist zu lang und bremst deine wichtige Encoder ISR 
zusätzlich aus.

Das kann man vermeiden indem man

a) die Schrittmotoransteurun mit in TIMER0_COMPA_vect packt (ohne 
Divisionen etc., siehe oben)
b) oder die Schrittmotoransteurung über ein Timer Flag in der 
Hauptschleife macht, siehe Interrupt.
c) oder verschachtelte ISRs der Timer per Software macht, siehe 
Interrupt

Denn dein 25 kHz Timer darf NIE durch eine andere ISR länger als 720 
Takte an der Ausführung gehindert werden.

von Stephan (Gast)


Lesenswert?

Falk Brunner schrieb:
> Reichlicher Luxus für so eine Kabeltrommel.

Einst arbeitete ich mit "motorumdrehung" als ganzzahlige Variable:
Da
1
volatile long motorumdrehung; 
2
3
ISR( TIMER2_COMPA_vect )  // langsame Abfrage 
4
{     
5
  int8_t temp = encode_read4();  /*temporaere Variable fuer Encoder*/
6
7
  val += temp;
8
  while (val>1023)
9
  {
10
     val-=1024;
11
     motorumdrehung++;
12
  }
13
  while (val<0)
14
  {
15
     val+=1024;
16
     if(motorumdrehung)motorumdrehung--;/*zaehlt nicht ins Negative*/
17
  }
18
}

Ergebnis war, dass bei jeder vollen Motorumdrehung der 
Schrittmotor-Timer hörbar erhöht wurde, was besonders bei sehr langsamem 
Lauf extrem störend ist.



Falk Brunner schrieb:
> val ist bei dir int, also 16 Bit, da kann man DEUTLICH langsamer
> abfragen, nämlich Faktor 32768.

Die Variable, die abgefragt werden muss und überzulaufen droht, ist 
enc_delta, also nur 8bit. Überlege gerade, was gegen eine 16bit spricht.

Danke für deinen Hinweise, werde sie mal durchpflügen.

von Falk B. (falk)


Lesenswert?

@ Stephan (Gast)

>> Reichlicher Luxus für so eine Kabeltrommel.

Ich meinte die Auflösung des Drehgebers.

>Einst arbeitete ich mit "motorumdrehung" als ganzzahlige Variable:
>Ergebnis war, dass bei jeder vollen Motorumdrehung der
>Schrittmotor-Timer hörbar erhöht wurde, was besonders bei sehr langsamem
>Lauf extrem störend ist.

Klar, ich sagte ja auch nicht, dass man nur mit ganzen Motorumdrehungen 
rechnen soll sondern mit Festkommaarithmetik! Da gibt es auch 
Bruchteile einer Umdrehung. Und wenn man das geschickt macht, erhält man 
daraus DIREKT die Sollposition des Schrittmotors! Ohne Multiplikation 
und Division!

>Die Variable, die abgefragt werden muss und überzulaufen droht, ist
>enc_delta, also nur 8bit. Überlege gerade, was gegen eine 16bit spricht.

Das meinte ich. War aber falsch geschrieben 8-0

von Stephan (Gast)


Lesenswert?

Der Vollständigkeit halber und um zu fragen, os sich dies auch in 
Festkommaarithmetik realisieren lässt:


#define B_TROMMEL 600    /*lichte Breite der Trommel*/
#define D_TROMMEL 400    /*Aussendurchmesser der Trommel*/
#define I_GETRIEBE 31.39 /*Getriebeuebersetzung*/
#define D_KABEL 10.4     /*Kabeldurchmesser*/
#define M_SPINDEL 6      /*Gewindesteigung der Trapezspindel*/
#define STEPS_PER_U 200  /*1.8° pro Schritt bei Vollschrittbetrieb*/
#define MICROSTEPS 16    /*Einstellung getaetigt mit TCML-IDE, */
#define RES_ENCODER 1024 /*Schritte pro Umdrehung des Winkelencoders*/

#define U_MOTOR  motorumdrehung
#define U_TROMMEL U_MOTOR / I_GETRIEBE    /*Trommelumdrehung*/
#define POS_KABEL (U_TROMMEL) * D_KABEL   /*Kabelposition*/
#define STEP_PER_U_ANTR D_KABEL  STEPS_PER_U  MICROSTEPS / (M_SPINDEL 
* I_GETRIEBE)

von Rudolph (Gast)


Lesenswert?

Ich würde auch erstmal schauen, ob sich die Trommelumdrehung nicht 
anders lösen lässt.
30720 Impulse pro Umdrehung? Das ist eine Auflösung von 0,012 Grad.

Wenn Du einen einen 8-Bit Binär Zähler dazwischen klemmst bekommst Du 
nur noch 120 Impulse pro Umdrehung.

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


Lesenswert?

Hallo Stephan,

Ergänzend zu den sehr richtigen Ausführungen von Falk...

> Die Frequenz dieses Timers richtet sich nach der Differenz Soll/Ist: je
> größer diese ist, desto kürzer die Pulsfolge (P-Regler). Bei Erreichen
> des Solslchrittes stoppt der Timer.

Also gibst du im Prinzip eine Solldrehzahl für den Schrittmotor vor. Das 
ist so zwar sehr kompakt, führt aber dazu, dass ein Sprung im Sollwert 
direkt auch einen Geschwindigkeitssprung zur Folge hat. Das hast du ja 
beim Rechnen mit ganzzahligen Umdrehungen (Sollwertsprünge) bereits 
selbst gemerkt.

Außerdem führen große Positonsabweichungen zu entsprechend hohen 
Geschwindigkeiten. Das kann alles funktionieren, kann aber auch zu 
extremfällen kommen, in denen der Motor nicht mehr hinterher kommt. 
Irgendwo sollte man Begrenzungen und/oder Überprüfungen einbauen, um 
feststellen zu können, ob man irgendwo an ein Limit gekommen ist.

Mit freundlichen Grüßen
Thorsten Ostermann

von Stephan (Gast)


Lesenswert?

Thorsten Ostermann schrieb:
> ein Sprung im Sollwert

Dürfte ja eigentlich nicht vorkommen. Die Trommel läuft sehr träge an.
Der DIY P-Regler arbeitet bisher ganz gut, ich werde ihn noch durch 
einen Minimalwert begrenzen.

Bin dabei, Festkommaarithmetik einzubauen...

von Stephan (Gast)


Lesenswert?

Rudolph schrieb:
> Ich würde auch erstmal schauen, ob sich die Trommelumdrehung nicht
> anders lösen lässt.

Ich sehe die Konflikte zwischen der sehr schnellen (notwendigen) Abfrage 
am Drehgeber und der sehr schnellen (notwendigen) Ansteuerung des 
Schrittmotors.

Siehst Du einen Vorteil darin, die "Impulse pro Umdrehung" 
herunterzuteilen?

von Falk B. (falk)


Lesenswert?

@ Stephan (Gast)

>Der Vollständigkeit halber und um zu fragen, os sich dies auch in
>Festkommaarithmetik realisieren lässt:

Ja, kann man, auch wenn man einige Werte runden muss.

#define B_TROMMEL 600    /*lichte Breite der Trommel*/
#define D_TROMMEL 400    /*Aussendurchmesser der Trommel*/
#define I_GETRIEBE 31.39 /*Getriebeuebersetzung*/
#define D_KABEL 10.4     /*Kabeldurchmesser*/
#define M_SPINDEL 6      /*Gewindesteigung der Trapezspindel*/
#define STEPS_PER_U 200  /*1.8° pro Schritt bei Vollschrittbetrieb*/
#define MICROSTEPS 16    /*Einstellung getaetigt mit TCML-IDE, */
#define RES_ENCODER 1024 /*Schritte pro Umdrehung des Winkelencoders*/

>#define U_MOTOR  motorumdrehung

So ein Macro ist nicht sehr sinnvoll. Warum willst du eine echte 
Variable hinter einem Macro verstecken?

>#define U_TROMMEL U_MOTOR / I_GETRIEBE    /*Trommelumdrehung*/

Hier fehlen Klammern! Denn sonst kann es böse Überraschungen geben, wenn 
dein Macro in einem komplexen Ausdruck genutzt wird!

>#define POS_KABEL (U_TROMMEL) * D_KABEL   /*Kabelposition*/
>#define STEP_PER_U_ANTR D_KABEL  STEPS_PER_U  MICROSTEPS / (M_SPINDEL
>* I_GETRIEBE)

Hier hat die Autoformatierung des Forums die Sternchen gefressen ;-) Es 
fehlt aber auch hier eine äußere Klammer.

von Karl H. (kbuchegg)


Lesenswert?

Stephan schrieb:

> Siehst Du einen Vorteil darin, die "Impulse pro Umdrehung"
> herunterzuteilen?


Natürlich.
Auf wieviele Nanometer genau muss denn der Schlitten vor der 
Kabeltrommel positioniert werden? Siehst du, wenn der Schlitten auf 
Zentel-Millimeter genau steht, dann wird das ja wohl reichen.

Vorteil: kleinere Zahlen
Vorteil von kleineren Zahlen: kleinere Datentypen
Vorteil von kleineren Datentypen: es kann schneller gerechnet werden.


die 32tausend-irgendwas Encoder-AUflösung pro Umdrehung macht dir das 
Leben unnötig schwer ohne das dir das irgendwas bringt. Denn ob deine 
Mechanik den Schlitten überhaupt so genau positionieren kann, steht in 
den Sternen. Was bringt es dir, wenn du auf 3 Atomradien genau 
ausrechnen kannst, wo die Führung stehen müsste, wenn dein Gewindespiel 
millionenfach größer ist?

Das würde ich als erstes rauswerfen.
ANstatt des Encoders wird eine einzelne Umdrehung vom Motor abgegriffen. 
Einfach Lochscheibe, 2 Lichtschranken - damit man rechts und linkslauf 
auseinanderhalten kann, und dann damit weiter arbeiten.
(Anstatt Lichtschranken irgendeine andere Technologie deiner Wahl. 
Wesentlich ist: 1 Impuls pro 1 Motorumdrehung. Und schon lacht die Sonne 
wieder, weil dein µC alle Zeit der Welt hat und nicht durch sinnlose 
Encoderabfragen ausgebremst wird. Man muss auch mal die Kirche im Dorf 
lassen. Nicht alles was technologisch möglich ist, ist auch sinnvoll)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Stephan schrieb:

> Die Frequenz dieses Timers richtet sich nach der Differenz Soll/Ist: je
> größer diese ist, desto kürzer die Pulsfolge (P-Regler).

Brauchts das wirklich?

Mit wievielfacher Schallgeschwindigkeit wird denn das Kabel abgerollt?

Der Ansatz mit Soll/Ist Vergleich ist ja ok. Aber braucht es da wirklich 
diese Geschwindigkeitssteuerung? Im regulären Betrieb ist die 
Ist-position ein paar Zehntel Millimeter oder Millimeter daneben. Welche 
Rolle spielt es, ob du den Schrittmotor (vergeblich) nötigst, diese 
Differenz in ein paar µs auszugleichen? Stell eine zeitliche 
Schrittfrequenz ein, die der Motor noch gut mitmacht und gut ists.

: Bearbeitet durch User
von Rudolph (Gast)


Lesenswert?

Mal anders überlegt.

30720 Impulse -> 5333 Schritte.
Also alle 5,76 Impulse ein Schritt.

Hmm, doofe Zahl.

5,76036 * 4 = 23,041
5,76036 * 21 = 120,967

Das ist doch nett, nimm den asynchronen Zähler 2,
stell den so ein das er bei 121 nen Überlauf macht (Mode 7 - falls ich
mich jetzt nicht vertue und das garnicht so funktioniert wie ich 
meine...)
In der ISR schiebst Du dann an, dass Dein Schrittmotor 21 Steps macht,
so schnell wie es eben noch geht und immer gleich schnell.

Wenn das zeitlich klappt macht der Stepper 254 Mal 21 Schritte pro 
Umdrehung der Trommel.
Und bei 10 mm Weg sind das immer noch 0,039 mm pro Schritt-Paket.

Passt das zeitlich?
Wieviele Umdrehungen pro Sekunde soll die Trommel machen?
Bei 4 Umdrehungen pro Sekunden (ja, eher nicht so :-) ), sind das alle 
985µs ein Interrupt.
Bei eher 1 Umdrehung pro 4s sind das alle 15,75ms ein Interrupt.

Wie schnell bewegt sich eigentlich so ein Stepper?
5333 Schritte pro Sekunde wären etwas viele, oder?

von Falk B. (falk)


Lesenswert?

Bei alten Drehmaschinen und Drahtwickelmaschinen macht man das einfach 
per Getriebe. Mehr wird hier auch nicht nachgebildet, nur mit 
elektrischer Kopplung statt Mechanik. Und die ganzen vielen Rechnungen 
laufen am Ende nur darauf hinaus, das eine konstante Übersetzung vom der 
Drehung des Trommelmotors auf den Kabelführungsmotor erfolgt

U_Kabelfüh = k * U_Trommel

In k stecken die ganzen Übersetzungen.

von Mike (Gast)


Lesenswert?

Stephan schrieb:
> float motorumdrehung_f;      // globale Variable fuer Motorumdrehung
> ...
> ISR( TIMER2_COMPA_vect )      //langsame Abfrage ...
> {
>     motorumdrehung_f += encode_read4() * (1.0/1024);
> }

Ist dir eigentlich klar, was du da für einen Zauber in der ISR 
anschmeißt?

Simulier den Code mal in deiner IDE und guck dir die Zahl der dafür 
erforderlichen CPU-Takte an.

von Stephan (Gast)


Lesenswert?

Falk Brunner schrieb:
> So ein Macro ist nicht sehr sinnvoll. Warum willst du eine echte
> Variable hinter einem Macro verstecken?
Kommt weg.


Falk Brunner schrieb:
> Hier fehlen Klammern!

Danke!


Karl Heinz schrieb:
> Stephan schrieb:
>
>> Die Frequenz dieses Timers richtet sich nach der Differenz Soll/Ist: je
>> größer diese ist, desto kürzer die Pulsfolge (P-Regler).
>
> Brauchts das wirklich?
Karl Heinz schrieb:
> Auf wieviele Nanometer genau muss denn der Schlitten vor der
> Kabeltrommel positioniert werden?
Karl Heinz schrieb:
> Aber braucht es da wirklich
> diese Geschwindigkeitssteuerung?

Die "Geschwindigkeitssteuerung" soll zugleich meine Gewähr dafür sein, 
dass die Schrittmotorfrequenz sich stets rampenförmig verändert.


Mike schrieb:
> Simulier den Code mal in deiner IDE und guck dir die Zahl der dafür
> erforderlichen CPU-Takte an.

Hab Angst.

Karl Heinz schrieb:
> Anstatt des Encoders

Der Encoder ist fest mit dem Antriebsmotor verbaut. Dieser hat zwar 
einen dritten Kanal, der nur einen Impuls pro Umdrehung liefert, dafür 
fehlte dann die Richtungsinformation.

von Stephan (Gast)


Lesenswert?

Rudolph schrieb:
> Mal anders überlegt.

Danke, hört sich gut an.


Rudolph schrieb:
> Wieviele Umdrehungen pro Sekunde soll die Trommel machen?

Etwa 1.6, da min. 1 m/s gefordert.

Rudolph schrieb:
> Wie schnell bewegt sich eigentlich so ein Stepper?

Verflucht schnell. Habe keine Zahl zur Hand aber einige kHz sind´s 
schon.

von Stephan (Gast)


Lesenswert?

Karl Heinz schrieb:
> Stell eine zeitliche
> Schrittfrequenz ein, die der Motor noch gut mitmacht und gut ists.

Dann taucht wieder das Problem auf, dass der Schrittmotor bei jeder 
Antriebsmotorumdrehung kurz hörbar seine Schritte läuft.
Bei sehr niedriger Drehgeschwindigkeit (<1/s) wirkst das unharmonisch.

von Falk B. (falk)


Lesenswert?

@ Stephan (Gast)

>Die "Geschwindigkeitssteuerung" soll zugleich meine Gewähr dafür sein,
>dass die Schrittmotorfrequenz sich stets rampenförmig verändert.

Kann man machen, aber dazu braucht man mehr als einen P-Regler.

>> Simulier den Code mal in deiner IDE und guck dir die Zahl der dafür
>> erforderlichen CPU-Takte an.

>Hab Angst.

Zu recht ;-)

>Der Encoder ist fest mit dem Antriebsmotor verbaut. Dieser hat zwar
>einen dritten Kanal, der nur einen Impuls pro Umdrehung liefert, dafür
>fehlte dann die Richtungsinformation.

OK, ist halt so. Kriegt man aber dennoch hin. Man muss halt garantieren, 
dass der schnelle 25 kHz Interrupt IMMER bedient werden kann und nie 
nennenswert (> 1 Dutzend Takte) warten muss. D.h. alle deutlich 
langsameren Funktionen laufen per Flag in der Hauptschleife. Das passt 
schon.

Man würde es vielleicht sogar hinkriegen, die Übersetzung von N 
Encoderschitten auf M Schrittmotorschritte im 25 kHz Interrupt zu 
erledigen (Bresenham!), das könnte die Sache deutlich vereinfachen. Dann 
hat man auch eine direkte Kopplung wie in einem mechanischen Getriebe. 
Die mechanische Trägheit des Trommelantriebs ist wahrscheinlich deutlich 
größer als die des Schrittmotors + Mechanik.

von Rudolph (Gast)


Lesenswert?

Stephan schrieb:
>> Wieviele Umdrehungen pro Sekunde soll die Trommel machen?
>
> Etwa 1.6, da min. 1 m/s gefordert.

Sind alle 2,46ms ein Interrupt wenn man jeden 121. Impuls einen 
Interrupt macht -> ein kleine Ewigkeit. :-)
Und die 50kHz macht der Timer locker auch.

> Rudolph schrieb:
>> Wie schnell bewegt sich eigentlich so ein Stepper?
>
> Verflucht schnell. Habe keine Zahl zur Hand aber einige kHz sind´s
> schon.

Also das wären dann 8533 Schritte pro Sekunde, dabei hätten ich dann am 
ehesten Bedenken.

Oder wenn man die 21 Schritte in 2ms machen will sind das nur noch 95µs 
pro Schritt.

Da fehlt mir die Erfahrung zu, dafür habe ich Schrittmotoren bisher zu 
selten benutzt und auch deutlich langsamer.
Aber zunächst finde ich das reichlich schnell.
Vor allem was man da ein Spannung braucht und was an Strom fliessen muss 
kann nicht ganz wenig sein wenn die Geschichte ja nicht ganz ohne Kraft 
auskommen kann.

Ich finde 5333 Schritte für 10mm Weg sowieso heftig übertrieben, geht 
nicht auch eine andere Spindel die weniger Schritte notwendig macht?
So 200 Schritte vielleicht?

von Stephan (Gast)


Lesenswert?

Falk Brunner schrieb:
> Man würde es vielleicht sogar hinkriegen, die Übersetzung von N
> Encoderschitten auf M Schrittmotorschritte im 25 kHz Interrupt zu
> erledigen

Wenn innerhalb des 25kHz Interrupts die Sollschritte errechnet und mit 
dem Istschritt verglichen würden- wie bzw. wo sollte dann der Step des 
Schrittmotors betätigt werden?

von Falk B. (falk)


Lesenswert?

@ Stephan (Gast)

>Wenn innerhalb des 25kHz Interrupts die Sollschritte errechnet und mit
>dem Istschritt verglichen würden-

So in etwa.

>wie bzw. wo sollte dann der Step des Schrittmotors betätigt werden?

Auch im gleichen Interrupt! Mit einer einfachen Statemachine. Dein 
Schrittmotor wird mit max. 8,3kHz Schrittfrequenz gesteuert, da reichen 
25 kHz locker. Sprich, wenn eni Schritt ansteht, wird im Interrupt das 
IO-Pin eingeschaltet und beim nächsten Interrupt wieder ausgeschaltet. 
Schon ist ein Schritt gemacht.

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


Lesenswert?

Hallo Rudolph,

>>> Wie schnell bewegt sich eigentlich so ein Stepper?
>>
>> Verflucht schnell. Habe keine Zahl zur Hand aber einige kHz sind´s
>> schon.
>
> Also das wären dann 8533 Schritte pro Sekunde, dabei hätten ich dann am
> ehesten Bedenken.
...
> Da fehlt mir die Erfahrung zu, dafür habe ich Schrittmotoren bisher zu
> selten benutzt und auch deutlich langsamer.
> Aber zunächst finde ich das reichlich schnell.

Naja, der OP hat 3200 Schritte pro Motorumdrehung angegeben. Solche 
Motoren gibt es nicht. Es wird sich wohl um einen normalen 2-phasigen 
Motor mit 1,8° Schrittwinkel handeln. Der hat dann 200 Vollschritte/U, 
also wird hier mit 1/16 Mikroschritt gearbeitet. Das ist nicht für die 
Positioniergenauigkeit erforderlich *), aber für einen ruhigeren 
Motorlauf. Aus den 8533 Mikroschritten/s kommt man dann auf 2,67 U/s. 
Das ist ein durchaus realistischer Wert.

Mit freundlichen Grüßen
Thorsten Ostermann

*) Mikroschritt erhöht nur die Auflösung, nicht die Genauigkeit.

von Falk B. (falk)


Lesenswert?

@ Thorsten Ostermann (Firma: mechapro GmbH) (ostermann) Benutzerseite

>Naja, der OP hat 3200 Schritte pro Motorumdrehung angegeben. Solche
>Motoren gibt es nicht. Es wird sich wohl um einen normalen 2-phasigen
>Motor mit 1,8° Schrittwinkel handeln. Der hat dann 200 Vollschritte/U,
>also wird hier mit 1/16 Mikroschritt gearbeitet.

Das ist auch so, wie man seinem Quelltext entnehmen kann ;-)

Beitrag "Re: Drehgeber und Schrittmotor- 2 Riesenbaustellen im Programm"

von Stephan R. (Firma: FHK) (nautosteer)


Lesenswert?

Falk Brunner schrieb:
> Mit einer einfachen Statemachine

Hm. Was ist daran Statemachine?
Und was mich noch mehr wurmt: das fixe Verhältnis ist genau 2,8975. Also 
Alle 2,8975 Encoderschritte ein Schrittmotortakt (Takt-Toggeln).
Der Einfachheit halber da drei draus zu machen würde am Ende des 750m 
Kabels einen Positionsfehler von 160mm ausmachen, also ist nicht drin.
Also, Festkommaarithmetik. Nur wie? Ich kann ja schlecht auf den 
28974ten Encoderschritt warten und dann 10000 Schrittmotorschritte 
machen?!  Ich sehe es nicht, leider.




Am Rande schonmal danke für die großartigen Hilfen hier...
Ihr seid alle nächste Woche zum Babybier eingeladen :)

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


Lesenswert?

Das ist doch nicht so schwierig: 2,8975*400=1159. Also alles mit Faktor 
400 versehen.

Mit freundlichen Grüßen
Thorsten Ostermann

: Bearbeitet durch User
von Stephan R. (Firma: FHK) (nautosteer)


Lesenswert?

Thorsten Ostermann schrieb:
> Das ist doch nicht so schwierig: 2,8975*400=1159. Also alles mit Faktor
> 400 versehen.

Macht die Änderung Sinn?
1
ISR( TIMER0_COMPA_vect ) // schnelle Abfrage 
2
{
3
  int8_t new, diff; 
4
  new = 0;
5
  if( PHASE_A )
6
    new = 3;
7
  if( PHASE_B )
8
    new ^= 1;             // convert gray to binary
9
  diff = last - new;      // difference last - new
10
  if( diff & 1 )          // bit 0 = value (1)
11
  {            
12
    last = new;           // store new as next last
13
    enc_delta += (diff & 2) - 1;      // bit 1 = direction (+/-)
14
  }
15
16
  if (Sollschritt * 400 == 1159) PORTA ^= (1 << STEPPER_STEP);
17
18
}

Nein, ich merk schon, das macht keinen Sinn..

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Stephan R. (Firma: FHK) (nautosteer)

>> Mit einer einfachen Statemachine

>Hm. Was ist daran Statemachine?

Man kann es so machen. ICH würde es wahrscheinlich so machen.

>Und was mich noch mehr wurmt: das fixe Verhältnis ist genau 2,8975.

Ja und?

>Also
>Alle 2,8975 Encoderschritte ein Schrittmotortakt (Takt-Toggeln).

Ja.

>Der Einfachheit halber da drei draus zu machen würde am Ende des 750m
>Kabels einen Positionsfehler von 160mm ausmachen, also ist nicht drin.

Hat auch keiner gesagt.

>Also, Festkommaarithmetik. Nur wie?

Lies den Artikel und denk drüber nach! Du hast mehr als genug Hinweise 
bekommen! Stichwort Bresenham! (Nun sieht es ein Blinder!)

> Ich kann ja schlecht auf den
>28974ten Encoderschritt warten und dann 10000 Schrittmotorschritte
>machen?!  Ich sehe es nicht, leider.

Siehe oben!

von Falk B. (falk)


Lesenswert?

@ Stephan R. (Firma: FHK) (nautosteer)

> if (Sollschritt * 400 == 1159) PORTA ^= (1 << STEPPER_STEP);

Vergiss solche Multiplikationen, die braucht man nicht und sie sind eher 
Rechenintensiv.

>Nein, ich merk schon, das macht keinen Sinn..

In der Tat.

von Nosnibor (Gast)


Lesenswert?

Stephan R. schrieb:
> Also, Festkommaarithmetik. Nur wie? Ich kann ja schlecht auf den
> 28974ten Encoderschritt warten und dann 10000 Schrittmotorschritte
> machen?!  Ich sehe es nicht, leider.

Erstmal: Kürzen.
Statt alle 28975 Encoderschritte 10000 Motorschritte alle 1159 
Encoderschritte 400 Schrittmotorschritte.

Dann: Bresenham. Variable anlegen als Fehlerakkumulator.
Jeder Encoderschritt zählt 400 Punkte dazu, jeder Schrittmotorschritt 
zieht 1159 Punkte ab. Da es sich um einen Fehler handelt, will man ihn 
möglichst klein haben. Gegen die Encoderschritte kannst du nichts 
machen; die kommen einfach irgendwann und bringen 400 Fehlerpunkte. Aber 
jedesmal wenn der "Kontostand" über 1159 ist, kannst du einen 
Schrittmotorschritt machen und damit 1159 Punkte abbauen.

von Stephan R. (Firma: FHK) (nautosteer)


Lesenswert?

Nosnibor schrieb:
> Dann: Bresenham. Variable anlegen als Fehlerakkumulator.
> Jeder Encoderschritt zählt 400 Punkte dazu, jeder Schrittmotorschritt
> zieht 1159 Punkte ab. Da es sich um einen Fehler handelt, will man ihn
> möglichst klein haben. Gegen die Encoderschritte kannst du nichts
> machen; die kommen einfach irgendwann und bringen 400 Fehlerpunkte. Aber
> jedesmal wenn der "Kontostand" über 1159 ist, kannst du einen
> Schrittmotorschritt machen und damit 1159 Punkte abbauen.

Wow.

von Falk B. (falk)


Lesenswert?

@ Nosnibor (Gast)

>Dann: Bresenham. Variable anlegen als Fehlerakkumulator.

VORSAGEN IST BÄHHH!!!!!!

von Rudolph (Gast)


Lesenswert?

Ah, das sind keine ganzen Schritte okay.
Wobei 1,67*3200 = 5344 ist. :-)

Hab mich gewundert, warum 5344/16 so krumm ist...

Warum also nicht 334 ganze Schritte statt 5344 Mikro-Schritten?
10mm/334 = 0,03 mm / Schritt

30720 / 334 = 91,976

Ist doch schick, alle 92 Impulse einen Schritt auslösen.

Hmm, 1,6 Umdrehungen für 1m Kabel, 750m Kabel.
36,864 Mio Impulse
-> 400800 Schritte notwendig

36,864 Mio / 92 -> 400695 Schritte, 105 Schritte daneben, das sind 
3,14mm.

Da kann man bestimmt noch was korrigieren.
Falls das überhaupt stimmt mit 5344 Mikro-Schritten pro 10mm.

von Nosnibor (Gast)


Lesenswert?

Falk Brunner schrieb:
> VORSAGEN IST BÄHHH!!!!!!

Ja.

Andererseits hilft das Stichwort "Bresenham" einem Neuling nicht viel. 
Die meisten Erklärungen, die man im Netz dazu findet, vernebeln den 
recht einfachen, einleuchtenden Kern mit mathematischen Formalismen und 
verstecken die Universalität hinter dem Fokus auf genau eine Anwendung. 
Kann man ihnen auch nicht vorwerfen, schließlich hat Jack Elton 
Bresenham den Algorithmus damals nur zum Zeichnen pixeliger Linien 
gebraucht, und wenn man ihn dafür verwendet, muß man wirklich auf den 
richtigen Startwert und die Vorzeichen und Quadranten achten, sonst 
kommt Schrott raus. Aber das ist eben nicht gemeint, wenn hier jemand 
"Bresenham" sagt.

von Mat (Gast)


Lesenswert?

Nosnibor schrieb:
> Dann: Bresenham. Variable anlegen als Fehlerakkumulator.
> Jeder Encoderschritt zählt 400 Punkte dazu, jeder Schrittmotorschritt
> zieht 1159 Punkte ab. Da es sich um einen Fehler handelt, will man ihn
> möglichst klein haben. Gegen die Encoderschritte kannst du nichts
> machen; die kommen einfach irgendwann und bringen 400 Fehlerpunkte. Aber
> jedesmal wenn der "Kontostand" über 1159 ist, kannst du einen
> Schrittmotorschritt machen und damit 1159 Punkte abbauen.

Wow, sehr verständlich erklärt. Danke :)

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


Lesenswert?

Hallo Rudolph,

> Warum also nicht 334 ganze Schritte statt 5344 Mikro-Schritten?
> 10mm/334 = 0,03 mm / Schritt
>
> 30720 / 334 = 91,976
>
> Ist doch schick, alle 92 Impulse einen Schritt auslösen.

Aus den gleichen Gründen, warum man auch sonst Mikroschritt statt 
Vollschritt verwendet:
- Ruhigerer Motorlauf
- Deutlich geringere Gefahr von Resonanzen im Motor (führt zu einem 
Einbrechen des Drehmoments und damit zu Schrittverlust)
- Geringere Schwingungsanregung der umliegenden Mechanik

Mit freundlichen Grüßen
Thorsten Ostermann

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.