Servostyrning med avr

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Servostyrning med avr

Inlägg av MaggoT »

Jag har knåpat ihop en kod som skall ställa servot i mittläge, sedan om man kopplar PD0 till jord skall servot hoppa till ena sidan, och när man kopplar PD1 till jord skall det hoppa till andra sidan. Jag undrar om man istället kan koppla en potentiometer till AVRen och styra servot steglöst med den? Hur skulle man kunna göra detta isåfall?

Här kommer koden

Kod: Markera allt

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

int main()
{
        // Output
        DDRB = 0xFF;
        PORTB &= ~_BV(PD0);

        // Input
        DDRD = 0x00;
        PORTD = _BV(PD0) | _BV(PD1);

        while(1)
        {
                if(!(PIND & _BV(PD0)))
                {
                        // Om PD0 låg, Vänster (1ms)
                        _delay_ms(20);
                        PORTB |= _BV(PB0);
                        _delay_ms(1);
                        PORTB &= ~_BV(PB0);
                }
                else if(!(PIND & _BV(PD1)))
                {
                        // Om PD1 låg, Höger (2ms)
                        _delay_ms(20);
                        PORTB |= _BV(PB0);
                        _delay_ms(2);
                        PORTB &= ~_BV(PB0);
                }
                else
                {
                        // Annars mittläge (1,5ms)
                        _delay_ms(20);
                        PORTB |= _BV(PB0);
                        _delay_ms(1.5);
                        PORTB &= ~_BV(PB0);
                }
        }
}

Tyvärr har jag inte kunnat testa koden ännu, eftersom jag får mina servo's på posten först efter ett par dagar.
Kaggen
Inlägg: 432
Blev medlem: 29 januari 2005, 03:06:02

Inlägg av Kaggen »

Om du har en inbyggd A/D omvandlare i avr:en kan du ju använda den. Kolla vad du får för värden med vridpotten max resp. min, sedan räknar du ut faktorn av differensen och 1000 us (1 ms, max-min pulstid för servot).

Iomed att jag inte är nån expert på analog elektronik så vet jag inte exakt hur du skall koppla potten mot A/D:n, men det första jag tänker på är ett fast motstånd (säg 10kOhm) från matningen i serie med en pott på 10kOhm. Där tar du ut spänningen till A/D:n mellan det fasta motståndet och potten, enligt:

Kod: Markera allt

+5V----------
     |
     -
    | | 10 kOhm
    | |
     -
     |
     --------o  till A/D
     |
     - /
    |/| Vridpott 10kOhm
   /| |
     -
     |
GND -----
Då borde ju spänningen bli 2.5V mellan dessa motstånd då potten är på max ohm och 0V då den är på min. Du utnyttjar ju inte alla bitar i A/D:n då iofs, men det blir ju en enkel koppling.

Sedan är det bara att läsa A/D värdet, multiplicera med faktorn och använda produkten som delay-värde.

Som sagt, någon får väl invända om jag är totalt fel ute. Vet inte heller hur det blir med linjäriteten i ovanstående koppling. Antar att om du skall göra det riktigt så ska du nog använda en OP. Blir lite fler komponenter då iofs.

mvh Mats
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Gjorde precis samma sak för ca ett år sen, kommer inte ihåg riktigt hur jag tänkte men här är koden:

Kod: Markera allt

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include "a2d.c"

#  define OC1 PB5
#  define DDROC DDRD
#  define OCR OCR1A

volatile uint16_t pwm;
volatile uint16_t freq;
volatile uint8_t direction;


SIGNAL (SIG_OVERFLOW1)
{

	// Pulslängd ca 10ms gav bra respons
	ICR1=10000;
	
	//Försök att använda hela området på vridpot
	//pwm_scope=(936/1024)*pwm;
	//OCR=600+pwm_scope;
	
	// Det som funka bäst
	if(pwm*2<1536) // För att inte ge för lång pulstid till servot
		OCR=600+(pwm*2);
	
	// Försök med 8bit ad, 512*3=1536
	//OCR=600+(pwm*3);
}



void
ioinit (void) 
{
	a2dInit(); // Initierar ADC
	
    
    // Using phase & freq correct pwm, TOP=ICR1, freq scaling = 8
	TCCR1A = _BV (COM1A1);
    TCCR1B = _BV (CS11) | _BV (WGM13);
    /* set PWM value to 0 */
    OCR = 0;
    ICR1 = 0;
    /* enable OC1 and PB2 as output */
    DDRD = _BV (OC1);
    //DDRD= 0xFF;
    timer_enable_int (_BV (TOIE1));

    /* enable interrupts */
    sei ();
}

