Schrittmotor wie Getriebemotor laufen lassen

Hallo Zusammen
Ich will die Geschwindigkeit des Getriebemotors wie die Geschwindigkeit des Schrittmotors regeln.
Zuerst wird die Geschwindigkeit des Schrittmotors mit Drehencoder festgelegt. Der Geschwindigkeit des Getriebemotors wird mit PID-Regler und 2 Drehgeber und Arduino Mega 2560 angesteuert. Mit Drehgeber 1 werde ich die Geschwindigkeit des Schrittmotors als Sollgeschwindigkeit des Getriebemotor und mit Drehgeber 2 die Istgeschwindigkeit des Getriebemotor messen.
Code:

#include <AccelStepper.h>    
#include <Encoder.h>          
#include <PID_v1.h>           


#define encoderA_1 18      // Pin A encoder(Drehgeber) 1  
#define encoderA_2 19      // Pin A encoder(Drehgeber) 2

#define DIR 10            // DIR motor Driver
#define PWM_OUTPUT 11     // PWM motor Driver

#define MESSINTERVALL 1000
#define ppr 100           //  Encoder 100p/r
#define r_roller 31      //Radius in mm  Durchmesser 6,2cm Encoder Roller Rad



// PID Regler  Definierung
double Setpoint, Input, Output;        //Setpoint: Sollwert,      Input: Istwert, 
double   Kp=0.2, Ki=0.2, Kd=0.1;       //PID Parameter   
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);  

   
Encoder Encod(2, 3);

AccelStepper stepper(1,9,8);   //(  ,9 (PUL+), 8(DIR))
                            
 volatile unsigned long isr_impulse_1 = 0;    // gezählte Impulse encoder 1
 volatile unsigned long isr_letzterImpuls_1=0; // wann der letzte Impuls encoder 1 gezählt wurde

 volatile unsigned long isr_impulse_2 = 0;    // gezählte Impulse encoder 2
 volatile unsigned long isr_letzterImpuls_2=0; // wann der letzte Impuls encoder 2 gezählt wurde

  static unsigned long zeit_1;
  static unsigned long letzterImpuls_1; // Zeit des letzten Impulses zum Zeitpunkt der letzten Messwertausgabe
  unsigned long impulse_1;
  float frequenz_1;
  float rps_1;
  float geschwindigkeit_1;

  static unsigned long zeit_2;
  static unsigned long letzterImpuls_2; // Zeit des letzten Impulses zum Zeitpunkt der letzten Messwertausgabe
  unsigned long impulse_2;
  float frequenz_2;
  float rps_2;
  float geschwindigkeit_2;
  

void setup()
{
   Serial.begin(115200);
   
   stepper.setMaxSpeed(320);      
   stepper.setAcceleration(20000);    
   pinMode (PWM_OUTPUT, OUTPUT);
   pinMode (DIR, OUTPUT);
   digitalWrite(DIR, HIGH);
   pinMode (encoderA_1, INPUT_PULLUP);
   pinMode (encoderA_2, INPUT_PULLUP);
     //turn the PID  on
   myPID.SetMode(AUTOMATIC);
   myPID.SetOutputLimits(0,255);
   myPID.SetSampleTime(1);   

   attachInterrupt(digitalPinToInterrupt(encoderA_1), encodermessung_1, RISING);    
   attachInterrupt(digitalPinToInterrupt(encoderA_2), encodermessung_2, RISING);
}

