Eine Frage der Machbarkeit

Hallo,

ich möchte gerne dem Arduino zunächst zwei Positionswerte übergeben (z.B. 65 und 95 Grad). Ein DC-Encoder-Motor soll dann zunächst auf die 65 Grad einregeln und direkt im Anschluss soll ein Servomotor auf 180 Grad und danach sofort wieder auf 0 Grad fahren. Danach soll der DC-Encoder-Motor die 95 Grad-Position anfahren und anschließend soll der Servo wieder auf 180 Grad und dann wieder auf 0 Grad fahren. Ist dies geschehen, soll der Arduino wieder auf zwei neue Positionswerte warten und dann das ganze wieder von neuem befehligen. Zwischen den Befehlen soll der DC-Encoder-Motor wieder auf die 0-Grad-Position fahren.

Ist sowas überhaupt möglich? Denn die Positionierung des DC-Encoder-Motors läuft ja über eine PID-Regelung, die (wahrscheinlich???) nicht unterbrochen werden kann und ja davon lebt, ständig in einer while-Schleife aktuell gehalten zu werden.

Falls das nicht geht, kann man das irgendwie auf andere Weise mit einem Arduino bewerkstelligen?

Viele Grüße

oppaernst:
Ist sowas überhaupt möglich?

Möglich ist fast alles :wink:
Mach Dir einen PAP - nicht das, was ich jetzt zusammengestellt habe sondern in grafisch.

Übergabe PosA: 65
Übergabe PosB: 95

Frage 1: Muss gewartet werden bis Pos A UND Pos B übergeben wurden?
Frage 2: Wann kommt ein Reset, wenn Pos A ODER Pos B nicht kommen?

  • Starte Encoderantrieb
  • Wenn Encoder PosA dann stoppe Encoderantrieb UND Servo 180
  • Wenn Servo 180 erreicht, dann Servo 0
  • Variante 1: UND starte Encoderantrieb
  • Variante 2: Warte auf Servo 0 und starte DANN Encoderantrieb
  • Wenn Encoder PosB dann stoppe Encoderantrieb UND Servo 180
  • Wenn Servo 180 erreicht, dann Servo 0
  • Variante 1: UND starte Encoderantrieb
  • Variante 2: Warte auf Servo 0 und starte DANN Encoderantrieb
    • Der Encoder geht dann auf 0
      [edit]
    • und wartet auf die Übergabe zweier Werte für PosA und PosB

Ich würde evtl. pro Wert eine Aktion bearbeiten, da alle Aktionen außer dem ersten Zielwert gleich sind und an 0 enden, könnte man das als Kriterium nehmen, um einen neuen Zielwert einzulesen.

Gruß Tommy

Hat der DC-Encoder-Motor nur den Ecnoder dran oder schon eine Positionsregelung?
Alterntiv zum DC-encoder-Motor könnte man einen Schrittmotor nehmen.
Schrittmotoren gibt es auch in groß und stark 1 Nm, 3Nm, 5Nm Drehmoment
Schrittmotoren halten ihre Position ohne das man noch irgendetwas über den Microcontroller regeln müsste.
Stromregelung und Microschritt-Regelung macht der Schrittmotortreiber

Und es gibt Servomotoren die über Schritt / Richtung angesteuert werden.
Da ist dann die PID-Lageregelung im Motortreiber integriert.

Der Microcontroller gibt Schritt/Richtungssignale aus Motor fährt auf Position und dann kann der Microcontroller
sich um was anderes kümmern.

Oder du nimmst einen kleinen zweiten Microcontroller der nur die PID-Lageregelung des DC-Encoder-Motors macht.

Wenn es mal eben 100 Euro kosten darf. Diese Regelung hat eine Auflösung von 0,01 Grad
https://www.01mechatronics.com/product/supermodified-v30-dc-motors

viele Grüße Stefan

Hallo zusammen,

hier mein Code, der das ganze Realisiert hat:

