Go Down

Topic: Servo Scheibenwischerbetrieb, Zeit aendern (Read 720 times) previous topic - next topic

Arudnoh

Jan 10, 2012, 09:43 pm Last Edit: Jan 10, 2012, 11:04 pm by Arudnoh Reason: 1
Hallo,

ich betreiebe einen Servo mit dem Arduino Board. Der Server macht die Wischebewegung, wie Sie im Beispielprogramm vorgegeben ist.
Ueber die Delayzeit aendere ich die "Wischgeschwindigkeit" / Servogeschwindigkeit.
Anbei das Beispielprogramm von Arduino.

Code: [Select]
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
               // a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position

void setup()
{
 myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}


void loop()
{
 for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees                   Sobald man in dieser For-Schleife sich befindet, wird eine Aenderung der Delayzeit nicht mehr ausgefuehrt.
 {                                  // in steps of 1 degree
   myservo.write(pos);              // tell servo to go to position in variable 'pos'
   delay(15);                       // waits 15ms for the servo to reach the position
 }
 for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
 {                                
   myservo.write(pos);              // tell servo to go to position in variable 'pos'
   delay(15);                       // waits 15ms for the servo to reach the position
 }
}


Allerdings dauert es genau 1 Zyklus, bis sich die Aenderung auswirkt. D.h. faehrt der Servo gerade nach unten und ich aendere die Delayzeit, so muss der Servo ganz nach fahren, damit sich die Delayzeit in der For-Schleife aendert. Somit brauche ich 1/2 Wischbewegung bis sich die Geschwindigkeit aendert.
Frage: Kann ich dies so aendern, dass der Servo sofort seine Geschwindigkeit aendert? zBsp ueber einen Interrupt? Was fuer Vorschlaege habt ihr?

MfG

Robert


Joghurt

Was Du beschreibst und der Code hier passen aber nicht wirklich zusammen, bitte zeig uns mal Deinen aktuellen Code. :)

Arudnoh

#2
Jan 10, 2012, 11:13 pm Last Edit: Jan 11, 2012, 02:10 am by Arudnoh Reason: 1
Hi,

Code: [Select]
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
               // a maximum of eight servo objects can be created

int pos = 0;    // variable to store the servo position
int m = .... ; //geradesteigung
int b = .... ;  //y-achsenabstand
int transmitterThrottle;

void setup()
{
 myservo.attach(9);  // attaches the servo on pin 9 to the servo object
 pinMode (9, INPUT);    //Input of Throttle
}

void checkTransmitter() //function for reading a signal of a RC-Receiver
{
transmitterThrottlee = ((pulseIn (9, HIGH, 100000))/10)-transmitterThrottleeLow; //read RC channel, wait max of 0.1 seconds for pulse
}


void loop()
{
 for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees                   Sobald man in dieser For-Schleife sich befindet, wird eine Aenderung der Delayzeit nicht mehr ausgefuehrt.
 {                                  // in steps of 1 degree
   myservo.write(pos);              // tell servo to go to position in variable 'pos'
   delay(transmitterThrottle*m+b);                       // Formel zum ausrechnen der Delayzeit, ändert sich transmitterThrottle während der Schleife, so wird die ganze Schleife mit dem ursprünglichen Wert ausgeführt. Gibt es hier eine Interruptmöglichkeit??
 }
 for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
 {                                
   myservo.write(pos);              // tell servo to go to position in variable 'pos'
   delay(transmitterThrottle*m+b);                       // Formel zum ausrechnen der Delayzeit, ändert sich transmitterThrottle während der Schleife, so wird die ganze Schleife mit dem ursprünglichen Wert ausgeführt. Gibt es hier eine Interruptmöglichkeit??
 }
}

erni-berni

Hallo,

das Programm erzeugt Fehler beim Compilieren, hätte dir eigentlich schon sagen müssen, wo der Fehler liegt.
1. Die Variable transmitterThrottlee ist nirgendwo definiert worden.
2. Die Variable müsste global definiert werden, damit sie auch im Hauptprogramm gelesen werden kann
3. Du müsstest das Sub void checkTransmitter() aufrufen, damit sich die Variable überhaupt ändert

Besser: definiere die Formel für transmitterThrottlee als Function und übergebe im Aufruf in der Schleife diesen Wert.

Gruß
Reinhard

Arudnoh

#4
Jan 11, 2012, 02:08 am Last Edit: Jan 11, 2012, 02:12 am by Arudnoh Reason: 1
Hallo,

natürlich wird die Variable transmitterThrottle global deklariert. Habe das nur kurz zu Verdeutlichung aufgeschrieben. Ich möchte diesen Programmteil so verwenden, habe das Programm dafür aber noch nicht geschrieben, da ich noch nicht wusste, wie ich mein Problem löse. Habe den Fehler trotzdem oben korrigiert.

Ich verstehe nicht, was mit Sub void checkTransmitter() gemeint ist. Für was steht das Sub? Leider konnte mir Google da auch nicht weiterhelfen.

