Servosteuerung (Bluebird 660 DMG+HS) mittels Drehencoder funktioniert nicht!!

Hey Community,

das ist mein erster Post hier und ich bin ein blutiger Anfänger. Dennoch hab ich mich an die Steuerung eines Servomotors mithilfe eines Drehencoders gewagt. Hier hab ich jedoch seit Wochen folgendes nervenzerreibendes Problem:

Bei der Drehung des Encoders bewegt sich mein Servomotor zwischen Position 158 und 25 (Anzeige über seriellen Monitor des Arduinos) mäßig gut und zittert bzw schlägt immer wieder zt sehr stark um sich. Von 25 bis 0 und von 179 bis 158 spinnt mein Servo total rum und schlägt komplett um sich. Das liegt wahrscheinlich daran, dass sich mein Servo nur um ca 140° drehen kann, jedoch kann ich mir das heftige Servozittern und Umschlagen zwischen der Pos 158 und 25 nicht erklären, da ich unter anderem 2 4700µF Kondensatoren an meinem Servo angeschlossen habe.

Der Aufbau müsste soweit richtig sein, denke dass der Fehler i.wo am Code liegen müsste aber ich habe keine Ahnung woran es liegen soll.

Dies ist der Code:

enum PinAssignments {
 encoderPinA = 2,   // right (labeled DT on our decoder, yellow wire)
 encoderPinB = 3,   // left (labeled CLK on our decoder, green wire)
 clearButton = 8,  // switch (labeled SW on our decoder, orange wire)
// connect the +5v and gnd appropriately
};

volatile byte encoderPos = 0;  // a counter for the dial
byte lastReportedPos = 1;   // change management
static boolean rotating=false;      // debounce management

byte maxPos = 179; // max number before rollover (servo max 0-179)
byte servoPos;    // variable for servo angle

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;

#include <EEPROM.h>
int addr = 0;

#include <Servo.h>
Servo myservo;  // create servo object to control a servo 

void setup() {
 
 encoderPos = EEPROM.read(addr);

 pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
 pinMode(encoderPinB, INPUT_PULLUP); 
 pinMode(clearButton, INPUT_PULLUP);
// turn on pullup resistors (old method)
 //digitalWrite(encoderPinA, HIGH);
// digitalWrite(encoderPinB, HIGH);
// digitalWrite(clearButton, HIGH);

// encoder pin on interrupt 0 (pin 2)
 attachInterrupt(0, doEncoderA, CHANGE);
// encoder pin on interrupt 1 (pin 3)
 attachInterrupt(1, doEncoderB, CHANGE);

 Serial.begin(9600);  // output
 myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
}

// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() { 
 rotating = true;  // reset the debouncer
if (encoderPos > maxPos) {
     encoderPos = 0;
   }
 if (lastReportedPos != encoderPos) {
   encoderPos = constrain(encoderPos, 0, maxPos);
   Serial.print("Index:");
   Serial.println(encoderPos, DEC);
   EEPROM.write(addr, encoderPos);
   lastReportedPos = encoderPos;
   //  set servo
   myservo.write(encoderPos);    // sets the servo position according to the scaled value 
 
  
 }
 if (digitalRead(clearButton) == LOW )  {
   encoderPos = 0;
 }
 
 
}

// Interrupt on A changing state
void doEncoderA(){
 // debounce
 if ( rotating ) delay (1);  // wait a little until the bouncing is done

 // Test transition, did things really change? 
 if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
   A_set = !A_set;

   // adjust counter + if A leads B
   if ( A_set && !B_set ) 
     encoderPos += 1;

   rotating = false;  // no more debouncing until loop() hits again
 }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
 if ( rotating ) delay (1);
 if( digitalRead(encoderPinB) != B_set ) {
   B_set = !B_set;
   //  adjust counter - 1 if B leads A
   if( B_set && !A_set ) 
     encoderPos -= 1;

   rotating = false;
 }
}

Ich bitte um Hilfe!! :disappointed_relieved:

Setze bitte deinen Code in Codetags ( das Symbol oben links im Editorfenster ). Das kannst Du auch nachträglich machen: Code markieren, und dann das Symbol </> drücken.

Alababa:
jedoch kann ich mir das heftige Servozittern und Umschlagen zwischen der Pos 158 und 25 nicht erklären, da ich unter anderem 2 4700µF Kondensatoren an meinem Servo angeschlossen habe.

Wo hast Du bei deinem Servo denn diese Kondensatoren angeschlossen :o ?

Sind denn die Werte, die Du an den Servo ausgibst, in Ordnung ( im seriellen Monitor )?

P.S. Um einen manuellen Drehencoder auszuwerten braucht’s auch keine Interrupts.

Und Du darfst im Interrupt keine delay verwenden!!

Wo hast Du bei deinem Servo denn diese Kondensatoren angeschlossen :o ?

Die sind unmittelbar hinter den +- Anschlüssen des Servomotors auf dem Steckboard angeschlossen, das längere Kondensatorbein bei + und das kürzere bei - .
Im seriellen Monitor zeigt er bei jeder Drehung des Encoders die darauffolgende Zahl an.

Und Du darfst im Interrupt keine delay verwenden!!

sprich ich muss die "if (rotating) delay" entfernen oder wie darf ich das verstehen?

Hatte den Code so aus einem Video übernommen wo er scheinbar funktioniert hatte :confused:

Ich kann das zwar jetzt mangels geeigneter HW nicht probieren, sehe aber die Interrupts als Problem. Auch die Servoimpulse werden per Interrupt erzeugt, und wenn deine Drehencoderinterrupts wegen des delay’s hängen, dann hat das massive Auswirkungen auf den Servoimpuls.
Ich weis zwar nicht was Du für einen Drehencoder hast, aber ich würde in ohne Interrupt auswerten. Das braucht man eigentlich nur bei den Drehencodern, die auf einer Motorwelle montiert sind, und zur Drehzahl- und Positionsbestimmung dienen. Die sind dann aber eh nicht mit mechanischen Schaltern und müssen nicht entprellt werden.

Mach die servo.write Befehele nicht von 0-180°, weil das machen die wenigsten Servos. Nimm die Werte 1000 bis 2000, das sind dann Microsekunden, das sollten alle Servos abkönnen.

Und wie gesagt, Rotary Auswertung ohne Interrupt

Und genügend starke Stromversorgung, die Servos nicht über den 5V Ausgang des Arduino versorgen