PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Servo Include-Datei zum Steuern von x Servos an y Ports



durchgebrannt
13.03.2012, 14:27
Hallo,
ich habe hier eine Include-Datei für das universelle steuern von Servos geschrieben. Die Lib ermöglicht das Steuern von einer beliebigen Anzahl von Servos an verschiedenen Ports. Jedoch sinkt die Geschwindigkeit der Positionsänderung mit steigender Servoanzah. An Resourcen verbraucht die Lib neben 16 Bit pro Servo im Ram und 8 im Heap einen 8-Bit Timer im CTC-Mode. Die Die verwendung der Lib, bzw die initalisierung sieht wie folgt aus am Beispiel eines ATmega32 mit Timer0


#define VEKTOR TIMER0_COMP_vect // Der Interruptvektor für die ISR von Timer0 im CTC-Modus
#define VERGLEICHSREGISTER OCR0 // Das Register, in das der Wert geschrieben wird, wann eine ISR aus gelöst werden soll
#define NUMBER_OF_SERVOS 3 // Die Anzahl der verwendeten Servos.


//In main() oder in einer anderen Funktion muss dann das Array Servolist zuerst initalisiert werden und dann mit Werten bestückt werden.
//Die Initalisierung erfolgt über die Funktion init_ServoArray() danach werden die Belegungen der einzelnen Servos wie folgt eingetragen:
servolist [0].pin = PORTxy ; //Servo1, der an PORTx an Pin y angeschlossen ist
servolist [0].port =& PORTx; // Da für den Zugriff auf die PORTs Zeiger verwendet werden, muss hier umbedingt der Adressoperator verwendet werden
//In die nächte Variable wird der Drehwinkel geschrieben, dabei bedeutet der Wert 0 Mittelposition, -127 linker Anschlag und 127 rechter Anschlag. Die Variable ist //vom Typ int8_t
servolist[0].angle = 0;

Die Lib geht davon aus, das die maximale Pulslänge 2ms beträgt, die minimale 1ms. Aus diesem Grund muss der verwendete Timer so eingestellt sein, das der längst mögliche Durchlauf möglichst genau 1ms beträgt.


#include <avr/io.h>
#include <avr/interrupt.h>
/*
Wichtig für die korrekte Funktionsweise der Lib ist das richte Einstellen des Taktes vom 8-Bit Timer auf 1KHz Wichtig dabei CTC-Mode
logischerweise müssen die entsprechenden Ports in das Array Servolist eingetragen werden
Dazu muss in der Funktion init_ServoArray() nach initialisierung der Servos, dieses mit Pins,Port und evtl Winkeln gefüllt werden
Diese drei Konstanten müssen vor dem Einbinden der include definiert werden:
#define VEKTOR -> Der passenden Interruptvektor aus dem Datenblatt. BSP TIMER0_COMP_vect
#define NUMBER_OF_SERVOS
#define VERGLEICHSREGISTER BSP: ORC0
*/
typedef struct
{

uint8_t PIN;
volatile uint8_t *PORT;
int8_t angle;
} servo;

volatile struct
{
unsigned modus :1 ;
unsigned index: 7;
} Servo;

volatile servo servolist[NUMBER_OF_SERVOS];
ISR (VEKTOR)
{

VERGLEICHSREGISTER = 255;

if (Servo.modus)
{
*(servolist[Servo.index].PORT) &= ~(1 << servolist[Servo.index].PIN ); //Alten Servo löschen

if (++Servo.index >=NUMBER_OF_SERVOS) //Wenn inkrementierter Index größer als Servoanzahl, reset
{
Servo.index= 0;
}

*(servolist[Servo.index].PORT) |= (1 << servolist[Servo.index].PIN ); //Neuen Servo setzen und...
VERGLEICHSREGISTER = 255; //...1ms warten
Servo.modus =0; //Servo als aus makieren
}
else
{

VERGLEICHSREGISTER = 127+servolist[Servo.index].angle; //Drehwinkel, "Restzeit" warten , Wertebereich [-127...127]
Servo.modus = 1; //Servo als ein makieren
}

}
void init_ServoArray() //lädt in alle Stellen des Arrays eine Null
{
servo empty;
empty.PIN = 0;
empty.PORT = 0;
empty.angle = 0;
for(uint8_t i = 0; i >= NUMBER_OF_SERVOS;i++)
{
servolist[i] = empty;
}





}

Getestet worden ist die Lib bis jetzt nur mit den Conrad Topline Servos mit einem ATmega32. Es würde mich freuen, wenn ihr die Lib auch an anderen Servos testen würdet.
Gruß Jannis

radbruch
13.03.2012, 15:53
Hübsch. Viele Wege führen zum Servoimpuls.


Wichtig ... ist das richtige Einstellen des Taktes vom 8-Bit Timer auf 1KHzDa wirds dann oft schwierig. Wo wird denn die Datenrichtung der Pins gesetzt?

VERGLEICHSREGISTER = 255; //...1ms warten

???


Gruß

mic

durchgebrannt
13.03.2012, 16:13
Die Datenrichtung muss manuel gesetzt werden.
Dazu ist das Einstellen auf ein KHz garnicht so schwierig.
Bei 2 MHz braucht man einen Teiler von 8 bei 4 MHz von 16 usw. Dabei ist der Puls aber immer etwas länger, jedoch noch im Toleranzbreich. Wenn absolute Präzision gefordert ist, sollte man den Timer extern triggern

VERGLEICHSREGISTER = 255; //...1ms warten
Wenn der Timer korrekt eingestellt ist, dann dauert ein Durchlauf von 0-255 1ms. Der Puls wird in einer zweigeteielten ISR erzeugt um eine hohe Genauigkeit zu erreichen. Im ersten Teil wird ein 1ms "gewartet", der Pin wird auf High gesetzt. Im zweiten Teil der ISR wird der Drehwinkel bestimmt, da dort die Zeitspanne "gewartet" wird, durch die der geforderte Drehwinkel erreicht wird.
Gruß Jannis