Forum: Mikrocontroller und Digitale Elektronik Roboter, ArduinoMicro, Wheelencoder, Auswertung


von Berus (Gast)


Angehängte Dateien:

Lesenswert?

Hallo wertes Forum,

ich wende mich an dich, weil ich mit meinem Latein am Ende bin. Ich 
soll/moechte einen Roboter bauen. Er ist ausgestattet mit einem Arduino 
Micro.

Dank einer Rueckkopplungsschleife soll es moeglich sein, dass er gerade 
aus faehrt, was er allerdings nicht tut.

Ich glaube, dass das daran liegt, dass mein Code die Geschwindigkeit auf 
Basis der beiden quadratur Wheelencoder nicht richtig bestimmt.

Das Prinzip fuer die Bestimmung der Geschwindigkeit ist ja:

Neue_Tickanzahl = Encoderticks; (Encoderticks kommen uber einen 
Hardwareinterrupt direkt vom Encoder)
Encoderticks = 0; (Zurueckezen der Encoderticks fuer nachfolgenden 
Durchlauf)

Neue_Tickanzahl - Alte_Tickanzahl;
Alte_Tickanzahl = Neue_Tickanzahl;

und diese Berechnung eben je Dauer einer Schleife. Meine Schleifendauer 
ist zu kurz, was ich daran erkenne, dass ich nur ein Tick pro 
Schleifendurchgang erhalte. Verlaengere ich die Schleifendauer dadurch, 
dass ich z.B. ein delay(1000)
vor diesen 4 Codezeilen einbaue, dann erhalte ich zwar 2000 Ticks pro 
Schleifendurchgang, aber dann spinnt mein linkes Rad. Es faehrt dann im 
Wechsel nach vorn und danach wieder nach hinten. Das passiert im 
Wechsel. Das rechte Rad hingegen fahert konstant gerade aus.

Ich weiss nicht genau, wo das Problem liegt. Ich weiss aber, dass ich 
mir nicht im klaren bin, wie ich die Geschwindigkeit richtig bestimme. 
Es harpert am Verstaendnis, an welcher Stelle ich die Encoderticks 
zuruecksetze, wo genau im Code die Geschwindigkeit berechnet werden soll 
und wie lange ein Schleifendurchgang dauern sollte. Ausserdem ist der 
Code ein Kompendium von Codeschnipsseln aus diversen Internetquellen. 
Diese habe ich versucht aneinander anzupassen, was mir vielleicht 
teilweise auch gelungen ist. Ich habe mich darein gearbeitet und die 
Theorie dahinter verstanden, aber bei der Umsetzung komme ich ins 
Stocken, weil mir die Erfahrung  im Programmieren und im Bauen von 
Robotern fehlt.

Zudem ist da noch das Problem, dass dies eine Gruppenarbeit ist und ich 
in zwei Wochen mit meinem Team den Roboter vorstellen muss. Ich will 
nicht scheitern und noch weniger will ich meine Kollegen haengen lassen. 
Ich hab mich mit dieser Arbeit wohl uebernommen.

Ich hab meinem Code im Anhang angehaengt. Ich bin fuer jede Hilfe 
dankbar.

FG,
Berus

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Berus schrieb:
> Robotercode.txt
Heißen diese Arduino-Programme nicht mit Nachnamen *.ino?
Probiers mal aus. Die Forensoftware dankt es dir mit 
Syntax-Highlighting...

Berus schrieb:
> dann erhalte ich zwar 2000 Ticks pro Schleifendurchgang, aber dann
> spinnt mein linkes Rad. Es faehrt dann im Wechsel nach vorn und danach
> wieder nach hinten.
Mit der aktiven Rechezeitvernichtung per delay() stellst du dich ja 
jedes Mal für 1 Sekunde tot. Da würde so mansches Programm nicht mehr 
funktionieren.

Wie wäre es, wenn du dir die Sache mit den millis() mal ansiehst?

> Encoderticks = 0; (Zurueckezen der Encoderticks fuer nachfolgenden
> Durchlauf)
Warum setzt du die Encoderticks zurück? Lass sie doch einfach immer 
weiterlaufen und berechne nur die Differenz zum alten Wert:
1
  Distanz = Encoderticks - Alte_Tickanzahl;
