- Akku Tests und Balkonkraftwerk Speicher         
Seite 2 von 2 ErsteErste 12
Ergebnis 11 bis 17 von 17

Thema: einfacher schnellerer Timer zur Ansteuerung von Servos

  1. #11
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.01.2008
    Ort
    Zürich
    Beiträge
    604
    Anzeige

    Powerstation Test
    Ach ja, ich wollte noch ne kleine Frage dazu stellen:

    Warum holst du dir für deine ganzen Servos dann nich nen Mega32 extra, das kostet dich mit Grundschaltung bei Reichel 5-7€ und du kannst mit diesem delayCycles(); (sofern es das da auch gibt) die Servos alle zusammen ansteuern, also halt eine Funktion schreiben, bei der das mit einer blockierenden Delayfunktion auch geht(etwas viel schreibarbeit, aber doch machbar)

    etwas komfortabler geht es natürlich mit nicht-blockierenden Delayfunktionen, danach Suche ich aber selber grade...

    Wenn ich nix finde oder mal lust zum proggen hab mach ich dir nen entwurf zu o.g. funktion für delayCycles();


    man muss dabei vermutlich aber die Werte von Servo1 bis ServoX per Parameter übergeben denke ich, das ist zwar auch wieder ein bisschen was zum schreiben, aber wenns nicht gleich 100 sind geht das schon

    Wenn ihr so eine nicht-blockierende Delayfunktion in der Standard AVR-Lib findet, dann bitte unbedingt mitteilen, damit geht das alles viel einfacher, man liest einfach Variablen Servo1 bis ServoX aus und stellt in eine while-Schleife lauter if-Bedingungen mit if(delayvar==Servo1){<Servoleitung auf low>}
    und am Anfang jedes mal die delayvar einlesen...


    Kurze Zusatzfrage: Kann man bestimmen, wie lange eine Schleife in ms braucht, 1x durchzulaufen?
    das wäre dann am einfachsten, wenn das geht

    man kalibriert einmal am Anfang im Programm nach der Zeit, die die Schleife braucht und dann in der endlosschleife gibt es eine Variable, die sich bei jedem Durchlauf um 1 erhöht

    Mit bestimmen meine ich in diesem Fall, ob das eine Rolle spielt, ob eine if-Bedingung mit Port-auf-low-setzen ausgeführt wird oder nur abgefragt und die Bedingung false ist

    Code:
    void task_Servos()
    {
    <Delay>  //hier genau 1 Sekunde Delay für unteren Anschlag
    task_0Grad();
    task_1Grad();
    task_2Grad();
    task_3Grad();
    task_4Grad();
    task_5Grad();
    task_6Grad();
    :
    :
    :
    :
    task_180Grad();
    }
    
    void task_0Grad()
    if(Servo1==0)
    {//Servoleitung auf Low
    }
    if(Servo2==0)
    {//Servoleitung auf Low
    }
    :
    :
    :
    if(ServoX==0)
    {//Servoleitung auf Low
    }
    
    }
    
    void task_1Grad()
    {
    <Delay>  //hier lange genug für ein weiteres Grad warten
    if(Servo1==1)
    {//Servoleitung auf Low
    }
    if(Servo2==1)
    {//Servoleitung auf Low
    }
    :
    :
    :
    if(ServoX==1)
    {//Servoleitung auf Low
    }
    
    }
    
    void task_2Grad()
    {
    <Delay>  //hier lange genug für ein weiteres Grad warten
    if(Servo1==2)
    {//Servoleitung auf Low
    }
    if(Servo2==2)
    {//Servoleitung auf Low
    }
    :
    :
    :
    if(ServoX==2)
    {//Servoleitung auf Low
    }
    
    }

    usw.


    Naja, da könnte man dann unabhängig von der Anzahl der Timer belibig viele Servos ansteuern, vorausgesetzt man hat genug Pins und aber auch Servos


    MfG Pr0gm4n

    EDIT: Wenn ich mich jetz nicht recht irre, dann muss man glaube ich aufpassen, dass man am Anfang alle task-Funktionen als Prototypen anführt, damit das keinen Fehler ausgibt (Prototyp der Funktion printf(Parameter) ist: printf(Parameter); das man einfach ganz oben unter dem "Include" aufruft)

  2. #12
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    37
    Beiträge
    150
    Hallo Alle zusammen...

    Ich denke ich habe hier eine Narrensichere die Lösung:

    Code:
    // Includes:
    
    #include "RP6ControlLib.h" 		// The RP6 Control Library. 
    								// Always needs to be included!
    #define		MIN					4		//Servo's pulse length limits 1 = 0,1ms
    #define		MAX					22
    #define		CLOCKWISE			45		//Rotation angles in Degree (actually the pulse leght = MIN*0.1ms + CLOCKWISE*0.001ms [in my case its one degree]) 
    #define		COUNTERCLOCKWISE	135	
    #define		SPEED				10		//set impulse increasement/decreasement Speed in ms (0 = fastest)
    #define		ADJUSTTIME			1000	//if the servo's movement is very fast then set at least the servo's time needed to rotate the required angle in ms else use it as a break between changing movedirection 
    #define		CYCLES				15		//set the individual ammount of Cycles made in 1us (15-16 @16MHz / 7-8 @8MHz) (Use this to adjust on a test angle)
    
    // Main function - The program starts here:
    
    int main(void)
    {
    	initRP6Control(); // Always call this first! The Processor will not work
    					  // correctly otherwise. 
    
    	initLCD(); // Initialize the LC-Display (LCD)
    			   // Always call this before using the LCD!
    
    	// Write some text messages to the UART - just like on RP6Base:
    	writeString_P("\n\n   _______________________\n");
    	writeString_P("   \\| RP6  ROBOT SYSTEM |/\n");
    	writeString_P("    \\_-_-_-_-_-_-_-_-_-_/\n\n");
    
    	// Set the four Status LEDs:
    	setLEDs(0b1111);
    	mSleep(500);
    	setLEDs(0b0000);
    	
    	// Play two sounds with the Piezo Beeper on the RP6Control:
    	sound(180,80,25);
    	sound(220,80,0);
    	
    	showScreenLCD("<<RP6  Control>>", "<<LC - DISPLAY>>");
    	mSleep(1000); 
    	showScreenLCD(" Servo  Control ", "  Test Program  ");
    	mSleep(1000);
    
    	
    	setStopwatch1(0);
    	startStopwatch1();
    	setStopwatch2(0);
    	startStopwatch2();
    	
    	DDRA |= (ADC3);
    	
    	uint8_t pulse = CLOCKWISE;
    	uint8_t countup = true;
    	
    	uint8_t counter = 0;
    	
    	while(true) 
    	{
    		if (getStopwatch2() >= 18)							// hier geschiet die eigentliche Pulserzeugung alle 20ms
    		{
    			PORTA |= ADC3;									// alle anzusteuernden Ports werden auf high gesetzt
    			sleep(MIN);
    			for (counter=0;counter<(MAX-MIN)*10;counter++)		// jeder schleifendurchlauf bedeutet 1° Winkeländerung
    			{
    				delayCycles(CYCLES);
    				if (pulse == counter)							// sobald der gewünschte Winkel erreicht wird, Wird der entsprechende Port auf low gesetzt
    					PORTA &= ~ADC3;
    			}
    			setStopwatch2(0);
    		}
    		
    		if(getStopwatch1() >= (ADJUSTTIME + SPEED))		// nach Ablauf der Zeit wird die nächste Position angefahren
    		{
    			setStopwatch1(ADJUSTTIME);
    			if (pulse>=COUNTERCLOCKWISE)	// wechsel der drehrichtung
    			{
    				countup = false;
    				setStopwatch1(0);
    			}
    			else if (pulse<=CLOCKWISE)
    			{
    				countup = true;
    				setStopwatch1(0);
    			}
    
    			if (countup == true)			// änderung der Richtung
    				pulse++;
    			else
    				pulse--;
    		}
    	}
    	return 0;
    }
    Das meiste ist der standard Quellcode
    In der Endlosschleife sind zwei If()-Bedingungen, die eine erzeugt das Servo-Signal und die andere erzeugt eine Pendelbewegung. Eigentlich war das nicht Ziel dieses Threads, aber sonst ist das so langweilig... ein still stehender Servo... =D>
    Die Pulsvariable könnte man auch durch beliebige eigene Funktionen generieren lassen.
    Da mein uC bei 16MHz maximal eine genauigkeit von 0,06us schafft (= 1 Takt), finde ich dass mein bis auf 1us genaues Signal keine schlechte alternative zu den aus meiner Sicht eher komplizierten timern ist.
    Der Servo hat eine Auflösung von 180 Stellungen, (360 sind auch leicht möglich, aber da der Servo ehh im 20ms takt ruckelt, fand ich es nicht deutlich flüssiger mit 360er Auflösung).
    Ich konnte das prgramm jetzt noch nicht mit mehreren Servos testen, da ich z.Zt nur einen Servo am M32 angeschlossen habe.(Ich muss erst noch die Servokabel auseinanderpulen, um sie anzuschließen)
    Prinzipiell, sollte man jedoch beliebig viele Servos gleichzeitig parallel ansteuern können. Vielleicht muss man dann jedoch wegen des steigenden rechenaufwandes die CYCLES der "delayCycles()" reduzeren.

    mfg WarChild
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  3. #13
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.01.2008
    Ort
    Zürich
    Beiträge
    604
    Ok, habs jetzt mal gelesen und ist so weit ok!!

    Wie du schon sagtest haste es ja auch schon getestet...


    Mal die Frage: isses nich mit meiner Funktion dann einfacher, mehrere Servos anzusteuern?

    Ich überlege grad, ob man denn bei mir mit einbeziehen muss, dass er recht viel Code zu durchlaufen hat und somit die Rechenzeit die Servostellung beeinträchtigt

    Ich hoffe jetz mal nicht...


    Kann mir jemand sagen, wo ich mir die ganzen Befehle die ich bei anderen AVRs (halt nicht am RP6) habe, damit ich da mal nach einer Taktzähl-Funkt. gucken kann, die nicht blockiert, denn damit wär das ganze echt einfacher

    reicht es dann das mit Interrupts zu machen oder soll man das dann lieber mit if-Bedingungen abfragen?



    MfG Pr0gm4n


    PS: ansonsten werd ich jetz dann meine Version mal ausprogrammieren, da fehlte ja noch einiges
    Ich denke die ist dann einfacher zu verstehen und man muss nur die Funktion aufrufen, die Servostellungen in Grad angeben und den Rest erledigt der Code

    Wenn man jetzt nicht immer 20 Servos braucht könnte man auch genausogut eine zusätzliche Funktion schreiben, in der das alles nur mit 5 Servos gemacht ist, nur um dem Anwender Schreibarbeit zu ersparen

    Edit: Ich würde gerne am Anfang kalibrieren, sodass ich dann einmal feststelle, wie lange die delayCycles(); bei dem Wert 1 braucht und danach dann mein Programm richten, denn es soll möglichst auf alle AVRs protabel sein

    Kann ich dafür möglicherweise die eingebauten Timer hernehmen oder zeigen die mir solche kleinen Werte nicht an?

    Wenn nicht muss ich es halt mit 1 Mio. delayCycles machen, dann gehts aber, oder?

  4. #14
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.01.2008
    Ort
    Zürich
    Beiträge
    604
    Hallo!!

    Hier nun mein überarbeiteter Vorschlag-Code für eine Ansteuerung von 5 Servos:

    Code:
    #include <avr/io.h> /* Servoansteuerung AVR --- 8.4.2008 Pr0gm4n*/
    
    //Defines:
    
    
    #define SERVOMAX 180 //Anzahl der Schritte, die möglich sein sollen.
    
    
    //alle defines hier kann man irgendwo in seinem Programm machen,
    //doch sie sind nötig um Servos mit der Funktion task_Servos anzusteuern
    
    //z.B. #define SERVOREGISTER DDRA
    //#define SERVOREGISTER1 
    //#define SERVOREGISTER2 
    //#define SERVOREGISTER3 
    //#define SERVOREGISTER4 
    //#define SERVOREGISTER5 
    //z.B. #define SERVOPORT PORTA
    //#define SERVOPORT1 
    //#define SERVOPORT2 
    //#define SERVOPORT3 
    //#define SERVOPORT4 
    //#define SERVOPORT5 
    //z.B. #define SERVOBIT 0
    //#define SERVOBIT1 
    //#define SERVOBIT2 
    //#define SERVOBIT3 
    //#define SERVOBIT4 
    //#define SERVOBIT5 
    
    
    
    
    //Prototypen:
    void task_Servos(uint Servo1, uint Servo2, uint Servo3, uint Servo4, uint Servo5);
    void task_Grad(uint Servo1, uint Servo2, uint Servo3, uint Servo4, uint Servo5, uint Grad);
    
    
    /*********************************************************************************************/
    /******************  Prototypen ende, jetzt: Funktionen  *************************************/
    /*********************************************************************************************/
    
    
    //Funktionen:
    
    
    void task_Servos(uint Servo1, uint Servo2, uint Servo3, uint Servo4, uint Servo5) 
    {
     
    
    
    SERVOREGISTER |=(1<<SERVOBIT1);
    SERVOREGISTER |=(1<<SERVOBIT2);
    SERVOREGISTER |=(1<<SERVOBIT3);
    SERVOREGISTER |=(1<<SERVOBIT4);
    SERVOREGISTER |=(1<<SERVOBIT5);
    SERVOPORT1   |= (1<<SERVOBIT1);
    SERVOPORT2   |= (1<<SERVOBIT2);
    SERVOPORT3   |= (1<<SERVOBIT3);
    SERVOPORT4   |= (1<<SERVOBIT4);
    SERVOPORT5   |= (1<<SERVOBIT5);
    <Delay>  //hier genau 1 ms Sekunde Delay für ersten Anschlag 
    
    for(int i=0;i<(SERVOMAX+1);i++)
    {
    task_Grad(uint Servo1, uint Servo2, uint Servo3, uint Servo4, uint Servo5, i);
    <Delay>  //hier genau 1/180 ms Sekunde Delay  und auch zwischen allen anderen
             //auch sehr leicht auf mehr als 180 Schritte ausweitbar durch höhere Zahlen für Grad und und Servo1-5
             
    }//for-Schleife schliessen (nur zur besseren Übersicht)
    
    } 
    
    
    void task_Grad(uint Servo1, uint Servo2, uint Servo3, uint Servo4, uint Servo5, uint Grad)
    {
    if(Grad >(SERVOMAX-1))                  Grad   = SERVOMAX;  //Grad und die Servowerte auf das Maximum beschränken
    if(Grad <1)                             Grad=1;             //Wenn man dies nicht macht kann es passieren, dass es
    if(Servo1 >(SERVOMAX-1))                Servo1 = SERVOMAX;  //keinen übereinstimmenden Wert für ServoX und Grad gibt
    if(Servo1 <1)                           Servo1 = 1;
    if(Servo2 >(SERVOMAX-1))                Servo2 = SERVOMAX;
    if(Servo2 <1)                           Servo2 = 1;
    if(Servo3 >(SERVOMAX-1))                Servo3 = SERVOMAX;
    if(Servo3 <1)                           Servo3 = 1;
    if(Servo4 >(SERVOMAX-1))                Servo4 = 180;
    if(Servo4 <1)                           Servo4 = 1;
    if(Servo5 >(SERVOMAX-1))                Servo5 = SERVOMAX;
    if(Servo5 <1)                           Servo5 = 1;
    if(Servo1==Grad)SERVOPORT1   &= ~(1<<SERVOBIT1); //Servo 1 Signal beenden
    if(Servo2==Grad)SERVOPORT2   &= ~(1<<SERVOBIT2); //Servo 2 Signal beenden
    if(Servo3==Grad)SERVOPORT3   &= ~(1<<SERVOBIT3); //Servo 3 Signal beenden
    if(Servo4==Grad)SERVOPORT4   &= ~(1<<SERVOBIT4); //Servo 4 Signal beenden
    if(Servo5==Grad)SERVOPORT5   &= ~(1<<SERVOBIT5); //Servo 5 Signal beenden
    }


    Im Moment versuche ich, der Funktion task_Servos noch einen Parameter servos_count hinzuzufügen. Dabei soll festgelegt werden, wie viele Servos angesteuert werden sollen.
    bisherige Ideen:

    Code:
    if(servos_count=1) task_1_Servo(Parameter);
    if((servos_count>1)&&(servos_count<6)) task_5_Servos(Parameter);
    if((servos_count>5)&&(servos_count<11)) task_10_Servos(Parameter);
    if(servos_count>10)task_max_Servos(Parameter);

    Ich bin mir nicht sicher, ob es stört, dass man für Servo7-10 keinen Wert hat, andernfalls muss man sie als 0 definieren und dann mit den richtigen Werten überschreiben


    eine weitere Möglichkeit wäre es, die Servo-Stellungen in einem Array zu übergeben und dann die Elemente von 0-(servos_count-1) abzufragen

    diese Möglichkeit halte ich für sinnvoller


    MfG Pr0gm4n

    EDIT: An meinen Code muss noch ein Delay von 18ms angefügt werden, da man Servos nur alle 20 ms neu mit Signalen versorgt und maximale 2ms Signal nötig sind, um einen Servo auf Anschlag zu stellen

  5. #15
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.01.2008
    Ort
    Zürich
    Beiträge
    604
    Hi nochmal,

    ich hab da mal eine Frage: Ich möchte die Servofunktion auch auf alle anderen ATMegas portabel haben und brauche nun eine Delayfunktion, die in etwa einfach den Takt des µCs hat und ich dann kalibrieren kann

    Es reicht auch ein Takt von 10us, aber am liebsten würde ich einfach gerne einen Link zur AVR/io.h, die man ja überall includen kann

    wenn ich die Servofunktion dann fertig habe, denke ich sie wird auch auf dem RP6 funktionieren, oder muss man dann noch extra die AVR/io.h includen?

    Ich werde mir auf jeden Fall eine Art Servolibrary schreiben, die man bei include reinschreibt, im makefile angibt

    danach einfach nur noch die Funktion aufrufen zu müssen wäre doch super, oder?


    MfG Pr0gm4n

  6. #16
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    05.09.2007
    Ort
    Preetz
    Alter
    37
    Beiträge
    150
    Ich dachte mir das so ähnlich... ich wollte einfach ne funktion in der Control library hinzufügen... ist ja nicht soo viel an Quellcode, dass ich dafür eine ganze Lib anlegen würde..
    Das mit der Portabilität ist so eine sache, letztendlich muss man die funktion ehh auf die individuelle Anzahl von Servos aufbauen und die sind außerdem bei jedem an anderen Ports also soll meine lösung auch nur bei mir funzen.

    ich habe jetzt die ersten erfolgreichen versuche mit meiner auf drei sevos erweiteren version des von mir oben geposteten codes ausgeführt.

    mfg WarChild

    PS: eigentlich war meine frage bereits mit der delayCycles(); funktion geklärt.
    (c) Rechtschreibfehler sind rechtmäßiges Eigentum des Autors (c)

  7. #17
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.01.2008
    Ort
    Zürich
    Beiträge
    604
    Hi,

    das mit den Servos an verschiedenen Pins hab ich ja gelöst, indem man die Angaben (oben in meinem Code) irgendwo im Programm definiert und somit dann die eigenen Pins reinschreiben kann. das mit der individuellen Zahl an Servos kann man auch umgehen, du kannst ja bei ner Funktion mit 20 Servos dann das aufrufen:

    task_Servos(90, 90, 90, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 180); //das letzte ist die Anzahl der zählschritte


    damit musst du nur die Register der Servos 4-20 auf unbenutzte Pins legen



    MfG Pr0gm4n

    PS: ich werde als Zusatz noch eine Funktion eibauen, bei der man als Parameter die Stellung des Servos und den Pin angiebt und dann kann man auch einzelne Servos ändern

    Was ich aber in dem Code noch unbedingt beachten muss, ist dass man ja alle 20 ms senden muss und ich so nur die Servos einmal ausrichten würde. Ich werde das aber vermutlich so lassen, denn der µC hat eigentlich nix anderes zu tun und das kann ich dann auch mit in meiner while(1) - Schleife berücksichtigen

Seite 2 von 2 ErsteErste 12

Berechtigungen

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

LiFePO4 Speicher Test