Forum: Mikrocontroller und Digitale Elektronik Schritte vor und zurück zählen mit Inkrementalgeber


von Dog G. (dogger) Flattr this


Lesenswert?

Erst einmal Hallo
Bin ziemlich neu hier und habe bis jetzt immer direkt meine Antworten zu 
meinen Problemen gefunden !
Aber jetzt bin ich am verzweifeln !

Zu Thema:
Ich habe ein Tintenstrahldrucker so weit zerlegt das ich nur noch die 
Druckerkopfaufnahme und die Achse  auf der der Druckerkopf läuft, mit 
dem DC-Motor und den Zahnriemen.
Jetzt möchte ich den Druckerkopf auf der Achse  in meine Gewünschte 
Position bewegen ( die Position soll sich erst einmal mit einem Poti 
verändern lassen)
Um das erst einmal Technisch aufzubauen habe ich einen optischen 
Inkrementalgeber aus anderen teilen des Druckers und "Strichrasterband" 
mit gröberer Auflösung zur Position Erkennung eingebaut!

Zum Problem:
Ich schaffe es nicht die Position des Druckerkopfs genau auszulesen.
Er verzählt sich immer wieder und das schon nach der ersten links-rechts 
fahrt um 10-30 Schritte !

Ein paar Fakten:
-habe ein Arduino UNO Board mit einem ATmega328
-Der Inkrementalgeber liest mit großer Sicherheit jeden Impuls vom 
"Strichrasterband"
-Besonders langsame Fahrten 1m/h werden zum teil über Haupt nicht 
gezählt!
-Der Inkrementalgeber hat 2 digitale Ausgänge: Wenn ich eine Karte von 
links nach rechts durchzieh bleibt er auf A1=HIGH A2=LOW. Ziehe ich die 
Karte von rechts nach links bleibt er auf A1=LOW A2=HIGH.
-Ich habe sehr wenig Erfahrung in C/C++ und habe das meiste an 
Programmen mir zusammen gefummelt und verändert bis es läuft !

Mein Programm:
Ich weiß das hier vieles nicht gebraucht wird aber gehe jetzt einfach 
mal davon aus das Geschwindigkeit nicht mein Problem ist !
Wie gesagt das Programm gibt mir zwar einen Zählerstand wieder und 
erkennt auch die Richtung (zählt rauf und runter) aber lässt viele 
Schritte aus und das meist bei langsamen !

1
int Refahrt = LOW;
2
int fahrtR;
3
int fahrtL;
4
int soll;
5
int sollmax;
6
int sollmin;
7
int ES =6;
8
int reset;
9
int SensorL =3;
10
int SensorR =2;
11
int val;
12
int val0;
13
int SensorRst;
14
int SensorLst;
15
int StreckeR = 0;
16
const int LEDR =4;
17
const int LEDL =5;
18
 const int led = 9  ;
19
 const int led1 = 10  ; 
