Styra rc-servos från ATTINY2313

Robot, CNC, Pneumatik, Hydraulik, mm
The11thGrape
Inlägg: 12
Blev medlem: 15 augusti 2005, 21:32:52

Styra rc-servos från ATTINY2313

Inlägg av The11thGrape »

Hej.

Jag håller på med ett projekt där jag ska försöka styra rc-servos från en ATTINY2313, nu är det så att jag tyvärr inte vet hur jag ska göra.
Jag vet hur man styr en rc-servo i teorin, problemet är att jag inte vet hur jag ska göra för att få AVR´n att förstå... så att säga.

Jag skulle bli väldigt glad om någon skulle kunna hjälpa mig.

Nu har den här frågan säkert tagits upp tidigare, men jag använde sökfunktionen och hittade ingen. Om det skulle visa sig att den har tagits upp tidigare så ber jag om ursäkt och hoppas att någon admin kan vara så vänlig att ta bort den här tråden.
Användarvisningsbild
PaNiC
Inlägg: 2610
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Inlägg av PaNiC »

Vilket språk programmerar du i?
Hur styr man servot i teorin?
The11thGrape
Inlägg: 12
Blev medlem: 15 augusti 2005, 21:32:52

Inlägg av The11thGrape »

Om jag har föstått det rätt så styr man en servo genom att ge den pulser, där frekvensen och pulsbredden avgör vilken position servot ska vridas till.

Jag ska försöka skriva programmet i C
Användarvisningsbild
AndLi
Inlägg: 18118
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Inlägg av AndLi »

frekvensen är väll inte jätteviktig, lägg den på ca 50hz, Det är längden på den höga pulsen som är viktig. 1-2ms brukar det vara.

Titta på hur du sätter upp hardware timern i uC (om den har nån) sätt den så den löser var 20 ms, när den sen löser höjer du utpinnen och ställer en annan timmer till 1-2ms. När den i sin tur löser sänker du utpinnen och väntar på att den första timern ska lösa igen.

Eller så gör du två lopar, enklare men tar upp all processortid och är jobbig att trimma in.
Användarvisningsbild
RDX*
EF Sponsor
Inlägg: 1651
Blev medlem: 28 maj 2003, 22:52:04
Ort: Skåne - Lund

Inlägg av RDX* »

Jag skrev denna kod till en mega8 för ett tag sedan.

Det är skrivet i Bascom. Det den gör är att den läser av en accelerometer och reglerar ett servo efter lutningen på accelerometern. Jag använder mig av polling (kollar sensor och utför saker varje loop) så det är långt ifrån optimerat men det fungerade för ändamålet.

Kod: Markera allt

$regfile = "m8def.dat"
$crystal = 1000000
$baud = 19200
 Osccal = 141

Config Portb = Output
Config Portc = Input
Config Timer0 = Timer , Prescale = 64
Config Adc = Single , Prescaler = Auto , Reference = Internal


On Adc Adc_isr Nosave
Enable Adc
Enable Interrupts

Dim X_temp As Single
Dim X As Word
Dim X1 As Word
Dim X2 As Word
' -----[ Constant ]----------------------------------------------------------
Dim Kp As Single                                            ' Proportional factor
Dim Ki As Single                                            ' Integral factor
Kp = 0.9
Ki = 0.3
'-----[ Varibles ]-----------------------------------------------------------
Dim Error As Single
Dim Sum_error As Single
Dim Sum_error_temp As Single
Dim Pterm As Single
Dim Iterm As Single
Dim Servo_temp As Word
Dim Ref As Single
Ref = 148


X = 0

Do

   Start Adc
   Idle
   Stop Adc

   X_temp = X - 465
   X_temp = X_temp / 130
   X_temp = X_temp * 300                                    '[signal: faktiska vinkeln 0-300]
   Error = Ref - X_temp                                     '[errot =-150 till 150]
   Sum_error_temp = Error
   Sum_error_temp = Sum_error_temp / 150
   Sum_error = Sum_error + Sum_error_temp
   If Sum_error > 150 Then
   Sum_error = 150
   End If
   If Sum_error < -150 Then
       Sum_error = -150
   End If
   Pterm = Kp * Error                                       '[Pterm = kp[-150 till 150]
   Iterm = Ki * Sum_error
   Pterm = 380 + Pterm                                      '[pterm = 200 till 500]
   Servo_temp = Pterm + Iterm
   If Servo_temp > 530 Then
   Servo_temp = 530
   End If
   If Servo_temp < 200 Then
       Servo_temp = 200
   End If
   Pulseout Portb , 0 , Servo_temp                          'ger en puls 1-2ms
   Waitms 20


