Hallo!

Is er ergens een tutorial te vinden over het aansturen van een servo met een AVR controller?

Hier zijn toch vast wel stukjes script voor te vinden lijkt mij?
Ik heb geen scope, dus zelf code schrijven om een goed puls signaal te genereren zit er waarschijnlijk niet in.

Ik zal wel verkeerd zoeken, maar ik heb nog niks gevonden :(
Voor PICs vind ik vanalles, maar voor een AVR alleen hex files of 'grote' source files met te veel functies. Ik ben helaas nog te onervaren om alleen het servo sturen daar uit te destilleren.
Ik hoef geen seriële input te verwerken, het aansturen van de servo is genoeg.

Wie o wie helpt mij op weg?

bij voorbaat dank,

Joost

Script? Wat voor taal moet het zijn dan, ASM, basic, C, etc.. ? En wat voor servo? Bedoel je een standaard modelbouw servo met 1-2ms PWM signaal?

[Bericht gewijzigd door Marcel op ]

Sorry voor mijn onvolledigheid.

Ik bedoel inderdaad een 'gewone' modelbouw servo.
En met script bedoelde ik de C cource.

Ik programmeer namelijk in CodeVision, dus ik heb het liefst een C voorbeeld.

Bedankt voor je antwoord.

Joost

Op zich is een servo sturing wel een leuke uitbreiding voor mijn AVRGCC tutorial. Ik zal eens kijken wat ik kan doen. Maar heb vooral geen haast. Wellicht dat ik er vanavond nog mee begin. Maar anders schuift het zo door naar volgende week. Het wordt dan uiteraard geschreven voor de AVRGCC compiler. Je moet het dan zelf maar zien te porteren naar Codevision. Of je stapt over op AVRGCC, dat kan natuurlijk ook.

Dat zou wel vet zijn :)

Maar er is toch vast ergens te vinden hoe je zoiets in C aanpakt?

Joost

Zo, ik heb wat in elkaar gezet. Het is vrij eenvoudig, maar toch heb ik er nog wel even mee zitten klooien. Ik kreeg de timing niet goed en snapte er niets van. Om de getallen met elkaar uit te lijnen had ik er een 0 voorgezet en er niet bij stilgestaan dat dat de octale notatie is.

Dit is voor een ATtiny2313 op 1MHz (1MHz is ook de fabriekinstelling). Voor een andere kloksnelheid hoeft alleen de timing aangepast te worden. Een andere AVR is ook geen probleem mits die een 16 bits timer heeft.

Een servo signaal is een pulsbreedte gemoduleerd signaal. De totale puls is altijd 20ms lang. De tijd dat de puls hoog is varieert van 1ms tot 2ms, waarbij 1.5ms overeenkomt met de middenstand van de servo. De servo waarmee ik heb getest, een oude Robbe S122, heeft een iets groter bereik 0.6ms tot 2.4ms.

Timer 1 loopt op de zelfde snelheid als de core (1MHz). Deze loopt tot 20.000 (output compare register 1A) en begint dan opnieuw. 20.000 tellen komt precies overeen met 20ms.

De output compare registers 1A en 1B triggeren een bijbehorend interrupt die er voor zorgt dat poort PB3 op de max van 20.000 hoog gemaakt wordt en op de instelbare waarde van OCR1B weer laag. OCR1B representeert het servo signaal in us.


#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

SIGNAL(SIG_TIMER1_COMPA)
{
  PORTB |= (1 << PB3); // PB3 high
}

SIGNAL(SIG_TIMER1_COMPB)
{
  PORTB &= ~(1 << PB3); // PB3 low
}

int main()
{  
  TCCR1B = (1 << WGM12) | (1 << CS10); // timer1: ctc, clk/1
  TIMSK = (1 << OCIE1A) | (1 << OCIE1B); // timer1: output_compare a and b 
  OCR1A = 20000; // 20ms
  OCR1B = 1500; // 1.5ms

  DDRB |= (1 << PB3); // PB3 as output

  unsigned int servoTiming; // servo timing in us

  sei(); // enable interrupts

  while(1)
  {
    // slowly turns servo from one side to the other
    for(servoTiming = 1000; servoTiming < 2000; servoTiming++)
    {
      OCR1B = servoTiming;
      _delay_ms(10);
    }
    // slowly turns the servo back
    for(servoTiming = 2000; servoTiming > 1000; servoTiming--)
    {
      OCR1B = servoTiming;
      _delay_ms(10);
    }
  }

  return 0;
}