int
main (void)
{
    ioinit ();

    

    while(1)
	{
		pwm=a2dConvert10bit(0);
		freq=a2dConvert10bit(2);
	}

    return (0);
}
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Inlägg av MaggoT »

Hmm, jag försökte kompilera ovanstående kod och fick följande felmeddelande

Kod: Markera allt

> "make.exe" all

-------- begin --------
avr-gcc (GCC) 3.4.3
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Compiling: servo2.c
avr-gcc -c -mmcu=attiny2313 -I. -gdwarf-2 -DF_CPU=8000000UL  -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=servo2.lst  -std=gnu99 -MD -MP -MF .dep/servo2.o.d servo2.c -o servo2.o 
servo2.c:5:17: a2d.c: No such file or directory
servo2.c:16: warning: `SIG_OVERFLOW1' appears to be a misspelled signal handler
servo2.c: In function `ioinit':
servo2.c:39: warning: implicit declaration of function `a2dInit'
servo2.c: In function `main':
servo2.c:66: warning: implicit declaration of function `a2dConvert10bit'
servo2.c:71:3: warning: no newline at end of file
make.exe: *** [servo2.o] Error 1

> Process Exit Code: 2
Försökte googla efter vad "a2d.c" är men blev inte så mycket klokare :(
Skall försöka förstå mig på koden lite :)

EDIT: Jag glömde skriva att det är en ATTiny2313 jag använder, antar att jag måste ändra någonting i koden för att det skall passa den.
Kaggen
Inlägg: 432
Blev medlem: 29 januari 2005, 03:06:02

Inlägg av Kaggen »

Antar att "a2d.c" är frejo's egenhändigt hopknopade A/D konverterar funktioner. Antingen kanske han kan ge dig den koden också, eller får du knåpa ihop något motsvarande själv (mer utmaning och bra träning för de små grå).

mvh Mats
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

nä det var något jag hittade på nätet vid den tiden.

Nu har jag oftast använt avrlib, ad-libbet i den fungerar riktigt bra.

http://hubbard.engr.scu.edu/embedded/avr/avrlib/
Användarvisningsbild
MadModder
Co Admin
Inlägg: 31456
Blev medlem: 6 september 2003, 13:32:07
Ort: MadLand (Enköping)
Kontakt:

Inlägg av MadModder »

Varför inte koppla in alla tre anslutningar på en 10kOhm-potentiometer och utnyttja hela spannet mellan 0 och 5V?

Kod: Markera allt

  +5V
   |
   |
   -
  | |
  | |<-----till a/d
  | |
   -
   |
   |
   0V
Kaggen
Inlägg: 432
Blev medlem: 29 januari 2005, 03:06:02

Inlägg av Kaggen »

Eh! Tänkte inte på det. :)
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Inlägg av MaggoT »

Tack för alla svar :) Jag fick mina servo's på posten idag.. sitter och labbar lite nu men något verkar vara fel :shock:

Med _delay_ms(0.75) ställer sig servot i mitten, (borde väl vara 1.5ms?). Hur ställer jag in "hastigheten" i AVRen? Verkar vara där det strular..
Användarvisningsbild
anlamotte
Inlägg: 859
Blev medlem: 5 augusti 2003, 15:54:34
Ort: Stockholm
Kontakt:

Inlägg av anlamotte »

de flesta AVR har en inbyggd spänningsreferens som kan användas.. 2,56V eller liknande.

En pot kopplat mellan den utgången (AREF) och jord funkar bra.
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

MaggoT: Har du satt F_CPU till rätt värde?
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Inlägg av MaggoT »

cykze> Efter lite pill kom jag fram till att tiden (1.5ms för mittläge) stämde när jag satte såhär:
#define F_CPU 500000UL
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Förlåt, jag skulle ju naturligtvis ha skrivit att F_CPU ska sättas till den frekvens (i Hz) som du kör din AVR i, och inget annat.
MaggoT
Inlägg: 113
Blev medlem: 28 juli 2005, 16:48:27
Ort: Finland
Kontakt:

Inlägg av MaggoT »

Jo jag tänkte på det, problemet är att jag inte vet vilken hastighet den körs i :) jag läste någonstans att de flesta AVR'er är inställda på 1Mhz som default, jag vet dock inte hur man kollar/ändrar detta...
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Ta en titt i databladet under kapitlet som heter något med Clock. Där står det vad "default" är.
Skriv svar