2
  Alte_Tickanzahl = Encoderticks;

von Delay (Gast)


Lesenswert?

Delay ist Böse - wusstest Du das noch nicht?

Benutz den internen Timer mit millis() - sonst bekommst du keine gleich 
langen Intervalle zwischen zwei Messungen weil dein Code unterschiedlich 
lange läuft.

Ansonsten hilft nur damit beschäftigen, damit beschäftigen und nochmal 
damit beschäftigen.

Man kann zwar erkennen, dass Du es versuchst, ganz abnehmen wird es dir 
aber kaum einer wollen...

von aSma>> (Gast)


Lesenswert?

Sowie in der biblischen Entstehungsgeschichte, als auch in der 
Regelungstechnik gibt es die s.g. EVA:
-Einlesen
-Verarbeiten
-Ausgeben

> Dank einer Rueckkopplungsschleife soll es moeglich sein, dass er gerade
> aus faehrt, was er allerdings nicht tut.

Aus der Aufgabenstellung wird generell nicht klar was du regelst. 
Geschwindigkeit oder Posisition?

Jedenfalls, muss du dafür sorgen, dass die Sensordaten kalibriert 
vorliegen. Hier scheiterst du wohl schon.

Weiterhin, ein digitaler Regler wird in Abhängigkeit der Abtastzeit 
erstellt, d.h man muss garantieren können, dass diese eingehalten wird.

von Berus (Gast)


Lesenswert?

@Lothar:

ich hab es versucht. Auch durch deinen Ansatz

Distanz = Encoderticks - Alte_Tickanzahl;
Alte_Tickanzahl = Encoderticks;

erhalte ich leider keine Geschwindigkeit/Distanz (wie du es nennst) bzw. 
kommt hierfuer Null heraus. Ich habe die Berechnung schon in die 
Rueckkopplungsschleife, die mit millis() arbeitet, hineinverschoben. 
Infolgedessen spinnen die Raeder wieder. Es geht so leider auch nicht.

@Gast:

Ich moechte ja gar nicht, dass mir jemand die ganze Arbeit abnimmt. Ich 
hoffe einfach nur, dass mir jemandn zeigt, wo der Wurm im Code drinne 
ist.

von Berus (Gast)


Lesenswert?

@aSma:

ich moechte die Wheelnencoder verwenden, um die Geschwindigkeit der 
Raeder zu bestimmen. Diese Ist-Werte der Geschwindigkeiten der beinden 
Raeder sollen mit einem Soll-Wert verglichen werden und innerhalb einer 
PI-Regelung diesem angepasst werden.

Diese Encoder verwende ich:

https://www.pololu.com/product/3081

von Jan Heynen (Gast)


Lesenswert?

Um die wheelencoder aus zu werten musst du mit bestimmte Intervallen die 
Werte von Encodertics anschauen. Diese Intervallen macht men nicht met 
"Delay" ! Einen Delay ist eine Warteschleife wo nur "gewartet" wird. 
Darum muss man ein Timer verwenden, dan lauft ihre Program weiter. Hier 
ein Beispiel mit LED Blinken : 
https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
Auf die gleicht art und weise geht das mit die Auswertung von die 
Encoder. In die Schleive wo jetzt die LED angesteurt wird, kommt ihre 
Zuweisung Speed_L=Neue_Wert-Alte_Wert;Alte_Wert=Neue_Wert;Das Interval 
(1000 ?) wird soklein moglich gewahlt, aber noch immer zo gross dat bei 
niedrige Drehzahlen noch minimal 2 bis 4 Pulsen gezahlt werden 
(Speed_L=4 Pulsen/Interval).Den Grund das dieses Interval klein sein 
muss, ist Regel -Geschwindigkeit. Men kan nur eine neue PWM-Wert 
forgeben nach passieren von Interval !! Mit hochauflosende Encoder sind 
Intervalle von 10 - 50 ms machbar !!

von Berus (Gast)


Lesenswert?

Danke fuer die hilfreiche Antwort. Das bringt mich vermutlich weiter. 
Ich teste das aus!

von Eric B. (beric)


Lesenswert?

