Funktion abhängig von Encoderwert aufrufen

Hallo,

mit einem Arduino Mega lese ich die Impulse im Verlauf eines Motorencoders aus. In dessen Verlauf (Encoderwert auf Startposition 400, Endposition 75000) möchte ich, sagen wir alle 2000 Encoderimpulse, eine Funktion im Code aufrufen.
Wie könnte man das lösen? Ich dachte vielleicht an sowas wie Modulo??

Könnt ihr mir da mal auf die Sprünge helfen?

Joe

Immer die gleiche Funktion (dann wäre %2000 ein möglicher Weg) oder verschiedene Funktionen?

Gruß Tommy

Immer die gleiche Funktion. Dann wäre das mit Modulo zu lösen?

Ja.

Gruß Tommy

Danke dir, dann les ich mich mal in die Modulo Funktion ein. Hab ich noch nie gebraucht :wink:

Joe

Hi

if(!(wert%2000)){
   //do some shit
}

Das Modulo musst Du umdrehen (oder Deinen Aufruf in den ELSE-Zweig setzen).
Das ! bindet aber stärker als das % - daher die Klammer.
!(wert%2000) ergibt alle 2000 Zähler 1x true
Was Dir passieren könnte: In der loop() überspringst Du Encoderwerte - z.B., wenn der Encoderwert über Interrupt (Timer oder PCINT) gezählt wird.
Das siehst Du daran, daß Deine Funktion eben nicht aufgerufen wird, weil das genaue Treffen der Zahl nicht sicher vorkommt.
Das habe ich noch mit einem Encoder, Der 600/r (2400 Flanken) ausgibt - bei 1500 r/min kommt der Uno gerade so mit Zählen hinterher - zumindest habe ich via Oszi nicht mehr wirklich viel Zeit, bevor der nächste Interrupt auslöst.

MfG

Ich dachte mir schon, dass das zeitkritisch werden wird, dann muss ich halt die Geschwindigkeit zurückstellen.
Wäre es möglich einen gewissen Encoderbereich zu definieren, den der Encoder zurückgibt, so dass die Funktion sicher ausgeführt wird? Mir käme es hier nicht auf den absolut exakten Encoderwert an.

if ((wert % 2000) < 10)

Gruß Tommy

OK ich glaub, dass ich das so verstehe “wenn der Rest der Division kleiner 10”, so dass die Funktion bereits bei einem Rest größer 0 und nicht erst bei exakt 0 aufgerufen wird?

Werd ich in der Praxis mal testen, welcher Wert gute Ergebnisse liefert.

dr_nobody:
Danke dir, dann les ich mich mal in die Modulo Funktion ein.

Das ist keine Funktion sondern ein Operator

Ja, den real günstigen Wert musst Du herausfinden.

Gruß Tommy

Serenifly:
Das ist keine Funktion sondern ein Operator

Sorry, war so schnell dahingeschrieben 8)

Hi

Da musst Du ‘nur’ noch ein Flag mitführen.

  if ((wert % 2000) < 10) {
    if (!flag) {
      flag = true;
      //do some shit
    }
  } else if (flag) {
    flag = false;
  }

MfG

Warum benötigt man das flag?

Hi

Das <10 wird bei langsam drehendem Encoder mehrere 100 Mal zutreffen - denke, Du wirst nur einen Aufruf pro Umdrehung haben wollen?
Über das Flag (… Flagge) merken wir uns, daß wir Das schon gemacht haben.
Somit führen wir Das nur 1x aus.
Aber dann müssen wir auch dafür sorgen, daß das Flag wieder gelöscht wird, wenn wir aus dem kritischem Bereich wieder draußen sind.

MfG

Du hast recht, so weit hatte ich das nicht durchdacht!! Danke

Da der Encoderwert “fortlaufend” ist, könnte man auch mit + - und < > hinkommen.
Diese Operatoren sind auf AVR um Größenordnungen billiger als %.
Dort dürften / und % mit Abstand die teuersten aller Operatoren sein.

Da hast Du allerdings auch recht, besonders wenn die Werte keine 2er-Potenzen sind.

Gruß Tommy

Momentan löse ich das so

  enc1 = rc.ReadEncM1(address); //Encoder Motor1 auslesen
  rc.SpeedAccelDeccelPositionM1(address, 1000, 2500, 1000, 75000, 1); // Motor geht zur Endposition
  while (enc1 < 75000) // laeuft solange bis Ende erreicht ist
  {
    pos = (enc1 / divisor); // entspricht einem 39tel der Motorstrecke, so oft soll die Funktion data() aufgerufen werden, divisor = 1913
    enc1 = rc.ReadEncM1(address); //Encoder Motor1 neu auslesen
    old_pos = pos; // aktuelle Position wird der Variablen old_pos zugewiesen
    pos = (enc1 / divisor); // wieder aktuelle Position berechnen

    if (old_pos != pos) { // wenn sich die aktuelle Position geaendert hat dann starte Funktion data()
          data(); // Funktion ausloesen
    }
  }

Das geht aber auch nur mit Geschwindigkeitseinbußen zuverlässig. Welche Lösung wäre nun effektiver? Oder gibt es noch einen anderen Lösungsansatz als meinen oder den mit modulo?

in etwa so wie du millis prüft, oder was auch combie angesprochen hat.

merken wo du bist,
prüfen, ob die aktuelle Position um (mindestens) 2000 von der alten abweicht

Ich glaube du brauchst zwei Drehrichtungen oder? Daher beim Vergleich aufpassen, habs der Einfachheit mit einem zweiten IF vorgesehen:

ungeprüft:

static int previousPos = pos;            // Variablentyp prüfen ob das int passend ist ?!?
if ((pos > previousPos) && (pos - previousPos > 2000))
{ 
  // callme();
  previousPos=pos;
}
else if ((pos < previousPos) && (previousPos - pos > 2000))
{ 
  // callme();
  previousPos=pos;
}