/////////////////////////////////////////////////////////////////////// CODE ////////////////////////////////////////////////////////////////////////////
// 
//        Ablaufplan
//
// 1.)    Warten auf irgendeine Eingabe im Serial Monitor, um den Programmstart zu triggern
// 2.)    Motor läuft, bis über den Schalter ein Interrupt ausgelöst wird und die aktuelle Encoder-Position (Pos.1) gespeichert wird (Kalibrierung)
// 3.)    Es wird auf die Pos.1 eingeregelt
// 4.)    Es wird eine Position angefahren (Pos.1 + Position)
// 4.1)   Servo auf 180° und dann auf 0°
// 5.)    Es wird eine weitere Position angefahren (Pos.1 + Position)
// 5.1)   Servo auf 180° und dann auf 0°
// 6.)    Einnehmen der Ausgansposition (Pos.1) und dann Pos.1 auf 0 setzen
// 7.)    gehe zu 1.)
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//        Init
//
#include <PIDController.h>                                                    // Inkludieren Bibliothek fuer PID-Controller
PIDController pos_pid;                                                        
// 
#include <Servo.h>                                                            // Inkludieren Bibliothek fuer Servo
Servo myServo;
//
char incomingByte;                                                            // Eingehende Bytes fuer Trigger Serial Monitor
//
int schalter_kali =0;                                                         // Schalter fuer Kalibrierung
//
volatile long int encoder_pos = 0;
int akt_encoder_pos = 0;
//
int motor_value = 255;                                                        // Motor-Wert
unsigned int integerValue[]={1000,2000};                                      // Max.-Wert ist 65535
unsigned long start0;                                                          // Startwert fuer millis() 
unsigned long start1;                                                         // Startwert fuer millis()
unsigned long start2;                                                         // Startwert fuer millis()
unsigned long start3;                                                         // Startwert fuer millis()
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//        VOID SETUP
//
void setup() {
//  
myServo.attach(6);                                                            // Servo wird auf PIN 6 gelegt
pinMode(2, INPUT);                                                            // PIN 2 ist ein INPUT (A-Signal Encoder)
pinMode(3, INPUT);                                                            // PIN 3 ist ein INPUT (B-Signal Encoder)
pinMode(5, INPUT);                                                            // PIN 5 ist ein INPUT (Interrupt-PIN fuer Speicherung Pos.1, siehe Ablaufplan oben)
pinMode(9, OUTPUT);                                                           // PIN 9 ist ein OUTPUT (POWER DC-MOTOR fuer Steuergeraet)
pinMode(10, OUTPUT);                                                          // PIN 10 ist ein OUTPUT (POWER DC-MOTOR fuer Steuergeraet)
pinMode(11,OUTPUT);                                                           // PIN 11 ist ein OUTPUT fuer Kontrolllampe (Motor dreht sich nicht)
pinMode(12,OUTPUT);                                                           // PIN 12 ist ein OUTPUT fuer Kontrolllampe (Motor dreht sich gegen den Uhrzeigersinn)
pinMode(13,OUTPUT);                                                           // PIN 13 ist ein OUTPUT fuer Kontrolllampe (Motor dreht sich im Uhrzeigernsinn)
//
Serial.begin(9600);                                                           // Starten des Serial Monitors mit Baudrate 9600 
//
attachInterrupt(digitalPinToInterrupt(2), encoder, RISING);                   // Interrupt fuer DC-MOTOR-REGELUNG
attachInterrupt(digitalPinToInterrupt(5), schalter, RISING);                  // Interrupt fuer Speicherung Pos.1, siehe Ablaufplan oben

pos_pid.begin();                                                              // Beginn PID   
pos_pid.tune(15, 0, 2000);                                                    // Tuning Anteile P I D 
pos_pid.limit(-255, 255);                                                     // Grenzen Motor-Wert
}
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//        VOID LOOP
//
void loop() {
//  
//  1.)
myServo.write(0);
digitalWrite(11, HIGH);
if (Serial.available() > 0) {
    do{   
      incomingByte = Serial.read();
      if (incomingByte == '\n') break;   
      if (incomingByte == -1) continue;
      Serial.println(incomingByte);  
    }while(1);
digitalWrite(11, LOW);
//
//  2.)
do{
schalter_kali=digitalRead(5);  
MotorCounterClockwise(255);
Serial.println(encoder_pos);
}while(schalter_kali == LOW);
//
//  3.)
start0=millis();    
for (int i = 1; i <= 1; i++) {
   do{
   pos_pid.setpoint(akt_encoder_pos);
   motor_value = pos_pid.compute(encoder_pos); //+255 oder -255
     if(motor_value > 0){
     MotorCounterClockwise(motor_value);
       }else{
        MotorClockwise(abs(motor_value));
        }
    Serial.println(encoder_pos);
    delay(10);
     }while(millis()-start0<5000);
      start0=millis();
   }
//
//  4.)
start1=millis();    
for (int i = 0; i <= 0; i++) {
   do{
   pos_pid.setpoint(integerValue[i]+akt_encoder_pos);
   motor_value = pos_pid.compute(encoder_pos); //+255 oder -255
     if(motor_value > 0){
     MotorCounterClockwise(motor_value);
       }else{
        MotorClockwise(abs(motor_value));
        }
Serial.println(encoder_pos);
delay(10);
      if (motor_value > 40 || motor_value < -40 ) {
     digitalWrite(11, LOW);
      }else{
       digitalWrite(11, HIGH);
       }  
     }while(millis()-start1<5000);
      start1=millis();
   }
//
//  4.1)   
delay(500);
myServo.write(180);
delay(500);
myServo.write(0);
digitalWrite(11, LOW);   
delay(500);
//
//  5.)
start2=millis();    
for (int i = 1; i <= 1; i++) {
   do{
   pos_pid.setpoint(integerValue[i]+akt_encoder_pos);
   motor_value = pos_pid.compute(encoder_pos); //+255 oder -255
     if(motor_value > 0){
     MotorCounterClockwise(motor_value);
       }else{
        MotorClockwise(abs(motor_value));
        }
Serial.println(encoder_pos);
delay(10);       
     if (motor_value > 40 || motor_value < -40 ) {
     digitalWrite(11, LOW);
      }else{
       digitalWrite(11, HIGH);
       }  
     }while(millis()-start2<5000);
      start2=millis();
   }
//
//  5.1)
delay(1000);
myServo.write(180);
delay(1000);
myServo.write(0);
delay(1000);
digitalWrite(11, LOW);   
//
// 6.)
start3=millis();    
for (int j = 1; j <= 1; j++) {
   do{
   pos_pid.setpoint(akt_encoder_pos);
   motor_value = pos_pid.compute(encoder_pos); //+255 oder -255
     if(motor_value > 0){
     MotorCounterClockwise(motor_value);
       }else{
        MotorClockwise(abs(motor_value));
        }
    Serial.println(encoder_pos);
    delay(10);
     }while(millis()-start3<5000);
      start3=millis();
   }
digitalWrite(11, HIGH);
encoder_pos=0;
Serial.println(akt_encoder_pos);
//
//  7.)
  }
}
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//        VOIDS
//
//  Interrupt fuer Kalibrierung
//
void schalter() {
akt_encoder_pos = encoder_pos;
}
//
//  Interrupt fuer Motorsteuerung
//
void encoder(){

  if(digitalRead(3) == HIGH){
    encoder_pos++;
  }else{
    encoder_pos--;
  }
}
//
//  Motor im Uhrzeigersinn drehen
//
void MotorClockwise(int power){
  if(power > 100){
  analogWrite(9, power);
  digitalWrite(10, LOW);
  digitalWrite(13, HIGH);
  }else{
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(13, LOW);
  }
}
//
// Motor gegen den Uhrzeigersinn drehen
//
void MotorCounterClockwise(int power){
  if(power > 100){
  analogWrite(10, power);
  digitalWrite(9, LOW);
  digitalWrite(12, HIGH);
  }else{
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
  }
}

