Hey Leute,
im Rahmen eines Schulprojekts übertragen wir das Bewegungskonzept von
Sechsfüßer auf ein technisches Modell. Wahrscheinlich sind andere
ähnliche Projekte als "Hexapod" unter euch bekannt ;)
Die Entwicklungsumgebung: WinAVR, PonyProg.
Die Hardware: Pollin Evaluationsboard, ATMega32.
Benutzt werden 18 Servos, die einzeln ansteuerbar sind. D.H es werden 18
PWM's benötigt. Die Ansteuerung der Servos und die erstellung der Soft
PWM's klappt soweit.
PROBLEM: Da außer den PWM's auch noch die bewegungsmodis über den µC
gesteuert werden soll, suchen wir nun verzweifelt nach einer
Möglichkeit, die PWM's praktisch "parallel" neben dem Hauptprogramm
ablaufen zu lassen. Mir ist durchaus bewusst, dass der µC natürlich
keine befehle wirklich parallel ausführen kann, Ich hoffe unser problem
ist trotzdem deutlich geworden und ihr wisst, worauf ich hinaus will.
Es gab erste ansätze mit der DWORD WINAPI Thread Funktion. Jedoch
funktionierte diese nur unter windows und ließ sich unter WinAVR (auch
nach dem kopieren der entsprechenden libraries) nicht compillieren. Ist
es möglich diese Funktion auf einem µC auszuführen??
Auch andere Lösungsvorschläge sind herzlich wilkommen !
Danke schonmal im Vorraus!
Wenn aus dem PWM-Signal eh eine Gleichspannung erzeut wird könnte man
vielleicht auch Digital/Analogwandler mit SPI oder anderen
Schnittstellen verwenden.
Also Bausteine bis 16 Kanälen habe ich schon gesehen. Vielleicht gibt es
noch größere oder man nimmt 2.
ado schrieb:> Wenn aus dem PWM-Signal eh eine Gleichspannung erzeut wird könnte man> vielleicht auch Digital/Analogwandler mit SPI oder anderen> Schnittstellen verwenden.
Es geht nicht um wirkliches PWM, Marv will Servos ansteuern, er nennt
das nur PWM.
MfG Klaus
Gibt es nicht auch Portexpander (glaub für LEDs) die jeden Kanal einzeln
mit einer PWM ansteuern können?
Soweit ich weis ist bei denen die Frequenz (hier dann 50Hz) und das
Tastverhältnis für jeden Kanal einzeln einstellbar.
Bei 10 Bit wär dass immerhin eine Auflösung von 20ms/1024= 19,5us.
Müssten dann so um die 50-60 Positionen sein die man einstellen kann.
Vorteil: Einfach über SPI/I2C anzusteuern und der uC hatt außer die
neuen Werte über SPI zu senden nichts zu tun.
Grüße
N.Müller
Vielleicht hift Dir dieses Programmbeispiel, viele PWM-Kanäle zu
realisieren. Falls nicht alle 64 Kanäle gebraucht werden, bleibt mehr
Zeit für die Verarbeitung anderer Programmteile.
http://www.mino-elektronik.de/AVR_PWM_64/AVR_PWM_64.htm
Marv schrieb:> Danke für die schnellen Antworten ! Der Multitasking Thread hört sich> schonmal verdammt gut an ;9
Multitasking halt ich für übertrieben, schau dir mal den Link zur
Ansteuerung an. Mit einem Timer lassen sich bequem 8 Servos ansteuern.
Mit z.B. 3 Timern lassen sich dann alle 18 (eigentlich schon 24) Servos
ansteuern.
Der Trick dabei ist, dass die 8 benötigten Pulse über die Periodendauer
verteilt sind, um die Prozessorzeit zu minimieren.
Floh schrieb:> Multitasking halt ich für übertrieben, schau dir mal den Link zur> Ansteuerung an. Mit einem Timer lassen sich bequem 8 Servos ansteuern.> Mit z.B. 3 Timern lassen sich dann alle 18 (eigentlich schon 24) Servos> ansteuern.
Es reicht ein einzigster Timer und eine intelligente Programmierung um
die benötigten 18 Pulsweiten zu erzeugen, welche auch stabil sein
sollten.
Eine Servo Ansteuerung lässt sich nicht ohne weiteres mit einer normalen
PWM Steuerung verleichen.
Man benötigt eine minimale Pulslänge von ca. 1 ms um den Servo in seiner
0
Referenzposition zu halten.
Die nächste ms (zur Erweiterung der 1.) muss in Stufen geteilt werden um
den
Servo um ca. 90° zu bewegen.
Dir Wiederholung dieses Vorganges beträgt 20ms.
Mit einer entsprechend intelligenten Ansteuerung (Software) kommt ein
relativ geringer Softwareaufwand zustande.
Dirk schrieb:> Es reicht ein einzigster Timer und eine intelligente Programmierung um> die benötigten 18 Pulsweiten zu erzeugen, welche auch stabil sein> sollten.
Geile Idee. Also in etwa so (für gedachte 8ms Periodendauer ,da mir hier
die Breite fehlt :-)
0 1 2 3 4 5 6 7 8
Zeit | | | | | | | | | | (je 1 ms)
S1 PPPPPP--------------------------PPPPPPP--
S2 ----PPPPP------------------------------PP
S3 --------PPPPPPP--------------------------
S4 ------------PPPPPPP----------------------
...
Dann skaliert man z.B. einen Timeroverflow auf 1ms.
Zusätzlich hat man nen Output Compare-Interrupt.
Bei Timeroverflow wird immer Serv0(n) angeschaltet und gleichzeitig der
Output-Compare-Wert von Servo(n-1) genommen.
Bei Output-Compare-Interrupt wird dann Servo(n-1) ausgeschaltet.
Ja so kriegt man elegant 18 Servos in eine 20ms Periode.
:-)
Floh schrieb:> Der Trick dabei ist, dass die 8 benötigten Pulse über die Periodendauer> verteilt sind, um die Prozessorzeit zu minimieren.
Üblicherweise wird das auch als Zeitmultiplex bezeichnet, d.h. innerhalb
der Periodendauer gibt es für jeden Servo ein 2ms Zeitfenster, in dem
sein Puls erzeugt wird
Dirk schrieb:> Dir Wiederholung dieses Vorganges beträgt 20ms.
Als Wiederholung (Periode) werden zwar oft 20ms verwendet, aber den
Servos ist der genaue Wert ziemlich wurscht. Irgendwas zwischen 10 ms
und mindestens 100 ms funktioniert eigentilich immer. Einziger Effekt
einer langen Periodendauer ist, dass die Servos etwas langsamer
umsteuern.
Es kommt auf einen Versuch drauf an, ob es für den Hexapod ok ist, alle
18 Servopulse auf eine als Zeitmultiplex erzeugte Serie zu packen. Die
Chancen sind gut.
Matthias schrieb:> Als Wiederholung (Periode) werden zwar oft 20ms verwendet, aber den> Servos ist der genaue Wert ziemlich wurscht. Irgendwas zwischen 10 ms> und mindestens 100 ms funktioniert eigentilich immer. Einziger Effekt> einer langen Periodendauer ist, dass die Servos etwas langsamer> umsteuern.
Genau in der Reaktionsgeschwindigkeit liegt denke ich hier die
Anforderung.
100ms wären da wohl eindeutig zu langsam.
Nicht zu vergessen ist, dass preiswerte Servos per PWM offset und
aktiver Pulslänge evtl. kalibriert werden müssen, um zu verhinder, dass
der HEXAPOD
in Schräglage durch die Welt läuft.
Dirk schrieb:> Genau in der Reaktionsgeschwindigkeit liegt denke ich hier die> Anforderung.> 100ms wären da wohl eindeutig zu langsam.
Die 100ms sind ein Wert, bei dem sich bei mir noch kein Servo beschwert
hat. Mit 18 Servos á 2 ms wäre man bei 36 ms mit der Option, auch noch
Pausen aus dem Signal rauszukürzen, falls nicht gerade alle in der 2
ms-Stellung stehen.
Reaktionsgeschindigkeit ist nicht das Problem. Und fast 28
Positionskommandos pro Sekunde an jeden Servo sollte wohl noch kein
Engpaß sein.
Dirk schrieb:> Nicht zu vergessen ist, dass preiswerte Servos per PWM offset und> aktiver Pulslänge evtl. kalibriert werden müssen, um zu verhinder, dass> der HEXAPOD in Schräglage durch die Welt läuft.
Ja und? Warum soll man das nicht wie gewohnt machen können? Die Signale
werden einzig und alleine zeitlich verschachtelt, wie beim Summensignal
einer Funkfernsteuerung.
Das mit der periodendauer seh ich wie von euch beschrieben nicht so
eng. test haben ergeben dass die servos noch bei einer pause von 5-50ms
zwischen den pulsen sauber fahren. Auch unterschiedliche pausen machen
nichts aus. Zum test haben wir mal alle servos nacheinander angesteuert,
so ergaben sich pausenzeiten von min.: 17*0,8 = 13,6ms und max.: 17*2,2
= 37,4ms. Die Servos liefen problemlos. Außer der herangehensweise vom
multitasking sind mir die funktionsprinzipe der anderen beschriebenen
herangehensweisen noch unklar. Zum testen wurden bisher nur delays
eingesetzt. Wir sind aber gerade daran alles mit Timern umzusetzen.
mfG Marv
> die PWM's praktisch "parallel" neben dem Hauptprogramm> ablaufen zu lassen.
Ach was.
Das sind Servos.
Deren Ansteuersignal nennt man übrigens PCM pulse code modulation.
Es werden nicht alle Impulse gleichzeitig gesendet,
weil man nicht will, daß alle Servos gleichzeitig Strom ziehen,
sondern nacheinander.
Das geht problemlos, weil ein Servo auch erst in ca. 25msec seinen
nächsten Impuls sehen will.
Servo1 --XXX-----------------XXX----
Servo2 -----XX------------------XX--
Servo3 -------XXXX----------------XX...
Servo4 -----------XXX---------------
Wenn man das in Form einer Interrupt-Routine machen will, kann diese
einfach jedesmal den "nächsten" Zeitwert setzen. Also pseudocodemässig
in der Art:
int servoduration[19];
interrupt timer(void)
{
static int servo=0;
PORT[servo]=0; // letzten Puls zurücknehmen
TIMER=servoduration[servo]; // neue Zeit bis zum nächsten Interrupt
setzen
servo++;
if(servo>=19) servo=0;
PORT[servo]=1; // Puls auslösen
}
Es spielt dabei keine so grosse Rolle, daß die Pausenzeiten von den
Pulslängen der anderen Servos abhängen.
Danke erstmal für die vielen Antworten!
Es sind allerdings neue Probleme aufgetaucht. Aus uns unerklärlichen
gründen ist es nicht möglich Timer0 im CTC Modus zu betreiben. Normaler
Timerbetrieb funktioniert soweit. Nachdem unser programm nicht
kompillierbar war, haben wir alle fremdfaktoren entfernt, den fehler
allerding nicht gefunden.
Also: dieser fertige Code versucht zu kompillieren:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
intmain(void)
5
{
6
// Timer 0 konfigurieren
7
TCCR0A=(1<<WGM01);// CTC Modus
8
TCCR0B|=(1<<CS01);// Prescaler 8
9
// ((1000000/8)/1000) = 125
10
OCR0A=125-1;
11
12
// Compare Interrupt erlauben
13
TIMSK|=(1<<OCIE0A);
14
15
// Global Interrupts aktivieren
16
sei();
17
18
while(1)
19
{
20
/*Hier kann die aktuelle Zeit
21
ausgeben werden*/
22
}
23
}
24
25
26
27
ISR(TIMER0_COMPA_vect)
28
{
29
30
}
ABER: Wir bekommen nur ein Fehlercode. Hat jemand einen Tipp für uns,
was wir übersehen haben ?
>Deren Ansteuersignal nennt man übrigens PCM pulse code modulation.
nein. PPM PCM ist nur bei moderneren funken zwischen sender und
empfänger.
Wenn euch irgenwann bei eurem hexapod die Portpins zuneige gehen, könnt
ihr mit einem 4017 mit 2 portpins 8 servos ansteuern. alles was der
braucht ist das summensignal und sein sync signal. So in der ausführung
millionenfach in modellbauempfängern bewährt