Hallo,
es sind geneug Beiträge zum Thema Servoansteuerung im Forum zufinden.
Aber ich komme trotzdem nicht weiter. Ich möchte einfch nur, dass mein
Servo aus dem Modellbau die Position (Links Anschlag)einnimmt. Mit dem
folgendem Code tut sich aber nichts. Es wäre nett, wenn jemand einen
Blick drüber wirft und mir einen Tipp gibt.
1
/*
2
Alle 20ms (periodenlänge) einen Impuls senden--->f=50Hz
3
Links --> Pulsweite: 1ms
4
Mittelstellung --> Pulsweite: 1.5ms
5
Rechts --> Pulsweite: 2ms
6
Timer Konfiguration:
7
Timer1: 16Bit Timer zählt von 0...65536
8
Alle 100µs soll ein Interrupt ausgelöst werden
9
*1ms sind es 10 Takte -->Links Abschlag
10
*20ms sind es 200 Takte
11
12
Prescaler:1
13
TopWert: 16000000 Hz*100µ= 1600 Schritte <65536
14
*/
15
#define F_CPU 16000000UL
16
#include<avr/io.h>
17
#include<avr/interrupt.h>
18
#include<util/delay.h>
19
20
volatileuint8_tcount;
21
22
23
voidInit_Timer1(void);
24
ISR(Timer1_COMPA_vect);
25
26
//-----------------------------------------
27
28
intmain(void)
29
{
30
//Servoausgang
31
//Richtungsregister PortB Pin PB1
32
//Pin PB1 als Ausgang setzen
33
DDRB|=(1<<PB1);
34
//Pin PB1 auf High setzen
35
PORTB|=(1<<PB1);
36
while(1)
37
{
38
}
39
}
40
41
//------------------------------------------
42
//Konfigurations des Timer1
43
voidInit_Timer1(void)
44
{
45
//Modus 4:CTC-Modus, Topwert: OCR1A
46
TCCR1B|=(1<<WGM12);
47
//Prescaler 1, 16MHz/1=16MHz Frequenz des Timers
48
TCCR1B|=(1<<CS10);
49
//Timer/Counter1 Output Compare A Match interrupt ist freigegeben
Einen Funktions-Prototypen für eine ISR sehe ich hier zum ersten Mal -
interessant ...
Es wäre auch ganz praktisch, wenn Du in main() auch mal Timer1_Init
aufrufen würdest - so wird der Timer nie gestartet.
Welchen AVR nutzt Du?
Hi
>//Modus 4:CTC-Modus, Topwert: OCR1A>TCCR1B|=(1<<WGM12);
Was willst du mit CTC? Am einfachsten geht es mit Timer1 im PWM-Mode 14
oder 15. Vorteiler 8.
Mit Top = 40000 (20ms) und 2000 für 1ms bzw 2000 für 2ms erzeugst du ein
passendes Signal.
MfG Spess
spess53 schrieb:> Hi>>>//Modus 4:CTC-Modus, Topwert: OCR1A>>TCCR1B|=(1<<WGM12);>> Was willst du mit CTC? Am einfachsten geht es mit Timer1 im PWM-Mode 14> oder 15. Vorteiler 8.>> Mit Top = 40000 (20ms) und 2000 für 1ms bzw 2000 für 2ms erzeugst du ein> passendes Signal.>> MfG Spess
Hallo,
mit deR PWM habe ich bereits schon ausbrobiert und es funktioniert. Ich
möchte später mehrere Servos ansteuern, daher befasse ich mich momenta
mit dem CTC..
Der Compiler müsste eigentlich auch anmeckern, dass Du TIMER1_COMPA_vect
falsch (Groß-/Kleinschreibung) geschrieben hast - und wird gar keine ISR
erzeugen ...
Dieter F. schrieb:> Einen Funktions-Prototypen für eine ISR sehe ich hier zum ersten> Mal -> interessant ...>> Es wäre auch ganz praktisch, wenn Du in main() auch mal Timer1_Init> aufrufen würdest - so wird der Timer nie gestartet.>> Welchen AVR nutzt Du?AVR Studio4
oh ich habe es vergessen gehabt, die Funktion aufzurufen. Habe den Code
korrigiert und der Servo bewegt sich trotzdem nicht in die eingestellte
Position.
1
/*
2
Alle 20ms (periodenlänge) einen Impuls senden--->f=50Hz
3
Links --> Pulsweite: 1ms
4
Mittelstellung --> Pulsweite: 1.5ms
5
Rechts --> Pulsweite: 2ms
6
Timer Konfiguration:
7
Timer1: 16Bit Timer zählt von 0...65536
8
Alle 100µs soll ein Interrupt ausgelöst werden
9
*1ms sind es 10 Takte -->Links Abschlag
10
*20ms sind es 200 Takte
11
12
Prescaler:1
13
TopWert: 16000000 Hz*100µ= 1600 Schritte <65536
14
*/
15
#define F_CPU 16000000UL
16
#include<avr/io.h>
17
#include<avr/interrupt.h>
18
#include<util/delay.h>
19
20
volatileuint8_tcount;
21
22
23
voidInit_Timer1(void);
24
ISR(Timer1_COMPA_vect);
25
26
//-----------------------------------------
27
28
intmain(void)
29
{
30
//Servoausgang
31
//Richtungsregister PortB Pin PB1
32
//Pin PB1 als Ausgang setzen
33
DDRB|=(1<<PB1);
34
//Pin PB1 auf High setzen
35
PORTB|=(1<<PB1);
36
37
Init_Timer1();
38
while(1)
39
{
40
}
41
}
42
43
//------------------------------------------
44
//Konfigurations des Timer1
45
voidInit_Timer1(void)
46
{
47
//Modus 4:CTC-Modus, Topwert: OCR1A
48
TCCR1B|=(1<<WGM12);
49
//Prescaler 1, 16MHz/1=16MHz Frequenz des Timers
50
TCCR1B|=(1<<CS10);
51
//Timer/Counter1 Output Compare A Match interrupt ist freigegeben
Dieter F. schrieb:> Der Compiler müsste eigentlich auch anmeckern, dass Du TIMER1_COMPA_vect> falsch (Groß-/Kleinschreibung) geschrieben hast - und wird gar keine ISR> erzeugen ...
Ja - ich habs (mit AVR Studio 6) ausprobiert (Bild).
Es wird keine ISR erzeugt - Dein ATMega wird permanent per
"bad_interrupt" "resetten".
Dieter F. schrieb:
...
>> Ja - ich habs (mit AVR Studio 6) ausprobiert (Bild).>> Es wird keine ISR erzeugt - Dein ATMega wird permanent per> "bad_interrupt" "resetten".
Vielen Dank. Komisch, dass ich im AVR Studio 4 keine Fehlermeldung
erhalte.
Ich habe jetzt Timer1 in der ISR groß geschrieben und immer wird kein
Puls der Länge 1ms (10 Takte) erzeugt.
Dani schrieb:> Ich habe jetzt Timer1 in der ISR groß geschrieben und immer wird kein> Puls der Länge 1ms (10 Takte) erzeugt
Dann hast Du wohl einen anderen (oder kaputten) ATMega328(P)
1
/*
2
Alle 20ms (periodenlänge) einen Impuls senden--->f=50Hz
3
Links --> Pulsweite: 1ms
4
Mittelstellung --> Pulsweite: 1.5ms
5
Rechts --> Pulsweite: 2ms
6
Timer Konfiguration:
7
Timer1: 16Bit Timer zählt von 0...65536
8
Alle 100µs soll ein Interrupt ausgelöst werden
9
*1ms sind es 10 Takte -->Links Abschlag
10
*20ms sind es 200 Takte
11
12
Prescaler:1
13
TopWert: 16000000 Hz*100µ= 1600 Schritte <65536
14
*/
15
#define F_CPU 16000000UL
16
#include<avr/io.h>
17
#include<avr/interrupt.h>
18
#include<util/delay.h>
19
20
volatileuint8_tcount;
21
22
23
24
voidInit_Timer1(void);
25
26
ISR(TIMER1_COMPA_vect);
27
28
//-----------------------------------------
29
30
intmain(void)
31
{
32
Init_Timer1();
33
//Servoausgang
34
//Richtungsregister PortB Pin PB1
35
//Pin PB1 als Ausgang setzen
36
DDRB|=(1<<PB1);
37
//Pin PB1 auf High setzen
38
PORTB|=(1<<PB1);
39
while(1)
40
{
41
}
42
}
43
44
//------------------------------------------
45
//Konfigurations des Timer1
46
voidInit_Timer1(void)
47
{
48
//Modus 4:CTC-Modus, Topwert: OCR1A
49
TCCR1B|=(1<<WGM12);
50
//Prescaler 1, 16MHz/1=16MHz Frequenz des Timers
51
TCCR1B|=(1<<CS10);
52
//Timer/Counter1 Output Compare A Match interrupt ist freigegeben
Dani schrieb:> Kann es auch am Oszilloskop liegen?
Ja, oder auch am Bediener.
Aber das kannst Du ja testen: ein Oszi hat (üblicherweise) ein
Test-Signal-Ausgang zum Abgleich des Tastkopfs. Da sollte man einen
Rechteck sehen.
Dani schrieb:> Kann es auch am Oszilloskop liegen?
Es kann an allem Möglichen liegen ... :-)
Setze OCR1A auf einen höheren Wert - z. B. 16000 - und hänge eine LED
(mit Vorwiderstand) an PB1 - dann kannst Du das Blinken beobachten.
Bist Du sicher, dass Du den ATMega korrekt flasht? Bringt ein Verify das
gewünschte Ergebnis?
Dani schrieb:> mit deR PWM habe ich bereits schon ausbrobiert und es funktioniert.
Wenn das so ist, dann muss es eigentlich funktionieren - es sei denn, Du
hast den ATMega in die ewigen Jagdgründe geschickt.
Dieter F. schrieb:> gibt bei mir anliegendes Signal an PB1.
Hallo,
ich habe ein altes Oszilloskop der Firma Hameg 203-6. Ich wollte mir ein
neues holen aber ich weiss nicht welches. Darf ich erfahren, was für ein
Oszilloskop du verwendest?
BG
spess53 schrieb:> Hi>>>ich habe ein altes Oszilloskop der Firma Hameg 203-6.>> Na und. Wenn dein Oszi noch funktioniert solltest du das gleiche sehen.>> MfG Spess
Ja mein Oszi funktioniert.
Ich muss mal was loswerden. Undzwar ich bin total begeistert von diesem
Forum vorallem von eurer Hilfsbereitschaft.
Danke euch allen für die tollen Antworten.
Hallo,
ich bin es wieder:). Ich habe meinen Fehler gefunden und beseidigt.
Jetzt kann ich die Position (Links, Mittel und Rechts) des Servos
verändern in dem ich in der ISR die Werte in der If-Abfrage verändere.
1
ISR(TIMER1_COMPA_vect)
2
{
3
if(count<10)//10(Links), 15(Mittel), 20 (Rechts)
4
PORTB|=(1<<PB1);
5
else
6
PORTB&=~(1<<PB1);
7
8
if(count<200)//alle 20 ms , 20ms/100µ=200;
9
count++;
10
else
11
count=0;
12
}
Nun möchte ich, dass der Servo in alle drei Positionen gefahren wird.
Die Frage ist, wie realisiere ich das? Ich habe es mal hiermit probiert,
um zusehen, welches Signal am Pin anliegt.
Dani schrieb:> Hallo,>> Nun möchte ich, dass der Servo in alle drei Positionen gefahren wird.> Die Frage ist, wie realisiere ich das? Ich habe es mal hiermit probiert,> um zusehen, welches Signal am Pin anliegt.
Ist hierfür eine Winkelberechnung erforderlich?
VG
Dani schrieb:> Nun möchte ich, dass der Servo in alle drei Positionen gefahren wird.> Die Frage ist, wie realisiere ich das?
Indem du Pulse ausgibt, deren Länge zu der gewünschten Position gehört.
Um den Rest kümmert sich dann der Servo.
Dani schrieb:> #define F_CPU 16000000UL
Mit AVR Studio 4 oder Atmel Studio 6 solltest du das nicht im Code
angeben, sondern in den Projekteinstellungen. Wenn du es doch im Code
machst, dann siehe aber zu, das es mit den Projekteinstellungen
übereinstimmt.
Aber warum denn Soft PWM? Der Mega328 hat eine gut funktionierende
Hardware PWM mit hoher Auflösung auf Timer 1. Dazu benutzt du am besten
den Mode 14, wie oben schon mal erwähnt und setzt TOP in ICR1:
1
// ruhig gleich mal beide PWM Kanäle (A und B) - kost' ja nix
Matthias S. schrieb:> Dani schrieb:>> #define F_CPU 16000000UL>> Mit AVR Studio 4 oder Atmel Studio 6 solltest du das nicht im Code> angeben, sondern in den Projekteinstellungen. Wenn du es doch im Code> machst, dann siehe aber zu, das es mit den Projekteinstellungen> übereinstimmt.>> Aber warum denn Soft PWM?
Danke für die Antworten,
mit der Hardware PWM habe ich bereits ausprobiert und es funktioniert.
Ich möchte später mehrere Servos anstuern und daher wollte mit Soft PWM
weiter arbeiten. Zudem wollte ich mich mit dem Timer/Interrupt
auseinandersetzen. Jedoch weiss garnicht wie ich das anstellen soll. Wie
ich den Controllern sagen soll, dass der Servo von einer Position in die
nächste Position gehen soll?
Dani schrieb:> Ich möchte später mehrere Servos anstuern und daher wollte mit Soft PWM> weiter arbeiten.
Wieviele Servos sollens denn werden? 6 Stück sind mit der Hardware des
Mega328 problemlos machbar. Jeder Timer kann 2 ansteuern, Timer 0 und
Timer 2 allerdings sind nur 8 Bitter, dadurch sinkt die erreichbare
Auflösung.
Dani schrieb:> Jedoch weiss garnicht wie ich das anstellen soll.
Lies mal Application Note AVR136. Die Jungs beschreiben da, wie man
Multichannel Soft PWM mit AVRs realisiert:
http://www.atmel.com/devices/atmega168.aspx?tab=documents
Runterrollen bis AVR136. Da gibts das beschreibende PDF und die Software
als ZIP.
Ich habe einen Code gefunden ,Link:
Beitrag "Servo-Interrupt Problem"
In diesem Code wurden die Servopositionen berechnet. Ich sehe die
Gleihung nicht zum ersten Mal aber ich weiß nucht wie ich diese
herleiten soll.
Eine genaue Umrechnung von Grad zum PWM Wert ist gar nicht möglich, weil
das jeder Servo anders umsetzt.
Du kommst so oder so nicht umhin, für jeden einzelnen Servo mindestens
zwei Werte zu experimentiell zu ermitteln:
- PWM Wert kurz vor dem linken Anschlag
- PWM Wert kurz vor dem rechten Anschlag
Und jetzt kommt noch eine Gemeinheit: Die Mittlere Position liegt
meistens nicht genau in der Mitte zwischen diesen beiden Werten!
Letztendlich musst du die PWM Werte für alle konkreten Positionen, die
du anfahren willst, experimentiell ermitteln. Und wenn du den Servo
auswechselst, geht das Spiel von Vorne los - auch wenn der neue Servo
vom selben Modell/Typ ist.
Also vergiss die Berechnung, der Aufwand lohnt sich nicht.
Stefan U. schrieb:> Eine genaue Umrechnung von Grad zum PWM Wert ist gar nicht> möglich, weil> das jeder Servo anders umsetzt.>> Du kommst so oder so nicht umhin, für jeden einzelnen Servo mindestens> zwei Werte zu experimentiell zu ermitteln:>> - PWM Wert kurz vor dem linken Anschlag> - PWM Wert kurz vor dem rechten Anschlag
Was heisst kurz vor dem linken Anschlag? Wie weit darf ich den Wert
(1ms) runtersetzen? Ich habe für die Pulsweite für den linken Anschalg
den Wert o.5 ms gestzt und der Motor dreht sich jetzt 90°
(Mittelstellung) nach Links.
> Wie weit darf ich den Wert (1ms) runtersetzen?
Das musst du heraus finden. Letztendlich ist es wichtig, dass der Servo
weder an seinen internen noch an irgendeinen externen Anschlag anstößt,
weil er sonst heiß läuft.
Wie viel Grad das entspricht und bei wie vielen ms das passiert, musst
du selbst herausfinden. Wie gesagt ist das bei jedem Servo anders.
Also grober Anhalswert gilt: 1ms=links, 1,5ms=mitte, 2ms=rechts
Dani schrieb:> Was heisst kurz vor dem linken Anschlag? Wie weit darf ich den Wert> (1ms) runtersetzen?
Na, so weit, dass der Servo gerade nicht gegen den linken Anschlag
stößt. Sonst zieht der Motor dauernd Strom und kann heiß laufen, genauer
gesagt heiß stehen.
Aber das Thema "Viele Servos" ist ja keine Neuerfindung
Beitrag "Servocontroller mit ATmega8 für 20 Servos"Beitrag "Re: Mehrere Servos mit OCR1A"
Dani schrieb:> Ich habe einen Code gefunden ,Link:>> Beitrag "Servo-Interrupt Problem">> In diesem Code wurden die Servopositionen berechnet. Ich sehe die> Gleihung nicht zum ersten Mal aber ich weiß nucht wie ich diese> herleiten soll.> [void loop() {> for(pos=0; pos<180; pos++) {> servoPos = ((pos * 11) + 500)/10; ????> delay(10);> }>> for(pos=0; pos>0; pos--) {> servoPos = ((pos * 11) + 500)/10; ????> delay(10);> }> }]
Hallo,
wiedermal ne Frage zum Servo. Ich möchte nicht dass der Servo nur die
drei Positionen (Pulsbreite 100: 1ms, Pulsbreite 150 :1,5 ms und
Pulsbreite 200:2ms) einnimmt. Ich würde gerne eine von mir definiert
Winkelposition (45 ° ) eingeben, die der Servo anfahren soll. Die Frage
ist, muss ich da eine Formel herleiten? Kann mir jemand einen
Denkanstoß geben?
Danke
100 = 1 ms ->0°
150 = 1.5 ms ->90°
Mark schrieb:>> wiedermal ne Frage zum Servo. Ich möchte nicht dass der Servo nur die> drei Positionen (Pulsbreite 100: 1ms, Pulsbreite 150 :1,5 ms und> Pulsbreite 200:2ms) einnimmt. Ich würde gerne eine von mir definiert> Winkelposition (45 ° ) eingeben, die der Servo anfahren soll. Die Frage> ist, muss ich da eine Formel herleiten? Kann mir jemand einen> Denkanstoß geben?
Ja, den Winkel kannst du mittels Dreisatz berechnen, wenn du die
minimale und maximale Pulsbreite des Servos (hier geht meist mehr als
1ms-2ms) kennst und dessen maximal möglicher Arbeitswinkel.
Das Problem: Das ist bei jedem Servo etwas anders. D.h. du musst es für
einen speziellen Typ bestimmen.
Immerhin sollte im allgemeinen die Pulsbreite ziemlich linear zum
tatsächlichen Winkel sein. Das hilft dir schon mal.
Cyblord -. schrieb:> Ja, den Winkel kannst du mittels Dreisatz berechnen,
Beispiel:
90°=150
x=Pulsweite -> x=(Pulsweite*90)/150
Mittels des Dreisatzes müsste ich immer die Pulsweite eingeben. Das
heißt, ich müsste vorher für den jeweiligen Winkel die entsprechende
Pulsweite ausgerechnet haben. Oder?
Mark schrieb:> Cyblord -. schrieb:>>> Ja, den Winkel kannst du mittels Dreisatz berechnen,>> Beispiel:>> 90°=150> x=Pulsweite -> x=(Pulsweite*90)/150
Du hast den Rest meines Postings aber schon gelesen und verstanden?
> Mittels des Dreisatzes müsste ich immer die Pulsweite eingeben. Das> heißt, ich müsste vorher für den jeweiligen Winkel die entsprechende> Pulsweite ausgerechnet haben. Oder?
Umstellen!