float read_speed_encoder1()
{
  static unsigned long ersteMessung_1; // Zeit der ersten Messwertausgabe
  static unsigned long letzteMessung_1; // Zeit der letzten Messwertausgabe
  static unsigned long Time_1;
geschwindigkeit_1=0.0;
  ersteMessung_1=millis(); // Aktuelle Zeit in Millisekunden
  if (ersteMessung_1 -letzteMessung_1 >= MESSINTERVALL) // Ist das Messintervall abgelaufen?
  {
    Time_1 = ersteMessung_1 -letzteMessung_1;
    letzteMessung_1 =ersteMessung_1;
    noInterrupts();  // Interrupts sperren
    // encoder1
    impulse_1 =isr_impulse_1; // volatile Variable auslesen
    isr_impulse_1=0;       // valatile Variable zurücksetzen
    zeit_1=isr_letzterImpuls_1 -letzterImpuls_1;
    letzterImpuls_1=isr_letzterImpuls_1;
    
    interrupts();   // Interrupts wieder zulassen
    //encoder1
    if (impulse_1>0) 
    {
    rps_1= impulse_1/(float)(zeit_1*ppr)*1000L;  
    geschwindigkeit_1 = rps_1 *2*r_roller* PI;    
    }
//    else {
//          frequenz_1=0;
//          impulse_1=0;
//          geschwindigkeit_1=0;
//          rps_1=0;
//    }    
   }
   return geschwindigkeit_1;  
}


float read_speed_encoder2()
{
  static unsigned long ersteMessung_2; // Zeit der ersten Messwertausgabe
  static unsigned long letzteMessung_2; // Zeit der letzten Messwertausgabe
  static unsigned long Time_2;
geschwindigkeit_2=0.0;
  ersteMessung_2=millis(); // Aktuelle Zeit in Millisekunden
  if (ersteMessung_2 -letzteMessung_2 >= MESSINTERVALL) // Ist das Messintervall abgelaufen?
  {
    Time_2 = ersteMessung_2 -letzteMessung_2;
    letzteMessung_2=ersteMessung_2;
    noInterrupts();  // Interrupts sperren
    
    //encoder2
    impulse_2 =isr_impulse_2; // volatile Variable auslesen
    isr_impulse_2=0;       // valatile Variable zurücksetzen
    zeit_2=isr_letzterImpuls_2 -letzterImpuls_2;
    letzterImpuls_2=isr_letzterImpuls_2;
    interrupts();   // Interrupts wieder zulassen
    
   
        if (impulse_2>0) 
    {
    rps_2= impulse_2/(float)(zeit_2*ppr)*1000L;
   
    geschwindigkeit_2 = rps_2 *2*r_roller* PI;    
   
    }
//    else {
//          frequenz_2=0;
//          impulse_2=0;
//          geschwindigkeit_2=0;
//          rps_2=0;
//    }
  }
    return geschwindigkeit_2;
}



void report(void)           // Ausgaben Serieller Monitor
{
   static uint32_t last=0;
  uint32_t now = millis();
  const uint32_t interval = 1000;
  if(now - last >= interval ){

   last= now;

      Serial.print("V_1:  ");Serial.print(read_speed_encoder1(),4);//Serial.print(geschwindigkeit_1,4);
       Serial.print('\t');
       Serial.print("V1 in m/min:  "); Serial.print((read_speed_encoder1()/16.666666666667), 4);
  

     Serial.print('\t');
      Serial.print("V_2:  ");Serial.print(read_speed_encoder2(),4);//Serial.print(geschwindigkeit_2,4);
      Serial.print('\t');
       Serial.print("V2 in m/min:  "); Serial.println((read_speed_encoder2()/16.666666666667), 4);

  }
   
}


long old_position  = -999;

void loop() 
{
  unsigned long new_position = Encod.read();
  if (new_position != old_position) {
    old_position = new_position;
      if(new_position> 320) {  new_position=320;  }
      if(new_position<0) {  new_position=0;   }
 
  }
   stepper.move(new_position);      
   stepper.run();

   Setpoint  = read_speed_encoder1()*2,8125;  //Umrechnung von der Gescwindigkeit in Pul
   Input = read_speed_encoder2()*2,8125;      //Umrechnung von der Gescwindigkeit in Pul
  
 if (myPID.Compute()) {
    analogWrite(PWM_OUTPUT, Output);
    digitalWrite(DIR,HIGH);
Serial.print("Output:  ");Serial.println(Output);
 }
  
     report();
}