Loop


Adc_isr:
  push r24
  in r24,sreg
  push r24
  push r25
  X1 = Getadc(0)
  X2 = Getadc(0)

  X = X1 + X2
  X = X / 2
  pop r25
Necator
Inlägg: 40
Blev medlem: 4 november 2003, 12:32:08
Ort: Stockholm
Kontakt:

Inlägg av Necator »

Skulle ju kunna vara tänkbart att använda två timers (1 om man har dåligt med timers över), en på 50Hz och den andra till t.ex 500Hz.
50Hz loopen får alltid gå och när den får interrupt så höjer den pinnen/pinnarna samt startar den snabbare loopen.
500Hz loopen har en/flera räknare som minskas och pinnen/pinnarna sänks när räknaren når 0. När alla är klara slår man bara av interrupten och väntar på nästa loop från 50Hz loopen.
T.ex max åt ena hållet så får man lägga in typ 255(~2ms) och max åt andra hållet lägger man in 127(~1ms) i registret som man uppdaterar varje gång den lilla loopen får interrupt
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Jag har inte grejjat något med RC-servos men jag tycker ändå att det borde vara smidigare att sköta allt i en timer. Typ så här:

Kod: Markera allt

timerinterrupten:
    if pinne låg:
        TIMER = tid_hög;
    else:
        TIMER = tid_låg;

    Växla värdet på pinnen;
The11thGrape
Inlägg: 12
Blev medlem: 15 augusti 2005, 21:32:52

Inlägg av The11thGrape »

Det tackar jag för. :)
Användarvisningsbild
MadModder
Co Admin
Inlägg: 31169
Blev medlem: 6 september 2003, 13:32:07
Ort: MadLand (Enköping)
Kontakt:

Inlägg av MadModder »

Håller själv som bäst på att planera lite servostyrning till ett litet projekt. Läste ett datablad för ett futaba-servo, och där stod det att perioden ska ligga mellan 30-50ms. Alltså 20-33Hz. 50Hz blir ju en period på 20ms. Borde det inte vara en slags standard på alla RC-servon?
Användarvisningsbild
bengt-re
EF Sponsor
Inlägg: 4829
Blev medlem: 4 april 2005, 16:18:59
Skype: bengt-re
Ort: Söder om söder
Kontakt:

Inlägg av bengt-re »

märkligt, jag har alltid trott och kört servon med 20ms pulsintervall, iofs oftast hitec-servon, men jag vet att jag mätte utgngen ifrån hitec mottagaren och där var det en pfr på 57 Hz om jag inte missminner mig, så sedan dess har jag alltid avänt 50Hz, rätt eller fel. Däeemot så kan man fuska och hoppa över några pulser ibland utan att det gör servot något - det står bara still ist
Användarvisningsbild
MadModder
Co Admin
Inlägg: 31169
Blev medlem: 6 september 2003, 13:32:07
Ort: MadLand (Enköping)
Kontakt:

Inlägg av MadModder »

Appropå Hitec-servon, så köpte jag ett hs-325hb på roffes modellflyg i stockholm för 85 spänn. Det tyckte jag var billigt. :)
Användarvisningsbild
bengt-re
EF Sponsor
Inlägg: 4829
Blev medlem: 4 april 2005, 16:18:59
Skype: bengt-re
Ort: Söder om söder
Kontakt:

Inlägg av bengt-re »

Det var billigt! Per styck eller? Jag beställde ett fyrpack till bra pis, har för mig att det var 325 spänn, men då fick du ett ännu bättre pris. Jag tycker att hitec-srevon är pricis lika bra som jr, eller futaba - så likssom inte lönt att betala mer. Oki, för någno som skall använda dem i ett sextusenkronorsplan, då resonerar man kanske annourlunda eftersom konsekvenserna av en felfunktion blir så otrevliga...

Men till hobbybruk så är billigare bättre !
Användarvisningsbild
MadModder
Co Admin
Inlägg: 31169
Blev medlem: 6 september 2003, 13:32:07
Ort: MadLand (Enköping)
Kontakt:

Inlägg av MadModder »

Ja, jag köpte ju bara ett, så jag antar att det var styckpriset... :D
Han säljer just dem som BULK. Ett servo utan kartong/ask, och en zip-påse med armar å grejer. :)

Ang. periodtiden får jag väl helt enkelt testa mig fram och se inom vilka gränser servona reagerar tillförlitligt, och välja ett medelvärde. :)
Det andra är ett äldre Graupner C512.
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Började på ett litet servoprojekt för något år sen.

Här är koden:

Kod: Markera allt