Jan Heynen schrieb:
> Um die wheelencoder aus zu werten musst du mit bestimmte Intervallen die
> Werte von Encodertics anschauen. Diese Intervallen macht men nicht met
> "Delay" !

Die beide Encoder werden aber über Interrupt ausgewertet:
1
  attachInterrupt(digitalPinToInterrupt(0), LeftEncoderEvent, CHANGE);
2
  attachInterrupt(digitalPinToInterrupt(3), RightEncoderEvent, CHANGE);

von Wolfgang (Gast)


Lesenswert?

Berus schrieb:
> Ich glaube, dass das daran liegt, dass mein Code die Geschwindigkeit auf
> Basis der beiden quadratur Wheelencoder nicht richtig bestimmt.

Wozu interessiert dich überhaupt die Geschwindigkeit. Wenn die Räder 
keinen Schlupf haben, fährt der Roboter geradeaus, wenn beide Räder 
gleiche Strecken fahren.

> Neue_Tickanzahl = Encoderticks; (Encoderticks kommen uber einen
> Hardwareinterrupt direkt vom Encoder)

Hoffentlich sind deine Encoder vernünftig entprellt.

von Jan H. (jan_h565)


Lesenswert?

Die encoder tics zahlen macht men ueber der interrupt. Das war auch 
nicht das Problem (so hab ich es verstanden). Aber jetzt muss men aus 
diese Werte die Geschwindigkeit erfassen. Das geht dan mit die 
Aenderungen von tics ueber die Zeit zu berechnen (speed = differential 
von Strecke). Und dafur muss men dan millis() verwenden (Arduino). Delay 
ist nich geeignet, um das es blockierend ist.

von Claude J. (berus)


Lesenswert?

Ich habe die Auswertung in die Schleife genommen

1 Variante:

if(timeChange >= SampleTime){

SpeedL = LeftEncoderPos - oldPosL;
oldPosL = LeftEncoderPos;

SpeedR = RightEncoderPos - oldPosR;
oldPosR = RightEncoderPos;


2 Variante:
}

if(timeChange >= SampleTime){

SpeedL = LeftEncoderPos - oldPosL;
oldPosL = LeftEncoderPos;

SpeedR = RightEncoderPos - oldPosR;
oldPosR = RightEncoderPos;

}


Soll ich vielleicht Timer verwenden, um die Interrupts zum Zaehlen der 
Ticks nur in bestimmten Zeitabstaenden laufen zu lassen? Bis jetzt 
laufen sie staendig und ohne Pause. Ist das sinnvoll? Ich nehme einen 
Timer, um die Interrupt nur in bestimmten Abstaenden die Ticks zaehlen 
zu lassen.

von Jan H. (jan_h565)


Lesenswert?

Die Interrupts bleiben immer actif. Den ISR (interrupt service routine) 
wird nur aufgerufen beim Wechsel an Pin. Das ist naturlich das Forteil 
von so einen Interrupt, unabhangig von main() functioniert das nur wen 
notig !!
Aber ihre Schleife für Speed zu berechnen darf nur einmal pro Interval 
laufen !

if(timeChange >= SampleTime){
timechange=0;
SpeedL = LeftEncoderPos - oldPosL;
oldPosL = LeftEncoderPos;

SpeedR = RightEncoderPos - oldPosR;
oldPosR = RightEncoderPos;

}
Ich weiss nicht genau wie du "timechange" berechnet, aber dus muss 
sicher stellen das timechange wieder auf 0 geht beim durchlaufen von die 
Schleife.
Siehe auch noch das Arduino Beispiel.

von Thomas W. (Gast)


Lesenswert?

Für die Bestimmung der Geschwindigkeit gibt es grundsätzlich zwei 
Methoden. Bei der ersten wird die Anzahl der Encoder-Ticks innerhalb 
eines (festen) Zeitintervalls bestimmt, bei der zweiten die Anzahl der 
Timer-Ticks zwischen zwei Encoder-Ticks.
Welche Methode genauer ist, hängt vom Timertakt und von der 
Encoder-Tick-Frequenz (Encoderauflösung, Geschwindigkeit) ab.

Beide Methoden werden beim Reziprokzähler unter einen Hut gebracht.
http://www.mikrocontroller.net/articles/Frequenzz%C3%A4hlermodul#Messverfahren

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.