void encodermessung_1()
{
   isr_impulse_1++;
   isr_letzterImpuls_1=millis();
}



void encodermessung_2()
{
   isr_impulse_2++;
   isr_letzterImpuls_2=millis();
}

Das Problem der Getriebemotor läuft nicht. Das was kommt raus:

11:27:06.316 -> V_1:  22.5612	V1 in m/min:  0.0000	V_2:  nan	V2 in m/min:  0.0000
11:27:07.188 -> Output:  0.00
11:27:07.302 -> V_1:  22.5395	V1 in m/min:  0.0000	V_2:  nan	V2 in m/min:  0.0000
11:27:08.187 -> Output:  0.00
11:27:08.306 -> V_1:  22.6487	V1 in m/min:  0.0000	V_2:  nan	V2 in m/min:  0.0000
11:27:09.186 -> Output:  0.00
11:27:09.312 -> V_1:  22.7590	V1 in m/min:  0.0000	V_2:  nan	V2 in m/min:  0.0000
11:27:10.186 -> Output:  0.00

kann jemand mir weiterhelfen.
Vielen Dank im Voraus

heisst das

"Ich will ein Getriebemotor durch einen Schrittmotor mit gleichem Drehmoment ersetzen"

oder

"ich habe zwei Motoren: Getriebe- und Schrittmotor. Ich möchte Schrittmotor Drehgeschwindigkeit der von Getriebemotor-Schaft anpassen"

?

Hallo,
Sorry, dass ich den Satz falsch ausgedrückt habe

Ich will die Geschwindigkeit des Getriebemotors wie die Geschwindigkeit des Schrittmotors regeln.

wie ist er angeschlossen?

DIR (Motortreiber) mit 10 Pin (Arduino Mega 2560)
PWM (Motortreiber) mit 11 Pin (Arduino Mega 2560)
GND (Motortreiber) mit GND Pin (Arduino Mega 2560)

Meine Frage:
PID-Regler regelt aufgrund der Differenz zwischen Soll- und Istgeschwindigkeit. bei mir Sollgeschwindigkeit ist Setpoint und Istgeschwindigkeit ist Input

und das was kommt raus:

V_1 ist Sollgeschwindigkeit und V_2 ist Istgeschwindigkeit
In diesem Fall sollte V_2 gleich 0 sein, weil der Getriebemotor nicht läuft. Wissen Sie, warum V_2 gleich nan ist?

Gleitkommatzahlen werden in C mit einem Punkt geteilt, der Komma-Operator macht ganz was anderes und setzt IMO Setpoint und Input auf 8125.

Vielen Dank für die Hinweise!

Ich habe noch ein Problem, und zwar die gemessene Geschwindigkeit durch Drehgeber 1 und 2 sind korrekt, solange der Getriebemotor noch nicht läuft. Wenn der Getriebemotor läuft, zeigt die gemessene Geschwindigkeit so viel zu groß

15:07:58.883 -> V_1:  1372.6151	V1 in m/min:  0.0000	V_2:  1671.2017	V2 in m/min:  0.0000
15:07:59.914 -> V_1:  1461.8125	V1 in m/min:  0.0000	V_2:  1667.3061	V2 in m/min:  0.0000
15:08:00.898 -> V_1:  1460.3531	V1 in m/min:  0.0000	V_2:  1768.7700	V2 in m/min:  0.0000

Das kommt mir seltsam vor. Drehst Du wirklich den Drehgeber 1 so schnell wie die Motoren laufen sollen?

Der Motor dreht im Geschwindigkeitsbereich 0-66 Millimeter pro Sekunde bzw. 0-4 Meter pro Minute

V_1 und V_2 sind in Millimeter pro Sekunde

