[GELÖST] 2 Servos, 2 Reedkontakte - Servo geht nicht auf Ausgangsposition zurück

Liebe Wissende,

ich bin gerade als Arduino-Neuling bei einem Experiment, bei dem ich im Programm Mist gebaut haben muss, aber nicht dahinter komme, wo der Fehler steckt.

Aufbau:
Ein Fahrrad mit einem Reed-Kontakt am Pedal und einem am Rad.

Wenn das Pedal gedreht wird sollen zwei Servos als Anzeigeinstrumente dienen: Einer zeigt die Umdrehungen pro Minute des Pedals, der andere des Rades an. Das funktioniert soweit auch ganz gut, Grundlage ist das Instructable für den DIY Bike Tachometer: http://www.instructables.com/id/DIY-bike-tachometer/

Nun zum Problem: Ich schaffe es nicht, den Pedal-Servo auf den Nullpunkt zurück zu stellen, wenn nicht mehr getreten/gekurbelt wird. Beim Rad habe ich zwar im Prinzip das gleiche Problem, hier fällt es aber nicht auf, da bei auslaufen des Rades der Servo irgendwann schlicht am Nullpunkt ankommt.

Es ist sicher was ganz simples, aber ich komme nicht drauf…

Code ist angehängt.

Vielen herzlichen Dank fürs draufschauen.

fahrrad_2_servos_V3.ino (3.72 KB)

Sorry, vorher die Code-Funktion nicht gesehen, und außerdem war der falsche Servo angesprochen:

//Verwendete librarys
#include  <Servo.h>
#include <Bounce2.h>

// Reedkontakte: REED1 Rad (Variable wheel), REED2 Pedal (Variable pedal)
#define REED1 A0
#define REED2 A1

// Benennung der Variablen für die Servos: myservo1=Rad myservo2
Servo myservo1;
Servo myservo2;

//Definition der Variablen für das Rad
 long previous1, time1, impulses1;
 float wheel;
 int servo1;
 
//Definition der Variablen für das Pedal
 long previous2, time2, impulses2;
 float pedal;
 int servo2;

 
// Initieren zweier Bounce-Objekte zum Entprellen der Reed-Kontakte debouncer1=REED1 (Variable wheel), debouncer2=REED2 (Variable pedal)
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
 
 void setup() {


  pinMode(REED1, INPUT);
  pinMode(REED2, INPUT);
  
  //Servo-Definition Anschluss Rad (wheel) und Zeiger Tachometer auf 0 setzen
  myservo1.attach(6); 
  myservo1.write(180);

  //Servo-Definition Anschluss Pedal (pedal) und Zeiger Pedalometer auf 0 setzen
  myservo2.attach(5); 
  myservo2.write(180);

  // Bounce-Instanz/Entprellung für Reedkontakt Rad (REED1):
  debouncer1.attach(REED1);
  debouncer1.interval(5); // interval in ms

  // Bounce-Instanz/Entprellung für Reedkontakt Pedal (REED2):
  debouncer2.attach(REED2);
  debouncer2.interval(5); // interval in ms


  Serial.begin(9600);

 } 




 void loop() {
      
  // Beide Bouncer-Instanzen updaten:
        debouncer1.update();        
        debouncer2.update();


   
   // Start wenn Rad sich dreht
   if(analogRead(REED2)>=300) {

     
   // Hochzählen der Umdrehungen
      impulses1++;
  // Umdrehungszeit Rad zählen, indem vorige Millisekunden von jetzigen Millisekunden abgezogen werden
    time1=(millis()-previous1);
   // Drehzahl messen
    wheel= 60000 / time1;

   // jetzige Millisekunden merken, um sie bei der nächsten Umdrehung abziehen zu können
  previous1=millis();
   // Zur Kontrolle Umdrehungszahl und Zeit auf seriellem Monitor ausgeben
  
    Serial.println("Rad: ");
    Serial.println(wheel);
    Serial.println("Radzeit: ");
    Serial.println(time1);
    
 // Warnmldung, wenn zu schnell gedreht wird
    if (wheel > 500) {
                         Serial.println("Hallo, zu schnell!");   
                        }
  // Tachometerfunktion aufrufen zur Anzeige
    Tachometer();
    
    
  delay(100);

  



   // Start wenn Pedal sich dreht
   if(analogRead(REED1)>=10) {

   // Hochzählen der Umdrehungen
      impulses2++;
  // Umdrehungszeit Pedal zählen, indem vorige Millisekunden von jetzigen Millisekunden abgezogen werden
    time2=(millis()-previous2);
   // Drehzahl messen
    pedal= 60000 / time2;
    // jetzige Millisekunden merken, um sie bei der nächsten Umdrehung abziehen zu können   
  previous2=millis();
   // Zur Kontrolle Umdrehungszahl und Zeit auf seriellem Monitor ausgeben
  
    Serial.println("Pedal: ");
    Serial.println(pedal);
    Serial.println("Pedalzeit: ");
    Serial.println(time2);
    Serial.println(analogRead(REED1));

 

  // Pedalmeterfunktion aufrufen zur Anzeige    
    Pedalmeter();
    
    
  delay(100);
   }

else {   
  
    myservo2.write(180);
    Serial.println("Pedal in Ruhe ");

}

  
}





   }




   
   //display speed on tachometer
   void Tachometer(){
     //map speed 0-180 to servo
  wheel=int(wheel);
  servo1 = map(wheel, 0, 180, 300, 0);
  //setup servo
  myservo1.write(servo1);
   }


   //display turns on pedalmeter
   void Pedalmeter(){
     //map speed 0-180 to servo
  pedal=int(pedal);
  servo2 = map(pedal, 0, 180, 50, 0);
  //setup servo
  myservo2.write(servo2);



  
   }