20
void setup(){
21
  pinMode(SensorR, INPUT);
22
  pinMode(SensorL, INPUT);
23
  pinMode(ES, INPUT);
24
  Serial.begin(9600);
25
 SensorRst = digitalRead(SensorR);
26
 SensorLst = digitalRead(SensorL);
27
  pinMode(LEDR, OUTPUT);
28
  pinMode(LEDL, OUTPUT);
29
   pinMode(led, OUTPUT);
30
   pinMode(led1, OUTPUT);
31
    
32
 
33
}
34
int sollAnalog ()
35
{
36
  int v;
37
  v = analogRead(A0);
38
  v -=500;
39
  v  /=4;
40
  return v;
41
}
42
43
void loop() {
44
  val = digitalRead(SensorR);  
45
  val0 = digitalRead(SensorL);
46
  digitalRead(ES);
47
  fahrtL = digitalRead(SensorR)== LOW & digitalRead(SensorL)== HIGH ;
48
  fahrtR = digitalRead(SensorR)== HIGH & digitalRead(SensorL)== LOW ;
49
  
50
if (val != SensorRst){
51
    if(fahrtR == LOW) {
52
      if(fahrtL == HIGH){
53
      StreckeR--;      
54
      }           
55
     }
56
     SensorRst = val ;
57
    }         
58
if (val0 != SensorLst){
59
    if( val0 == LOW) {
60
     if(fahrtR == HIGH){
61
      StreckeR++;
62
       
63
      }
64
     Serial.println(StreckeR);
65
     }
66
     SensorLst = val0 ;
67
  }
68
69
 
70
  
71
if (digitalRead(ES) == HIGH){ // Positionsangabe durch Enschalter reseten
72
  StreckeR = 0;
73
}
74
if (Refahrt == LOW){
75
  while(digitalRead(ES) == LOW ){
76
    analogWrite(led, 0);  // turn the LED on (HIGH is the voltage level)
77
    analogWrite(led1, 130);
78
  }
79
  Refahrt = HIGH;
80
}
81
82
 soll =  sollAnalog();
83
sollmin = soll - 1 ;
84
sollmax = soll + 1 ;
85
if (soll != StreckeR){
86
  if (sollmax <  StreckeR){
87
  analogWrite(led, 0);  // turn the LED on (HIGH is the voltage level)
88
  analogWrite(led1, 130);
89
 // fahrtR = LOW;
90
//  fahrtL = HIGH;
91
  }else {
92
    analogWrite(led1,0);
93
  }
94
  if (sollmin > StreckeR){
95
  analogWrite(led1, 0);    // turn the LED off by making the voltage LOW
96
  analogWrite(led, 130);
97
 // fahrtL = LOW;
98
 // fahrtR = HIGH;
99
  } else {
100
    analogWrite(led,0);}
101
                 // wait for a second
102
}
103
104
 // Schritt überwachung  
105
    if (val == HIGH) {     
106
    // turn LED on:    
107
    digitalWrite(LEDR, HIGH);  
108
  } 
109
  else {
110
    // turn LED off:
111
    digitalWrite(LEDR, LOW); 
112
  }
113
    if (val0 == HIGH) {     
114
    // turn LED on:    
115
    digitalWrite(LEDL, HIGH);  
116
  } 
117
  else {
118
    // turn LED off:
119
    digitalWrite(LEDL, LOW); 
120
  }
121
}

: Verschoben durch Admin
von Dog G. (dogger) Flattr this


Lesenswert?

Fallst jemand darauf stossen sollte !

Inkrementalgeber fuktionieren nur wenn die Scheibe oder das Band mit dem 
Strichcode genau auf den Inkrementalgeber abgestimmt ist.
Wird das raster grösser oder kleiner ist verzählt sich der 
Inkrementalgeber immer wieder und mann hat so Probleme wie ich oben !
Ansonsten fuktoniert der Code den ich oben geschrieben habe !

von skink (Gast)


Lesenswert?

>Inkrementalgeber fuktionieren nur wenn die Scheibe oder das Band mit dem
>Strichcode genau auf den Inkrementalgeber abgestimmt ist.
Nein. Es liegt am Code.
Lies Dir mal den Artikel 
"http://www.mikrocontroller.net/articles/Drehgeber"; durch. Dort ist das 
Problem beschrieben.

Im Prinzip hast Du 4 Zustände: 00, 01, 11 und 10. Wanderst Du von einem 
der 4 Zustände nach rechts, musst Du hochzählen, wanderst Du nach links, 
runter.

von skink (Gast)


Lesenswert?

So lässt sich übrigens einfach prüfen, ob der Code richtig ist:
Jeweils die eine und die andere Leitung trennen. Dreht man jetzt 
langsam, muss der Zähler immer eins hoch und dann wieder eins runter 
zählen. Also beispielsweise 70,71,70,71,70 ...
Zählt er weiter oder gar nicht, ist der Code falsch.

von Mike (Gast)


Lesenswert?