/* Filename		: yasc.c
 * Date			: 2004-07-08
 * Last modified: 2004-07-08
 * Author		: Fredrik Johansson
 * Description	: yasc stands for Yet Another Servo Controller.
 *				: It's basically a piece of code that makes one of the ports on the
 *				: atmega32 into a pwm. Why? Well, the built in pwm:s are just four,
 *				: which might suffice but they're also different to set, 16-bit vs 8-bit
 *				: phase correct vs phase and frequency correct.
 */

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

// Defines the port register we wanna use
#define DDRSERVO DDRD

// Defines the port we wanna use, must be same as the register
#define SERVOPORT PORTD

// Defines the pins we wanna attach servos to
#define SP0 PD0
#define SP1 PD1
#define SP2 PD2
#define SP3 PD3

// 8-bit integers for servo position
// Still gotta check up -min8t option for avr-gcc
volatile uint8_t SERVO_0;
volatile uint8_t SERVO_1;
volatile uint8_t SERVO_2;
volatile uint8_t SERVO_3;

// 8-bit integers for servo min value, learned it the hard way
volatile uint8_t SERVO_0_MIN;
volatile uint8_t SERVO_1_MIN;
volatile uint8_t SERVO_2_MIN;
volatile uint8_t SERVO_3_MIN;

// Same for max value
volatile uint8_t SERVO_0_MAX;
volatile uint8_t SERVO_1_MAX;
volatile uint8_t SERVO_2_MAX;
volatile uint8_t SERVO_3_MAX;

// Pulseparameters
volatile uint16_t pc; // Pulse can be up to 65535us
volatile uint16_t pulse_length; // 
volatile uint16_t pulse_with; // We need a pulse with of at least 2000us at max

// Test variables
volatile uint8_t test;

// Using counter1 since it's 16-bit
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
	pc++;
	
	// Resets the counter at the first interrupt after the 10ms delay defined below
	// Also takes care of resetting the pulse counter and set all outputs high at
	// the beginning of the new pulse
	if(OCR1A>19)
	{
		OCR1A=19;
		pc=0;
		SERVOPORT=(_BV(SP0) | _BV(SP1) | _BV(SP2) | _BV(SP3));
	}
	
	// No need to do interrupt every 10us after passing 2.5ms
	// Next interrupt will be in 10ms, ie the pulse is 12.5ms total	
	if (pc>250)
		OCR1A=19999; 
	
    // Sets the outputs low after specified pulse length	
	if(pc==SERVO_0)
		SERVOPORT=SERVOPORT&~_BV(SP0);
	if(pc>=SERVO_1)
		SERVOPORT=SERVOPORT&~_BV(SP1);
	if(pc>=SERVO_2)
		SERVOPORT=SERVOPORT&~_BV(SP2);
	if(pc>=SERVO_3)
		SERVOPORT=SERVOPORT&~_BV(SP3);
}

SIGNAL(__vector_default)
{
// Default interrupt vector, usefull for debugging
}

// Initiations to be done on reset/power on
void ioinit (void) 
{
	//a2dInit(); // Initiate AD
	
	// set up counter1 with 8 times prescaling on mcu clock (The CS11 bit), 2Mhz.
	// and Clear Timer on Compare Match (The WGM12 bit) with TOP-value=OCR1A
	TCCR1B = _BV (CS11) | _BV (WGM12);
    
	// With 2Mhz clock and counting 0-19 we should get an interrupt every 10us 
	OCR1A=19; // Should change after about 2ms, no need to do interrupts for following 18ms
		
    DDRSERVO = (_BV(SP0) | _BV(SP1) | _BV(SP2) | _BV(SP3));


    timer_enable_int (_BV (OCIE1A));

    // Enable interrupts
    sei ();
}

int main (void)
{
    ioinit ();
	SERVO_0=150;
	SERVO_1=244;
	SERVO_2=200;
	SERVO_3=50;
	
    for(;;)
	{

	}
	
	
    return (0);
}
Mina servon reagerade mycket bättre när jag låg runt 12ms periodtid jämnfört med 20ms.

Här är en annan snutt kod som använder pwm-modulen i atmega32:

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;
	
	// Pulsbreddens ställs via vridpot
	if(pwm*2<1536) // För att inte ge för lång pulstid till servot
		OCR=600+(pwm*2);
}

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);
    
    timer_enable_int (_BV (TOIE1));

    /* enable interrupts */
    sei ();
}

int
main (void)
{
    ioinit ();

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

    return (0);
}
Kan ju va lite smidigare att använda den färdiga pwm-modulen i attiny2313.
Inställningen av pulsbredden är lite fulkodad men du hajar nog konceptet iaf ;)
Skriv svar