Wie kann ich wenn sich die Variable transmitterThrottle ändert, die for schleife abbrechen und mit dem neuen wert wieder starten? Ich möchte nicht, dass die For schleife komplett durchlauft und dann die nächste losgeht, sondern die delayzeit soll sich automatisch ändern.
Wie kann man soetwas realisieren?? Ist es möglich, einen Interrupt auszulösen, wenn sich die Variable transmitterThrottle ändert?

MfG

mkl0815

Würde es nicht reichen, in jedem Schleifendurchlauf checkTransmitter() aufzurufen? Das war auch das was Reinhard wohl meinte mit
Quote
Du müsstest das Sub void checkTransmitter() aufrufen

Wobei Sub hier für Unterprogramm / Funktion / Subroutine steht.
Du brauchst auf jeden Fall zusätzlichen Code in der Schleife, der auf die "externe" Änderung reagiert.
Mario.

Arudnoh

#6
Feb 14, 2012, 04:32 pm Last Edit: Feb 14, 2012, 05:32 pm by Arudnoh Reason: 1
So, das Problem hab ich ein bisschen ruhen lassen, weil es nicht so wichtig war, aber nun wollt ich mich darum kuemmern.
Das Programm besteht aus 3 Teilen.
1. Die "Main" funktion mit der Deklaration der Variablen, Hauptschleife usw.
2. Dem Tab/ Der Funktion Checktransmitter, die den Wert vom RC Empfaenger einliest
3. Der Funktion Sweep

Hier ist der Original Code, der funktioniert. Aendere ich allerdings waehrend des Wischzyklus den Wert vom RC Empfaenger, so dauert es einen Wischzyklus bis der neue Wert umgesetzt wird.

Main Programm
Code: [Select]
//Imports servo library
#include <Servo.h>
//Initializes servos
Servo servo;
unsigned long transmitterThrottlee=0;     //these store the current transmitter positions/values
unsigned long transmitterThrottleeLow=0;  //these store the current transmitter positions/values

//Constants for actual frequency, minimum target angle, and maximum target angle
const int minAngle=45;
const int maxAngle=135;

void setup()
{
 servo.attach(11);
 pinMode (9, INPUT);    //Input of Throttle
 transmitterThrottleeLow = ((pulseIn (9, HIGH, 100000))/10);
}

void loop()
{
 checkTransmitter();              //check the data being received by the transmitter.
 sweepfunction();
}

CheckTransmitterFunction
Code: [Select]
void checkTransmitter()
{
 transmitterThrottlee = ((pulseIn (9, HIGH, 100000))/10)-transmitterThrottleeLow; //read RC channel, wait max of 0.1 seconds for pulse

 if (transmitterThrottlee > 42000)
   transmitterThrottlee =0;
}

Sweepfunction
Code: [Select]
void sweepfunction()
{
 if(transmitterThrottlee>=5&&transmitterThrottlee<95)
 {
   for(int pos = minAngle; pos < maxAngle; pos+=1)  // goes from 0 degrees to 180 degrees
   {
     servo.write(pos);
     delay((transmitterThrottlee*-.1143)+13.4286);
   }
   for(int pos = maxAngle; pos > minAngle; pos-=1)     // goes from 180 degrees to 0 degrees
   {                                
     servo.write(pos);
     delay((transmitterThrottlee*-.1143)+13.4286);
   }
 }
 else if(transmitterThrottlee>=95)
 {
   for(int pos = minAngle; pos < maxAngle; pos+=1)  // goes from 0 degrees to 180 degrees
   {
     servo.write(pos);
     delay(2);
   }
   for(int pos = maxAngle; pos > minAngle; pos-=1)     // goes from 180 degrees to 0 degrees
   {                                
     servo.write(pos);
     delay(2);
   }
 }
 else
 {
   servo.write(90);
 }
}


So nun habe ich dies Modifiziert in der Hoffnung, dass die Aenderung des RC Signales sofort in eine Geschwindigkeitsaenderung des Wischens umgesetzt wird.
Leider funktioniert anscheinend der Funktionsaufruf nicht.
Erneut MainFunction (alles identisch mit oben, bis auf dass die Function checkTransmitter nicht mehr aufgerufen wird. Dies passiert in der Funktion sweepfunction.Daher nur die main loop, den Rest spare ich ma aus.)
Code: [Select]
void loop()
{
 sweepfunction();
}