skink schrieb:
> Nein. Es liegt am Code.
In diesem Fall schon, aber ...

> Im Prinzip hast Du 4 Zustände: 00, 01, 11 und 10. Wanderst Du von einem

i,A. muss der Strichcode breiter als der Geberabstand sein, damit 
sichergestellt ist, dass beim Bewegen alle vier Zustände der Reihe nach 
auftreten.

von Axel S. (a-za-z0-9)


Lesenswert?

Wobei sich die Frage stellt, wozu man überhaupt einen zusätzlichen 
Encoder braucht. Der Schrittmotor liefert diese Information ja schon 
frei Haus.


XL

von Karl H. (kbuchegg)


Lesenswert?

Und wenn der Schrittmotor aus irgendeinem Grund blockiert ist und nicht 
steppt, dann stimmt die Zählung nicht mehr.

von Dog G. (dogger) Flattr this


Lesenswert?

OK zugegeben ich weiss nicht mehr genau ob das Programm was da oben 
stehet noch richtig ist !

Aber ich kann sicher bestätigen das die Inkrementalgeber aus einem 
Drucker nur mit dem Strichcode laufen mit dem sie verbaut sind.

Ich habe ein größeren Strichcode gebastelt und er hat sich immer 
verzählt !

Das Programm was ich genutzt habe :
1
 
2
int B=2;
3
int A=3;
4
int Wert;
5
6
void setup (){
7
  attachInterrupt(0,CHAInt,CHANGE);        // Call Channel A of ENCODER Function while on CH1 Signal Changing
8
  pinMode(2,INPUT);
9
  pinMode(3,INPUT);
10
  digitalWrite(2,HIGH);
11
  digitalWrite(3,HIGH);
12
  Serial.begin(9600);
13
}
14
15
void loop(){
16
17
  // Hier kannst du dann mit der Variabeln Wert machen was du willst
18
Serial.println(Wert);
19
}
20
21
void CHAInt (){
22
  
23
  boolean Aread=false;
24
  boolean Bread=false;
25
  Aread=digitalRead(A);
26
  Bread=digitalRead(B);
27
  if (Aread==true && Bread==false||Aread==false && Bread==true){
28
    Wert--;
29
  }
30
  if (Aread==false && Bread==false ||Aread==true&& Bread==true){
31
    Wert++;
32
  }
33
}

von Fa. Rast und Ruh (Gast)


Lesenswert?

Der Stichabstand vom Band muss zum Stichabstand der Maske passen die vor 
den Detektoren sitzt. Band und Maske haben eine Differenz im 
Stichabstand so das beim übereinanderlegen ein Interferenzmuster mit 
hellen und dunklen Stellen entsteht. An diesen Stellen sitzen die 
Phototransistoren.

von Josef D. (jogedua)


Lesenswert?

Peter Hunsen schrieb:

> Ich habe ein größeren Strichcode gebastelt und er hat sich immer
> verzählt !

Das kann auch an anderen Unzulänglichkeiten liegen.

>
> Das Programm was ich genutzt habe :
>

>   // Hier kannst du dann mit der Variabeln Wert machen was du willst
> Serial.println(Wert);

Es muss aber sichergestellt werden, dass "Wert" nicht während der 
Benutzung in der ISR geändert wird (Stichwort ATOMIC).


>   if (Aread==true && Bread==false||Aread==false && Bread==true){
>     Wert--;
>   }
>   if (Aread==false && Bread==false ||Aread==true&& Bread==true){
>     Wert++;
>   }

Was passiert, wenn  die Interrupts so kurz hintereinander auftreten, 
dass einer nicht behandelt wird, weil die ISR noch nicht fertig ist 
(Stichwort: prellen)? Das Programm kann das so gar nicht feststellen.

Besser wäre es, statt der PinChange-Interrupts einen Timer-Interrupt zu 
benutzen und alle vier mögliche Zustände (s. weiter oben) auszuwerten.

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.