Die Meldung “Pedal in Ruhe” kommt auch auf dem serial monitor, aber der Servo folgt dem write-Befehl nicht.

forkliftcat:
Liebe Wissende,

Ja, schön wär's, dennoch willkommen im Forum!

debouncer1.attach(REED1);  // Bounce-Instanz/Entprellung für Reedkontakt Rad (REED1):
...
  if (analogRead(REED2) >= 300) {  // Start wenn Rad sich dreht

REED1 oder REED2, was ist Pedal, was Rad?

Einen Reedkontakt, der vorher entprellt wurde, mit analogRead einlesen, erscheint mir als keine gute Idee. digitalRead wäre besser.

if (analogRead(REED1) >= 300) {
...
pedal = 60000 / time2;

Hier stecken Deine zwei Probleme: Wird pedal gleich Null, muß time2 Unendlich sein. Darüberhinaus kommst Du nur bei einem Impuls in die Auswertung, ohne Impuls gibt es auch keine Verstellung des Servos.

Hier liegt die Lösung:

delay(100);

Du trennst ständige Messung und gelegentliche Anzeige. Wenn dann previous2 einen Grenzwert übersteigt, entspricht das Unendlich oder der Drehzahl Null.

Oder Du zählst die Impulse zwischen zwei Anzeigen, dann bedeuten keine Impulse die Drehzahl Null.

Vielen herzlichen Dank für die schnelle Antwort und die Tipps!

REED1 und REED2 wurden beim Zusammenbau vertauscht (ja...), REED2 ist das Rad, REED1 das Pedal.

Also gleich eine ganze Reihe von Problemen. Hmm, bei digitalRead tut sich bei dem Script dann gar nichts mehr, aber das scheint ja insgesamt Teil des Problems zu sein.

Andererseits muss ich dem Programm ja irgendeinen Startpunkt geben. Hmmm, zurück zum Zeichenbrett...

forkliftcat:
Hmm, bei digitalRead tut sich bei dem Script dann gar nichts mehr, aber das scheint ja insgesamt Teil des Problems zu sein.

Hast Du PullUp- oder PullDown-Widerstände am Eingang? Versuche mal

digitalWrite(13, digitalRead(REED2));

Dann siehst Du, ob Dein Eingang gelesen wird.

Taster am Arduino

Zuerst sagst du 180° = 0 auf dem Tacho

  //Servo-Definition Anschluss Rad (wheel) und Zeiger Tachometer auf 0 setzen
  myservo1.attach(6); 
  myservo1.write(180);
  //Servo-Definition Anschluss Pedal (pedal) und Zeiger Pedalometer auf 0 setzen
  myservo2.attach(5); 
  myservo2.write(180);

und hier

else
    {
      myservo1.write(0);
      Serial.println("Pedal in Ruhe ");
    }

ist es auf einmal bei 0?

Probier das doch mal aus.

Herzlichen Dank für die vielen guten Tipps. Werd’s nächste Woche mal komplett überarbeiten und euch wissen lassen, ob’s funktioniert hat.

forkliftcat:
... und euch wissen lassen, ob's funktioniert hat.

Guter Vorsatz, schönes Wochenende :slight_smile:

So, wollte euch nur wissen lassen, dass ich Dank eurer Tipps Fortschritte mache, auch wenn ich noch nicht 100% am Ziel bin. So sieht’s jetzt i Moment (der Einfachheit halber nur für das Rad, Rest kommt später) aus:

//Verwendete librarys
#include  <Servo.h>
#include <Bounce2.h>

// Reedkontakte: REED1 Rad (Variable wheel), REED2 Pedal (Variable pedal)
#define REED1 A0
#define REED2 A1

// Benennung der Variablen für die Servos: myservo1=Rad myservo2
Servo myservo1;
Servo myservo2;

//Definition der Variablen für das Rad
 long previous1, time1, impulses1, speicher_impuls1, speicher_zeit1;
 float wheel;
 int servo1, nullnummer1;
 
//Definition der Variablen für das Pedal
 long previous2, time2, impulses2;
 float pedal;
 int servo2;

 
// Initieren zweier Bounce-Objekte zum Entprellen der Reed-Kontakte debouncer1=REED1 (Variable wheel), debouncer2=REED2 (Variable pedal)
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
 
 void setup() {


  pinMode(REED1, INPUT);
  pinMode(REED2, INPUT);
  
  //Servo-Definition Anschluss Rad (wheel) und Zeiger Tachometer auf 0 setzen
  myservo1.attach(6); 
  myservo1.write(180);

  //Servo-Definition Anschluss Pedal (pedal) und Zeiger Pedalometer auf 0 setzen
  myservo2.attach(5); 
  myservo2.write(180);

  // Bounce-Instanz/Entprellung für Reedkontakt Rad (REED1):
  debouncer1.attach(REED1);
  debouncer1.interval(5); // interval in ms

  // Bounce-Instanz/Entprellung für Reedkontakt Pedal (REED2):
  debouncer2.attach(REED2);
  debouncer2.interval(5); // interval in ms
  

  Serial.begin(9600);

 } 




 void loop() {
      
  // Beide Bouncer-Instanzen updaten:
        debouncer1.update();        
        debouncer2.update();

//Letzten Impuls Rad merken
speicher_impuls1=impulses1;
//Aktuelle Zeit seit Start merken
speicher_zeit1=millis();

if(digitalRead(REED2)== HIGH ){

  Serial.println("Reed 2 is high");
  Serial.println(impulses1);
       
   // Hochzählen der Umdrehungen
      impulses1++;
      
  // Umdrehungszeit Rad zählen, indem vorige Millisekunden von jetzigen Millisekunden abgezogen werden
    time1=(millis()-previous1);


   // jetzige Millisekunden merken, um sie bei der nächsten Umdrehung abziehen zu können
  previous1=millis();

     // Drehzahl messen
   wheel= 60000 / time1;
  Serial.println("Wheel ist");
  Serial.println(wheel);

  wheel=int(wheel);
  servo1 = map(wheel, 0, 180, 300, 0);
  myservo1.write(servo1);

  delay (100);


}

speicher_zeit1=(millis()-previous1);

if ((impulses1==speicher_impuls1)&&(speicher_zeit1>10000)) {
  Serial.println("Dann halt nicht!");
  nullnummer1=155;
  myservo1.write(nullnummer1);
  }
  
}

Problem derzeit: Der Servo lässt sich nicht auf die vollen 180 Grad, also den Nullpunkt stellen, ab 155 Grad macht er gar nichts mehr. Mit Sweep-Beispiel funktioniert’s tadellos. Hmmmm :o :o

forkliftcat:
Problem derzeit: Der Servo lässt sich nicht auf die vollen 180 Grad, also den Nullpunkt stellen, ab 155 Grad macht er gar nichts mehr. Mit Sweep-Beispiel funktioniert's tadellos. Hmmmm :o :o

In #2 hatte ich schon was zur Division durch Unendlich geschrieben, steht immer noch so im Sketch.

agmue:
In #2 hatte ich schon was zur Division durch Unendlich geschrieben, steht immer noch so im Sketch.

Ja, stimmt. Ich stehe allerdings furchtbar auf dem Schlauch, wie ich das anders lösen kann. Hatte mir mittlerweile mal diesen sketch angesehen: http://www.instructables.com/id/Arduino-Bike-Speedometer/?ALLSTEPS dann aber herausgefunden, dass das nicht funktioniert, weil die servo library den timer 1 schon verwendet.

Es muss doch eine Möglichkeit geben, das mit dem ursprünglichen Skript hinzubekommen. Hab den Eindruck, es muss mir nur jemand einen Tritt in die richtige Richtung geben?

Aaalso, nochmal alles durchgegangen, Bezeichnungen der Reed-Kontakte zwecks besserer Lesbarkeit korrigiert, delays durch die Lösung “Blinken ohne delay” ersetzt, Code sieht jetzt so aus:

//Verwendete libraries
#include  <Servo.h>
#include <Bounce2.h>

// Reedkontakte: REED1 Rad (Variable wheel), REED2 Pedal (Variable pedal)
#define REED1 A1
#define REED2 A0

// Benennung der Variablen für die Servos: myservo1=Rad myservo2
Servo myservo1;
Servo myservo2;

//Definition der Variablen für das Rad
 long previous1, time1, impulses1, speicher_impuls1, speicher_zeit1;
 int wheel, servo1;
 
//Definition der Variablen für das Pedal
 long previous2, time2, impulses2, speicher_impuls2, speicher_zeit2;
 int pedal, servo2;

//Variablen als Ersatz für delay
unsigned long previousMillis1 = 0;
unsigned long interval1 = 200;
unsigned long previousMillis2 = 0;
unsigned long interval2 = 400;

 
// Initieren zweier Bounce-Objekte zum Entprellen der Reed-Kontakte debouncer1=REED1 (Variable wheel), debouncer2=REED2 (Variable pedal)
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
 
 void setup() {


  pinMode(REED1, INPUT);
  pinMode(REED2, INPUT);
  
  //Servo-Definition Anschluss Rad (wheel) und Zeiger Tachometer auf 0 setzen
  myservo1.attach(6); 
  myservo1.write(179);

  //Servo-Definition Anschluss Pedal (pedal) und Zeiger Pedalometer auf 0 setzen
  myservo2.attach(5); 
  myservo2.write(179);

  // Bounce-Instanz/Entprellung für Reedkontakt Rad (REED1):
  debouncer1.attach(REED1);
  debouncer1.interval(5); // interval in ms

  // Bounce-Instanz/Entprellung für Reedkontakt Pedal (REED2):
  debouncer2.attach(REED2);
  debouncer2.interval(5); // interval in ms
  

  Serial.begin(9600);

 } 




 void loop() {
      
  // Beide Bouncer-Instanzen updaten:
        debouncer1.update();        
        debouncer2.update();



if ((millis() - previousMillis2) > interval2) {
if(digitalRead(REED2)== HIGH ){


       
   // Hochzählen der Umdrehungen
      impulses2++;
      
  // Umdrehungszeit Rad zählen, indem vorige Millisekunden von jetzigen Millisekunden abgezogen werden
    time2=(millis()-previous2);


   // jetzige Millisekunden merken, um sie bei der nächsten Umdrehung abziehen zu können
  previous2=millis();

     // Drehzahl messen
   pedal= 60000 / time2;
  Serial.println("Pedal ist");
  Serial.println(pedal);

  servo2 = map(pedal, 0, 179, 90, 0);
  myservo2.write(servo2);

                    previousMillis2=millis();


}
       
                    
}



if ((millis() - previousMillis1) > interval1) {
  

if(digitalRead(REED1)== HIGH ){


       
   // Hochzählen der Umdrehungen
      impulses1++;
      
  // Umdrehungszeit Rad zählen, indem vorige Millisekunden von jetzigen Millisekunden abgezogen werden
    time1=(millis()-previous1);


   // jetzige Millisekunden merken, um sie bei der nächsten Umdrehung abziehen zu können
  previous1=millis();

     // Drehzahl messen
   wheel= 60000 / time1;
  Serial.println("Wheel ist");
  Serial.println(wheel);


  servo1 = map(wheel, 0, 179, 300, 0);
  myservo1.write(servo1);



                    previousMillis1=millis();
}

}
 



  if ((digitalRead(REED2)==LOW)&&((millis()-previousMillis2))>2000) {
  Serial.println("Dann halt nicht Pedal!");
  myservo2.write(160);
  }



   }

Eine Division durch Unendlich dürfte eigentlich durch die Verzögerung 200 bzw. 400 Millisekunden nicht mehr passieren. Das scheint aber nicht der Grund für mein ursprüngliches Problem gewesen zu sein. Auch jetzt akzeptiert er die 179 Grad für das Rückstellen nicht, erst mit 160 geht es, gleiches gilt für den Maximalauschlag 0 auf der anderen Seite. Beides erreicht er beim Sweep-Beispiel. Lösche ich alles innerhalb der loop und setze dafür

if ((digitalRead(REED2)==LOW)) {
  myservo2.write(179);
  }

if ((digitalRead(REED2)==HIGH)) 
  myservo2.write(0);
  }

Bleibt das Problem bestehen, d.h. Servo tut nix. Setze ich z.B. die Werte 160 und 40 funktioniert es tadellos. Also muss doch eigentlich schon im setup der Hund begraben liegen. Aber wo? :o

Gelöst! :slight_smile:

Kein Fehler im Code, sondern eine Eigenheit der Servos… Falls jemand anderes das Problem auch mal hat, hier der Grund und die Lösung:

Aus der Referenz zur Servo library ergibt sich, dass die Library von einem Standard-Servo ausgeht und von diesen Voraussetzungen den Ausschlag von 0 bis 180 Grad macht:
1000 Mikrosekunden ist Null, 1500 der Mittelpunkt und 2000 Vollausschlag.
https://www.arduino.cc/en/Reference/ServoWriteMicroseconds

Nun schert sich, so steht das auch schon in der Dokumentation, Otto Billigservo einen feuchten Kehricht um Standards.

Lösung:
Mit readMicroseconds() mal schauen, was denn Real aus den Servos an Mikrosekunden rauskommt und dementsprechend beim Attach angeben:
myservo.attach (pin, Mikrosekunden wenn nix passiert, Mikrosekunden für Vollausschlag)

Dann klappt’s auch mit dem Rückstellen auf den Nullpunkt. :smiley:
Meine beiden Servos waren übrigens, trotz gleicher Baureihe, etwas unterschiedlich und weitab von allen angegebenen Werten: Servo 1 bei 544 und 2400, Servo 2 bei 600 und 2150.