Hallo,
ich vermute Störung durch EMV . Wie wird denn der Motor angesteuert. Wie sieht das Leistungsteil aus, gibt es Löschdioden ? Eventuell macht es Sinn eine Schutztbeschaltung zu verwenden. Eine zusätzliches C an ISR Eingang versuch mal 100nF parrallel zum Eingang.
Heinz

Hallo,
vielen Dank für den Vorschlag!
oder wäre auch von Interrupt Prioritäten?. kann man mehrere Interrupts gleichzeitig verwenden?

Hallo,
das machst Du doch schon

attachInterrupt(digitalPinToInterrupt(encoderA_1), encodermessung_1, RISING);
attachInterrupt(digitalPinToInterrupt(encoderA_2), encodermessung_2, RISING);

Mir ist aber immer noch nicht ganz klar was Du vorhast. Du hast den Sollwert Encoder_1 auf die Welle des Schrittmotors gebaut und willst den GS Motor synchron dazu betreiben. ? Dazu misst Du die Drehzahl mit einem zweiten Encoder_2 der auf der Welle des Getriebemotors sitzt.

Dann lass doch erst mal den PI Regler weg und lass den Getriebemotor mit einer konstanten Drehzahl laufen, die Du dann mit dem Encoder_2 messsen und überprüfen kannst. Wenn die Messung dann richtig funktioniert nimmst Du den Regelgreis mit dem PID Regler dazu. Und als letzten Schritt den Encoder_1 als Sollwert.
Heinz

Ja. Die Interrupts haben eine festgelegte Reihenfolge. Aber es gehen erst Interrupts verloren wenn mehrere auf dem gleichen Vektor ausgelöst werden bevor sie verarbeitet werden.

Hallo,

ja genau so

genauso habe ich gemacht. Wenn ich nur den Schrittmotor mit einer konstanten Drehzahl laufen lasse, funktioniert richtig also wird von Encoder_1 die richtigen Werte(gemessene Geschwindigkeit) und von Encoder_2 keine Werte also nur null im seriellen Monitor gezeigt.

Aber wenn ich nur den Getriebemotor mit einer konstanten Drehzahl laufen lasse, wird von beiden Encoder (Encoder_1 und Encoder_2) Werte gezeigt, Obwohl der Encoder_1 bzw. der Schrittmotor nicht dreht!

Hallo,
ok, das sieht mir dann doch nach EMV aus .
Siehe #10

Heinz

Ok vielen Dank.

ich benutze Labornetzgerät 0-30V und Ledmo Schaltnetzteil 24V und Motortreiber Cytron MD30C R2 für den Getriebemotor(DC24V40RPM).

wie kann ich das machen?

Hallo,
ok bei dem Treiber sollten eigentlich Löschdioden mit verbaut sein. Nun kann man noch einen Keramik Kondensator parallel zum Motor anschließen , ich denke auch 100nF / 50V , würde ich mal versuchen , eventuell 100Ohm mit in Reihe zu dem C
An die Eingänge für die Encoder ebenfalls einen Keramik Kondensator 100nF/50V gegen 0V und noch ebenso einen Widerstand.

such mal nach "rc schutzbeschaltung" oder "snubber"

Eventuell baut man auch einen Tiefpassfilter davor, Ziel sollte sein das unnötig hohe Frequenzen die da rein kommen können geblockt werden. Ich weiß jetzt nicht was Du an Frequenzen vom Encoder verarbeiten musst aber wenn man den Filter mal auf 5Kz auslegt.

such mal nach "Tiefpassfilter"

Wenn die Kabel zu den Encodern lang sind >2m sollten die auch abgeschirmt sein.
Eigentlich ist das ist das Thema EMV Störungen nicht ganz so einfach. Es gibt eine Menge allgemeine Grundlagen die man beachten sollte, dennoch kann das auch immer eine ziemliche Probiererei sein.
Heinz

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.