ESP32 und 2 Servos unterschiedlich schnell laufen lassen

Hallo zusammen,
Ich habe 2 Servos an GIPO 26 & 25 angeschlossen, soweit funktioniert auch alles.
Folgenden Code habe ich gefunden und modifiziert…

#define TIMER_WIDTHa 16
#define channela 1
#define channelb 2
#define pina 26
#define pinb 25

#define USMIN  1200 // This is the rounded 'minimum' 
#define USMAX  8700 // This is the rounded 'maximum' 
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates

int SRV_a_pos;
boolean SRV_a_moveFoward;
long SRV_a_nextWakeUp;

int SRV_b_pos;
boolean SRV_b_moveFoward;
long SRV_b_nextWakeUp;

void setup() {
  Serial.begin(115200);
   ledcSetup(channela, SERVO_FREQ, TIMER_WIDTHa); // channel 1, 50 Hz, 16-bit width
   ledcSetup(channelb, SERVO_FREQ, TIMER_WIDTHa); // channel 2, 50 Hz, 16-bit width
   ledcAttachPin(pina, channela);   // GPIO 26 assigned to channel 1
   ledcAttachPin(pinb, channelb);   // GPIO 25 assigned to channel 2
      
// init the compontent’s states
SRV_a_pos = USMIN;
SRV_a_moveFoward = true;
SRV_a_nextWakeUp = millis();

SRV_b_pos = USMIN;
SRV_b_moveFoward = true;
SRV_b_nextWakeUp = millis();

}

void loop() {
long currentTime = millis();
long nextWakeUpSRV_a = SRV_a_doStep(currentTime);
long nextWakeUpSRV_b = SRV_b_doStep(currentTime);
}

/* ** SERVO_a ** */
long SRV_a_doStep(long currentMillis) {
if(currentMillis>SRV_a_nextWakeUp) {
if(SRV_a_moveFoward) {
SRV_a_pos += SRV_a_getIncrement();
if(SRV_a_pos>USMAX) {
SRV_a_moveFoward = false;
SRV_a_pos = USMAX;
}
} else {
SRV_a_pos -= SRV_a_getIncrement();
if(SRV_a_pos<USMIN) {
SRV_a_moveFoward = true;
SRV_a_pos = USMIN;
}
}
Serial.print("Servo A pos "); Serial.println(SRV_a_pos);
      ledcWrite(channela, SRV_a_pos);       // sweep servo 1
SRV_a_nextWakeUp = currentMillis + 1;
}
return SRV_a_nextWakeUp;
}

int SRV_a_getIncrement() {
return 1;
}

/* ** SERVO_b ** */
long SRV_b_doStep(long currentMillis) {
if(currentMillis>SRV_b_nextWakeUp) {
if(SRV_b_moveFoward) {
SRV_b_pos += SRV_b_getIncrement();
if(SRV_b_pos>USMAX) {
SRV_b_moveFoward = false;
SRV_b_pos = USMAX;
}
} else {
SRV_b_pos -= SRV_b_getIncrement();
if(SRV_b_pos<USMIN) {
SRV_b_moveFoward = true;
SRV_b_pos = USMIN;
}
}
Serial.print("Servo B pos "); Serial.println(SRV_b_pos);
      ledcWrite(channelb, SRV_b_pos);       // sweep servo 2  
SRV_b_nextWakeUp = currentMillis + 1;
}
return SRV_b_nextWakeUp;
}

int SRV_b_getIncrement() {
return 5;
}

Nun mein Problem beide Servos Flattern manchmal. Servoa bei USMAX mehr.
Ich vermute es hängt mit den Timern des ESP32 oder dem Timing zusammen.
An den SG90 Servos kann es nicht liegen mit "for" laufen sie sauber, die Unterbrechung kann ich aber nicht gebrauchen.

Was habe ich falsch gemacht und was kann ich ändern?

Habe auch schon an TaskScheduler.h gedacht.
Nen Test Sketch habe ich auch geschrieben, Servoa Flattert am ende bei USaMAX genau so wie bei dem anderen Sketch. Aber nicht immer, ich bin bissel Ratlos... nen Oszi habe ich nicht um zu schauen was für Flanken kommen.
Die Prio 1,2,3 Tasks erst mal nicht beachten, die laufen nur mit.

Vielleicht hat auch dazu jemand eine Idee?

#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_PRIORITY
#define _TASK_WDT_IDS
#define _TASK_TIMECRITICAL
#include <TaskScheduler.h>

Scheduler r, hpr;

// Callback methods prototypes
void tCallback1();
void tCallback2();
void tCallback3();
void tCallback40();
void tCallback50();

#define TIMER_WIDTHa 16
#define channela 1
#define channelb 2
#define pina 26
#define pinb 25

#define USaMIN  2000 // This is the rounded 'minimum'
#define USaMAX  6000 // This is the rounded 'maximum'
#define USbMIN  1200 // This is the rounded 'minimum'
#define USbMAX  8700 // This is the rounded 'maximum'
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates

//Servo SRV_servo;
int SRV_a_pos;
boolean SRV_a_moveFoward;
long SRV_a_nextWakeUp;

int SRV_b_pos;
boolean SRV_b_moveFoward;
long SRV_b_nextWakeUp;

// Tasks
Task t1(0, TASK_FOREVER, &tCallback1, &r);  //adding task to the chain on creation
Task t2(0, TASK_FOREVER, &tCallback2, &r);
Task t3(0, TASK_FOREVER, &tCallback3, &r);

Task t4(0, TASK_FOREVER, &tCallback40, &hpr);  //adding task to the chain on creation
Task t5(0, TASK_FOREVER, &tCallback50, &hpr);  //adding task to the chain on creation

void tCallback1() {
  Scheduler &s = Scheduler::currentScheduler();
  Task &t = s.currentTask();
  
  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());

  if (t.getId() == 3) Serial.println();
}
void tCallback2() {
  Scheduler &s = Scheduler::currentScheduler();
  Task &t = s.currentTask();
  
  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());

  if (t.getId() == 3) Serial.println();
}
void tCallback3() {
  Scheduler &s = Scheduler::currentScheduler();
  Task &t = s.currentTask();
  
  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());

  if (t.getId() == 3) Serial.println();
}
void tCallback40() {
  Scheduler &s = Scheduler::currentScheduler();
  Task &t = s.currentTask();
  
  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());

  if (t.getId() == 3) Serial.println();
    if(SRV_a_moveFoward) {
    SRV_a_pos += SRV_a_getIncrement();
      if(SRV_a_pos>USaMAX) {
        SRV_a_moveFoward = false;
        SRV_a_pos = USaMAX;
      }
    } else {
      SRV_a_pos -= SRV_a_getIncrement();
      if(SRV_a_pos<USaMIN) {
      SRV_a_moveFoward = true;
      SRV_a_pos = USaMIN;
    }
}
Serial.print("Servo A pos "); Serial.println(SRV_a_pos);
      ledcWrite(channela, SRV_a_pos);       // sweep servo 1
}

int SRV_a_getIncrement() {
  return 10;
}
  

void tCallback50() {
  Scheduler &s = Scheduler::currentScheduler();
  Task &t = s.currentTask();
  
  Serial.print("Task: "); Serial.print(t.getId());Serial.print(":\t");
  Serial.print(millis()); Serial.print("\tStart delay = "); Serial.println(t.getStartDelay());

  if (t.getId() == 3) Serial.println();

  if(SRV_b_moveFoward) {
    SRV_b_pos += SRV_b_getIncrement();
    if(SRV_b_pos>USbMAX) {
      SRV_b_moveFoward = false;
      SRV_b_pos = USbMAX;
    } 
  } else {
    SRV_b_pos -= SRV_b_getIncrement();
    if(SRV_b_pos<USbMIN) {
    SRV_b_moveFoward = true;
    SRV_b_pos = USbMIN;
    }
}
Serial.print("Servo B pos "); Serial.println(SRV_b_pos);
      ledcWrite(channelb, SRV_b_pos);       // sweep servo 2  
}

int SRV_b_getIncrement() {
  return 50;
}

void setup () {
  Serial.begin(115200);
  Serial.println("Scheduler Priority Test");

  t4.setId(40);
  t5.setId(50);

  r.setHighPriorityScheduler(&hpr); 
  r.enableAll(true); // this will recursively enable the higher priority tasks as well

   ledcSetup(channela, SERVO_FREQ, TIMER_WIDTHa); // channel 1, 50 Hz, 16-bit width
   ledcSetup(channelb, SERVO_FREQ, TIMER_WIDTHa); // channel 2, 50 Hz, 16-bit width
   ledcAttachPin(pina, channela);   // GPIO 26 assigned to channel 1
   ledcAttachPin(pinb, channelb);   // GPIO 25 assigned to channel 2
      
   SRV_a_pos = USaMIN;
   SRV_a_moveFoward = true;

   SRV_b_pos = USbMIN;
   SRV_b_moveFoward = true;
}


void loop () {
  
  r.execute();
  
}

Wenn ich ehrlich bin gefällt mir der TaskScheduler schon besser :wink:

Hallo zusammen,

ich habe die Lösung.
Im Grunde sind es 2 Dinge die ich geändert habe.

Zuerst habe ich den channel geändert damit ein gemeinsamer Timer verwendet wird.

#define channela 0
#define channelb 1

Ergebnis:
Die Servos liefen schon besser, es flatterte seltener aber nach einem Langzeittest blieb Servo_a einfach stehen. :o

Noch etwas im Netz recherchiert dann fiel es mir wie Schuppen von den Augen. :o

Schuld war die Stromversorgung, über USB ist die Versorgung der Servos nicht ausreichend sie bleiben stehen und/oder flattern.

Habe dann ein 12V 3A Netzteil über DC-DC Step Down Converter HY-P332 mit 3,3 V / 5 V / 12 V angeschlossen und alles lief geschmeidig ohne flattern und hängen.