Checktransmitterfunction
Code: [Select]
identisch, siehe oben
Sweepfunction
Code: [Select]
void sweepfunction()
{
 int i=0;
 checkTransmitter();
 if(transmitterThrottlee>=5&&transmitterThrottlee<95)
 {
   for(int pos = minAngle; pos < maxAngle; pos+=1)  // goes from 0 degrees to 180 degrees
   {
     if (i=5)                          // habe dies aus dem folgenden Grund gemacht, dass alle 5 Grad Wischaenderung eine "Ueberpruefung"
     {                                  //erfolgt, ob das RC Signal noch das Selbe ist, und Falls nicht sollte mit dem neuen weitergearbeitet
       checkTransmitter();     //werden. Aber wo ist der Fehler? Wieso wird der neue Wert nicht in die Haupt For Schleife uebernommen
       i=0;
     }
     i++;
     servo.write(pos);
     delay((transmitterThrottlee*-.1143)+13.4286);
   }
   for(int pos = maxAngle; pos > minAngle; pos-=1)     // goes from 180 degrees to 0 degrees
   {    
     if (i=5)
     {
       checkTransmitter();
       i=0;
     }  
     i++;    
     servo.write(pos);
     delay((transmitterThrottlee*-.1143)+13.4286);
   }
 }

 else if(transmitterThrottlee>=95)
 {
   for(int pos = minAngle; pos < maxAngle; pos+=1)  // goes from 0 degrees to 180 degrees
   {        
     if (i=5)
     {
       checkTransmitter();  
       i=0;
     }  
     i++;
     servo.write(pos);        
     delay(2);
   }
   for(int pos = maxAngle; pos > minAngle; pos-=1)     // goes from 180 degrees to 0 degrees
   {          
     if (i=5)
     {
       checkTransmitter();  
       i=0;
     }    
     i++;                      
     servo.write(pos);
     delay(2);
   }
 }
 else
 {
   servo.write(90);
 }
}

Hoffe, mein anliegen wird nun klarer und verstaendlicher.

MfG

mkl0815

Du ahst nur das CheckTransmitter in die sweep-Funktion befördert. Allerdings ohne einen wirklichen Effekt, denn ob Du nun bei jedem Aufruf von loop() einmal checktransmitter aufrufs oder jedesmal innerhalb von sweepfunction(), aber immer noch nur einmal während des Durchlaufs von loop() macht keinen Unterschied.
Du musst wenn schon innerhalb der for-Schleife im sweepfunction() die CheckTransmitter() aufrufen.

Arudnoh

#8
Feb 14, 2012, 05:29 pm Last Edit: Feb 14, 2012, 05:33 pm by Arudnoh Reason: 1
Hi,
ja ich habe die CheckTransmitter in die Sweep Funktion befoerdet, damit beim allerersten Aufruft der SweepFunktion die Checktransmitter Funktion aufgerufen wird und ein definierter Wert eingelesen wird.
Allerdings wird in der for schleife die Checktransmitter function ebenfalls aufgerufen. Alle 5 Grad sollte der Wert ueberprueft werden. Leider kann ich die Stelle nicht farblich im Code markieren, dann wuerde man die stelle leichter sehen.

MfG

mkl0815

Ok, sorry. Das hatte ich tatsächlich übersehen. Versuch mal in der CheckTransmitter (oder dem Aufruf im if-Block in sweepfunction()) per Seria.-println() diverse Werte zu debuggen auszugeben. Damit siehst Du zum einen ob die Funktion an der richtigen Stelle aufgerufen wird und welche Werte danach gesetzt sind.

Arudnoh

Mh, das hat nicht wirklich was gebracht. Die Funktion wird zwar aufgerufen, aber der neue Wert wird nicht in die alte bereits laufende For Schleife übergeben.
Jemand Ideen?

Robert

mkl0815

Jetzt sehe ich den Fehler ....
Code: [Select]

      if (i=5)                          // habe dies aus dem folgenden Grund gemacht, dass alle 5 Grad Wischaenderung eine "Ueberpruefung"
      {                                  //erfolgt, ob das RC Signal noch das Selbe ist, und Falls nicht sollte mit dem neuen weitergearbeitet
        checkTransmitter();     //werden. Aber wo ist der Fehler? Wieso wird der neue Wert nicht in die Haupt For Schleife uebernommen
        i=0;
      }
      i++;


Mit i=5 setzt Du den Wert für "i" auf 5 aber vergleichst ihn nicht. Es muss "if (i == 5)" heissen.
Außerdem würde ich das erste checkTransmitter() in sweepfunction() mal auskommentieren, um zu sehen das die Funktionen innerhalb der Schleifen aufgerufen werden.

Arudnoh

Hi,

thx, jetzt funktioniert es. Ich mache oft so kleine dumme Fehler die ich dann nie finde und dann funktioniert es nicht. Ich hasse soetwas, danke dass du dir die Muehe gemacht hast meinen code genau anzuschauen. :)
Den ersten Checktransmitterfunctionaufruf kann ich nicht weglassen, da dieser eine Bedingung zurueckgibt, die zum Aufrufen der For-Schleife benoetigt wird. Aber in der For Schleife wird die Funktion nun aufgerufen und die Geschwindigkeit des Servos aendert sich sofort. Was mir allerdings aufgefallen ist, dass man die Zeit, die die Funktion Checktransmitter benoetigt (20ms) merkt. Nimmt man als Grenze den Wert 2 oder 3, so merkt man, dass man die maximalgeschwindigkeit des Servos niedriger ist, als bei dem Wert 10. Grund, die Funktion checktransmitter benoetigt 20ms und wenn man diese zu oft aufruft kann man den Servo nicht oft genug ansteuern und die Geschwindigkeit verringert sich.
Habe den gleichen Post nochmals im Englischsprachigen Forum stehen, wo mir ein anderer Ansatz geraten wurde, den ich nun auch verfolge. Ma schauen was da dabei rauskommt.

Gruesse
Robert

Go Up