Grüße

oppaernst:

/////////////////////////////////////////////////////////////////////// CODE 

// 1.)    Warten auf irgendeine Eingabe im Serial Monitor, um den Programmstart zu triggern
// 2.)    Motor läuft, bis über den Schalter ein Interrupt ausgelöst wird und die aktuelle Encoder-Position (Pos.1) gespeichert wird (Kalibrierung)
// 3.)    Es wird auf die Pos.1 eingeregelt
// 4.)    Es wird eine Position angefahren (Pos.1 + Position)
// 4.1)  Servo auf 180° und dann auf 0°
// 5.)    Es wird eine weitere Position angefahren (Pos.1 + Position)
// 5.1)  Servo auf 180° und dann auf 0°
// 6.)    Einnehmen der Ausgansposition (Pos.1) und dann Pos.1 auf 0 setzen
// 7.)    gehe zu 1.)

unsigned int integerValue[]={1000,2000};                                      // Max.-Wert ist 65535

pinMode(2, INPUT);                                                            // PIN 2 ist ein INPUT (A-Signal Encoder)
pinMode(5, INPUT);                                                            // PIN 5 ist ein INPUT (Interrupt-PIN fuer
attachInterrupt(digitalPinToInterrupt(2), encoder, RISING);                  // Interrupt fuer DC-MOTOR-REGELUNG
attachInterrupt(digitalPinToInterrupt(5), schalter, RISING);                  // Interrupt fuer Speicherung Pos.1, siehe Ablaufplan oben

Hallöle.

das Du mehrfach 160 / (Slashes) in eine Zeile kippst find ich schon bewerkenswert. Wer soll denn da noch Deinen Code lesen?
Kannst Du mir erklären, was der zweite Teil in 6. soll? - Ich halte das für absoluten Unsinn, da Du mit 7. das eh erledigst.

"intergerValue" ist nichts, was ich auch nur verstehen wollte, wo es später hingehört. Meine Empfehlung: Bitte unbedingt Bezeichnungen nehmen, die auch nachvollziehbar sind, wenn Du das in 3 Jahren überarbeiten willst.

Ich hoffe, das Du an PIN 2 und 5 die Beschaltung so gewählt hast, das Du sichergehen kannst, das die Routine auch das macht, was Du erwartest.

Danach habe ich - wegen der vielen Zeilen die wer weiss wo rechts aufhören - nicht mehr weitergelesen.

oppaernst:
hier mein Code, der das ganze Realisiert hat:

Danke für die Rückmeldung, ich finde, so sollte es sein :slight_smile:

Wenn Du Dich in ein paar Jahren noch mit Arduino beschäftigst, wirst Du feststellen, daß sich Deine Programmierkünste weitereintwickelt haben. Das ist ganz normal ::slight_smile:

//        VOIDS

Es gibt keine "voids". Void ist ein Datentyp:

Die Dinger heißen Funktionen

Und Multi-Byte Variablen die du in Interrupt änderst solltest du außerhalb bei abgeschalteten Interrupts auslesen