Testopstelling
http://www.uploadarchief.net/files/download/servo_controller.jpg

Timing servo controller op scoop. (5V/div 5ms/div)
Hier is duidelijk het 20ms herhalende signaal te zien.
http://www.uploadarchief.net/files/download/servo_scoop1.jpg

Een 1.5ms signaal. (5V/div 1ms/div)
http://www.uploadarchief.net/files/download/servo_scoop2.jpg

Moet dat bij het eerste scoopbeeld niet 5v/div 5ms /div zijn? ;)

Scherp opgemerkt. Ja ik zal het even verbeteren.

Vet!

Hier moet het zeker mee lukken, bedankt!!

zelf ook nog een linkje gevonden:
http://www.seattlerobotics.org/encoder/200106/16csscnt.htm#1.2

Binnenkort eens testen.

Nogmaals bedankt.

Joost

Hallo!

Ik heb het zojuist even geprobeerd, maar mijn servo duikt de hoek in :(
Terwijl hij toch in het midden zou moeten blijven staan lijkt mij. (compare register B verander ik niet)

Ik zal wel iets fout ingesteld hebben, maar ik kan helaas niet vinden wat.


// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{  
PORTB.0 = 1;

}

// Timer 1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{  
PORTB.0 = 0;
}

void main(void)
{
.....
........
......
....

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Toggle
// OC1B output: Toggle
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: On
TCCR1A=0x50;
TCCR1B=0x01;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0b1001110;     // 20000
OCR1AL=0b00100000;
OCR1BH=0b101;         // 1500
OCR1BL=0b11011100; 

 
....
.....
....

// Global enable interrupts
#asm("sei")

while (1)
      {   
      PORTB.1 = 1;   // zet power led aan
      };
} 

Ziet iemand wat ik fout doe?

En is het trouwens niet mogelijk een servo aan te sturen met een PWM signaal? Zo ja, is dat niet makkelijker/handiger?

Ik hoop dat iemand mij kan helpen.

Joost

Je hebt maar 1 compare match nodig, en dit is PWM opwekken.

Hmm, kan je me daar iets meer over vertellen?

Compare registers en PWM zijn nieuw voor mij.
Ik weet wel wat het in grote lijnen inhoud, maar niet goed hoe ik het moet uitvoeren.

Zonder scope is het moeilijk om te zien wat je doet, hij doet het, of hij doet het niet. Waardoor hij het niet doet, is met mijn ervaring moeilijk te achterhalen.

[Bericht gewijzigd door Joosty op ]

Ik gebruik de attiny2313 voor een rgbled projectje maar het zal vast aan te passen zijn voor die servo;
hieronder wat code:


#define OC0A PB2
#define OC1A PB3
#define OC1B PB4
#define OCR_R OCR1B
#define OCR_G OCR1A
#define OCR_B OCR0A

...onderstaande heb ik in een init methode staan

TCCR0A = (1<<WGM00) | (1<<COM0A1); // timer0 op 8bit normal pwm en doe ook even compare reg goed
TCCR0B = (1<<CS01); // timer 0 op 1/8 vd kloksnelheid

TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1B1); // timer1 op 8bit normal pwm en doe ook even compare reg goed
TCCR1B = (1<<CS11); // timer 1 op 1/8 vd kloksnelheid

OCR_R = 0; // pwm waardes op 0
OCR_G = 0; 
OCR_B = 0; 

DDRB = (1<<OC0A) | (1<<OC1A) | (1<<OC1B); // enable de output compare pinnen, PB2 PB3 PB4

TIMSK = (1<<TOIE1); // enable de interrupts
sei ();

....onderstaande is de functie die de interrupt steeds aanroept

ISR (TIMER1_OVF_vect) 
{
        //zet hier de waarde van je pwm bijv. (mooi kleurtje maken)
	OCR_R = 100;	
        OCR_B = 0;	
        OCR_G = 255;
}

Ik speel nog niet zo lang met C en AVR dus spaar me :)
Sorry voor de layout

Op 27 juni 2006 12:54:48 schreef Joosty:
Hallo!

Ik heb het zojuist even geprobeerd, maar mijn servo duikt de hoek in :(
Terwijl hij toch in het midden zou moeten blijven staan lijkt mij. (compare register B verander ik niet)

Ik zal wel iets fout ingesteld hebben, maar ik kan helaas niet vinden wat.

Hey

Het kan zijn dat je de pulsbreedte verkeerd hebt want ik heb eens ergens gezien geloof ik dat de ene servo bij een signaal van 1,5 ms het ene doet maar een ander type weer iets anders.
Ook kan het liggen aan het fiet dat je servo´s met een negative en een positieve impuls hebt.

In de elektuur van deze maand stond ook een servotester, hiervan was een compleet bouwpakket verkrijgbaar,of een losse voorgeprogrammeerde controller, de code voor het benodigde PIC kon je ook op de site vinden
als het goed is.

Zonder interrupts, maar met de PWM module.


#include <avr/io.h>
#include <util/delay.h>

int main()
{
  // timer1: fast pwm, clear OC1B on match
  TCCR1A = (1 << COM1B1) | (1 << WGM11) | (1 << WGM10);
  // timer1: fast pwm, ctc top=OCR1A, clk/1
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
  OCR1A = 20000; // 20ms
  OCR1B = 1500; // 1.5ms

  DDRB |= (1 << PB4); // PB4/OC1B as output

  uint16_t servoTiming; // servo timing in us

  while(1)
  {
    // slowly turns servo from one side to the other
    for(servoTiming = 1000; servoTiming < 2000; servoTiming++)
    {
      OCR1B = servoTiming;
      _delay_ms(10);
    }
    // slowly turns the servo back
    for(servoTiming = 2000; servoTiming > 1000; servoTiming--)
    {
      OCR1B = servoTiming;
      _delay_ms(10);
    }
  }

  return 0;
}

Bedankt voor je hulp!

ik krijg het alleen niet zo 123 naar codevision omgezet.

(1 << COM1B1) | (1 << WGM11) | (1 << WGM10)

wat is COM1B1 en WGM11 etc.?

CodeVision lijkt de OCR1 registers verdeeld te hebben over een Hi en een Lo register.
Bij jou is het 1 register, is dit een verschil tussen de compilers, of zit ik in de verkeerde registers te roeren?

Waarom gebruikt niemand CodeVision? Is AVRGCC beter? En waarom?
Ik wil eventueel best overstappen op AVRGCC, maar dan nog is het wel handig als ik weet wat er met bijv. COM1B1 bedoeld word. :)

nogmaals bedankt

[Bericht gewijzigd door Joosty op ]

Wat betreft die bit definities, lees even pagina 108 van de ATtiny2313 datasheet "16-bit Timer/Counter Register Description" De AVRGCC header files gebruiken altijd bit definities die overeenkomen met de benaming in de datasheet. Het gebruik daarvan is stukken duidelijker dan bijv. TCCR1A = 0x11;

OCRA1 is in werkelijkheid ook verdeelt over twee 8-bits registers, namelijk OCR1AL en OCR1AH. De AVRGCC library maakt daarvan een pseudo 16-bits register. Als je compiler daar niet in voorziet moet je dat dus zelf doen door het 16-bits getal op te splitsen in een hoge byte en een lage byte. Hoe je dat doet lees je op pagina 88 van de datasheet.

CodeVision moet ik voor betalen. AVRGCC kost niets. Met beide kan ik hetzelfde. De keuze lijkt me duidelijk.

Naar aanleiding van deze post heb ik een vervolg vraag. Ik weet niet zeker of dit dan de juiste plek is maar vooruit...

Ik heb de 'tutorial' van Marcel overgenomen en dat werkt (uiteraard) perfect. Maar nu wil ik een tweede servo (tegelijk) aansturen met dezelfde ATTINY2313. Mijn gedachte was als volgt:

De herhalingscyclus voor een servo is 20msec. Volgens mij maakt het dan niet uit waar in die cyclus je het stuursignaal geeft, als het maar steeds op dezelfde plek in de cyclus is. Doe je het bv. steeds op 10msec dan duurt het nog steeds 20msec voor de volgende puls gegeven wordt, toch?

Stel nu dat ik steeds op de 0msec en op de 10msec een stuursignaal geef om zo twee servo's aan te sturen. Dan moet ik er natuurlijk voor zorgen dat de puls op 0msec bij de ene servo komt (en de andere servo op dat moment geen puls krijgt) en op de 10msec de ander.

Iemand een idee hoe ik kan aansturen dat het stuursignaal op het ene moment bij de eerste servo aan komt en op het tweede moment bij de tweede? Ik wou dat via een vrije poort op de ATTINY doen maar krijg het niet voor elkaar...

Alvast bedankt voor het meedenken!

Jeroen.