-         

Ergebnis 1 bis 10 von 10

Thema: Servos auch langsam drehen?

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.01.2010
    Ort
    Bielefeld
    Beiträge
    101

    Servos auch langsam drehen?

    Anzeige

    Hallo

    habe schon gesucht aber nichts gefunden.
    kann ich Servos auch langsam drehen lassen?
    momentan ist es so wenn ich dem impuls gebe rast er sehr schnell dahin.
    geht das auch das er diese position auch langsam anfährt?

    benutze die M32 hier mein code:
    Code:
    void servo1(int pos)
    {
    	PORTC |= IO_PC4;
    	sleep(pos);
    	PORTC &= ~IO_PC4;
    	mSleep(20);
    }

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    19.02.2006
    Beiträge
    982
    Ein Servo hat je nach Typ eine bestimmte Geschwindigkeit mit der er die vorgegebene Position anfaehrt.
    D.h. um langsamer an diese zu fahren darfst du diese in deinem Programm nicht sofort auf den Endwert setzen, sondern musst sie schrittweise dem Endwert annaehern...z.B. via Timer interrupt

    MfG, BastelWastel
    Nam et ipsa scientia potestas est..

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.01.2010
    Ort
    Bielefeld
    Beiträge
    101
    also wenn von 10 nach 15 will nicht direkt 15 sonder die zwischenwerte auch anfahren zb 11, 12, 13 ...
    aber das ist dann meist noch schlimmer immer dieses beschleunigen und abbremsen macht es auch nicht besser.
    sonst keine andere möglichkeit?

  4. #4
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    Hallo

    Den Drehweg in mehrere Teilschritte zu zerlegen funktioniert recht gut:


    http://www.youtube.com/watch?v=s1bOm9C7GAk

    Besser geht's leider nicht, weil der Kontroller keinerlei Positionsrückmeldung erhält. Es gibt zwar Servos die das können, die haben aber auch einen höheren Preis.

    Eine Bastellösung wäre ein zusätzliches externes Poti (z.b. aus einem Gamecontroller) mit einer kleinen Regelung im M32.

    Gruß

    mic

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    30.12.2009
    Ort
    Koblenz
    Alter
    38
    Beiträge
    78
    Als Beispiel:
    Code:
    uint16_t i ;
    	for(i = 0; i < (ANSCHLAG_OBEN-ANSCHLAG_UNTEN)*10; i++)
    	{
    		servo4_position = ANSCHLAG_UNTEN + i/10;
    		mSleep(10);
    		task_SERVO();
    	}
    Sieht zwar komisch aus, läuft bei mir aber schön langsam und geschmeidig
    Ich habe bereits bis Unendlich gezählt. Zweimal, und zurück

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.01.2010
    Ort
    Bielefeld
    Beiträge
    101
    kannst du mir mehr von deinem code dazu schicken weil so sagt mir das nicht ganz so viel.
    ich habe ja nur die zeilen s.o.
    was müsste ich daran umbauen?

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    19.02.2006
    Beiträge
    982
    Code kann ich dir keinen anbieten, da Bascom und recht komplex..
    Aber vom selbst basteln bleibt eh mehr hängen

    Du kannst dir für dein 'pos' zwei variablen machen, pos_soll und pos_ist z.B.
    Wenn du dem Servo eine neue Position gibst speicherst du diese in pos_soll.
    Deine Funktion mit der du den Servo ansteuerst rufst du aber mit pos_ist auf.

    Wenn du nun z.B. jede mS einen Timer Interrupt hast kannst du in dieser pos_soll und pos_ist vergleichen und solange diese ungleich sind pos_ist in jedem Interrupt annähern.
    Dies kannst du einfach immer um einen fixen Wert, dann hast du eine gleichmäsige Geschwindigkeit. Oder du berechnest den Wert damit du die Strecke in einer bestimmten Zeit zurück legst.
    Bei Bedarf kannst du dann auch ein 'Geschwindigkeits Profil' fahren, mit langsamen an und ablauf.
    Nam et ipsa scientia potestas est..

  8. #8
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    Ich hab's nicht getestet:

    Code:
    // "Weiche" Servoansteuerung mit sleep()                             mic 30.8.10
    
    #include "RP6ControlLib.h"
    
    char servo1(int pos)
    {
       static char pos_temp=0; // static = Werte zwischen den Aufrufen speichern
       static char stellzeit=0;// dito
    
       if (!pos_temp)    		// pos_temp beim ersten Aufruf initialisieren
       {
          pos_temp=pos;  		// Schnell zur gewünschten Position fahren
    		stellzeit=50;  		// innerhalb einer Sekunde
       }
    
    	PORTC |= IO_PC4;			// Impuls für aktuelle Position senden
       sleep(pos_temp);
       PORTC &= ~IO_PC4;    	// Impulspause
       sleep(200-pos_temp);     // Edit: mSleep() wird zu sleep()
    
       if(stellzeit) // solange Stellzeit aktiv werden gleichlange Impulse gesendet
       {
          stellzeit--;
    	}
    	else                 	// Position weiterschalten
    	{
    	   stellzeit=5;     		// Stellzeit für den nächsten Teilschritt 0,1 Sek.
    	   if(pos_temp<pos) pos_temp++; // Position noch zu klein
    	   	else if(pos_temp>pos) pos_temp--; // Position noch zu groß
    	   	   else return(0); 							// 0 bedeutet: "Ziel erreicht"
    	}
    	return(1); // 1 bedeutet: "Ziel noch nicht erreicht"
    }
    
    int main(void)
    {
       initRP6Control();
       DDRC  |= IO_PC4;
       PORTC &= ~IO_PC4;
       while(true)
       {
    		while(servo1(10)); // Solange auf Position 10 fahren bis 0 zurückkommt
          while(servo1(20)); // dito mit Position 20
       }
       return(0);
    }

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.01.2010
    Ort
    Bielefeld
    Beiträge
    101
    funktionieren tut es danke radbruch.
    langsam ist es aber ruckelig und das hilft mir auch nicht viel weiter da ich am besten eine langsame bewegung brauch.
    was gibts denn sonst für möglichkeiten?
    was für Servos oder so was?

  10. #10
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    Hallo

    Hier kannst du das etwas entruckeln:

    stellzeit=5;

    Die 5 sind die Anzahl der Impulse die gesendet werden bevor die Position weitergerechnet wird. Je kleiner der Wert, umso schneller wird die Position geändert. Wenn die Zeit zu klein ist erreicht das Servo aber eventuell nicht die Zielposition!

    Etwas schneller und flüssiger wird es, wenn du die Schrittweite der Einzelschritte erhöhst:

    pos_temp++; bzw. pos_temp--;

    Dann wird es aber etwas komplizierter, weil die Bewegung nur als beendet gemeldet wird, wenn pos_temp genau pos entspricht.

    Einfacher Ansatz wäre hier, nur bestimmte Positionen zu verwenden, bzw. wenn die Ziele immer ein vielfaches der Schrittweite sind. Hier ein Beispiel dazu mit 3er-Schritten:

    Code:
    // "Weiche" Servoansteuerung mit sleep()                             mic 2.9.10
    
    #include "RP6ControlLib.h"
    
    char servo1(int pos)
    {
       static char pos_temp=0; // static = Werte zwischen den Aufrufen speichern
       static char stellzeit=0;// dito
    
       if (!pos_temp)    		// pos_temp beim ersten Aufruf initialisieren
       {
          pos_temp=pos;  		// Schnell zur gewünschten Position fahren
    		stellzeit=50;  		// innerhalb einer Sekunde
       }
    
    	PORTC |= IO_PC4;			// Impuls für aktuelle Position senden
       sleep(pos_temp);
       PORTC &= ~IO_PC4;    	// Impulspause
       mSleep(200-pos_temp);
    
       if(stellzeit) // solange Stellzeit aktiv werden gleichlange Impulse gesendet
       {
          stellzeit--;
    	}
    	else                 	// Position weiterschalten
    	{
    	   stellzeit=5;     		// Stellzeit für den nächsten Teilschritt 0,1 Sek.
    	   if(pos_temp<pos) pos_temp+=3; // Position noch zu klein
    	   	else if(pos_temp>pos) pos_temp-=3; // Position noch zu groß
    	   	   else return(0);        // 0 bedeutet: "Ziel erreicht"
    	}
    	return(1); // 1 bedeutet: "Ziel noch nicht erreicht"
    }
    
    int main(void)
    {
       initRP6Control();
       DDRC  |= IO_PC4;
       PORTC &= ~IO_PC4;
       while(true)
       {
    		while(servo1(9)); // Solange auf Position 9 fahren bis 0 zurückkommt
          while(servo1(21)); // dito mit Position 21
       }
       return(0);
    }
    (ungetestet)

    8-20 oder 10-19 würde auch funktionieren. Von den paar Codezeilen darf man natürlich keine Wunder erwarten. Wirklich gut geht es nur mit höherer Auflösung der Positionen. Das macht man dann aber normalerweise nicht mehr blockierend.

    Wenn man sleep(position) durch eine Zählschleife ersetzt, kann man mehr unterschiedliche Positionen anfahren:

    Code:
    // "Weiche" Servoansteuerung mit Zählschleife                             mic 2.9.10
    
    #include "RP6ControlLib.h"
    
    char servo1(int pos)
    {
       static int pos_temp=0; // static = Werte zwischen den Aufrufen speichern
       static int stellzeit=0;// dito
       int pos_dummy, dummy;  // Hilfsvariable für die Zählschleife
    
       if (!pos_temp)    		// pos_temp beim ersten Aufruf initialisieren
       {
          pos_temp=pos;  		// Schnell zur gewünschten Position fahren
    		stellzeit=50;  		// innerhalb einer Sekunde
       }
    
    	PORTC |= IO_PC4;			// Impuls für aktuelle Position senden
       //sleep(pos_temp);
       pos_dummy=pos_temp;     // Schleifenzähler laden
       while(pos_dummy--) dummy^=pos_dummy; // Zeit verbummeln
       PORTC &= ~IO_PC4;    	// Impulspause
       mSleep(190);
    
       if(stellzeit) // solange Stellzeit aktiv werden gleichlange Impulse gesendet
       {
          stellzeit--;
    	}
    	else                 	// Position weiterschalten
    	{
    	   stellzeit=5;     		// Stellzeit für den nächsten Teilschritt 0,1 Sek.
    	   if(pos_temp<pos) pos_temp+=100; // Position noch zu klein
    	   	else if(pos_temp>pos) pos_temp-=100; // Position noch zu groß
    	   	   else return(0);        // 0 bedeutet: "Ziel erreicht"
    	}
    	return(1); // 1 bedeutet: "Ziel noch nicht erreicht"
    }
    
    int main(void)
    {
       initRP6Control();
       DDRC  |= IO_PC4;
       PORTC &= ~IO_PC4;
       while(true)
       {
    		while(servo1(2000)); // Solange auf Position 2000 fahren bis 0 zurückkommt
          while(servo1(4000)); // dito mit Position 4000
       }
       return(0);
    }
    (ebenfalls ungetestet)

    Ob 2000 und 4000 passen kann ich grad nicht sagen, das sind nur "gefühlte" Werte ;)

    Aber ehrlich, das wird irgendwann eine Sackgasse.

    Gruß

    mic

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •