Servo
En servomotor er en motor med indbygget regulering, hvor man kan angive hvilken position man ønsker den skal stå i.
Anvendelse
Servo-motorer bruges typisk steder hvor der skal mere trækkraft til i forhold til en stepmotor, og typisk i forbindelse med en positionering hvor det er et begrænset vinkel-område der skal positioneres til.
Små servomotorer har stor udredelse i fjernstyrede fly og biler.
Styring
En servomotors position angives med en puls[1], der ved hjælp af pulslængden angiver hvilken position man ønsker servoen skal stå i:
Pulsen der angiver servoens position
Midterpositionen angives med en puls på 1.520 ms. Venstre og højre yderposition angives som hhv. 0.92 ms og 2.12 ms
Pulsen skal komme med et fast interval på mellem 14 og 20 ms:
Pulsen kommer med et fast interval
Softwaremodul til Arduino
I Arduinos eksempler kan man finde et fornuftigt eksempel Knob[2], der sætter en servo op til at styre efter et potentiometer.
Eksemplet connecter til servoen og initialiserer i følgende kode:
/*
Controlling a servo position using a potentiometer (variable resistor)
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
modified on 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Knob
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
I loop() læses den analoge pin A0, og værdien tilpasses 0-180, hvorefter den skrives til servoen. Der ventes lidt, så servoen kan nå at reagere. Dette gentages, så servoen hele tiden følger potentiometerets stilling.
void loop() {
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
myservo.write(val); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
}
Softwaremodul til PIC
Softwaren er baseret på timer 2, der er en 8 bit timer, som kan indstilles til at interrupte.
Timeren forsynes med en clock-frekvens der stammer fra PIC'ens clock, og bliver delt ned via 4 forskellige delere.
Først deles oscillatorfrekvensen med 4 som standard.
Herefter deles den ned med enten 1, 4 eller 16, og her vælges fast at det er 4.
Efter tælleren ligger den sidste deling, der kan indstilles fra 1 til 16. Denne deling anvendes til at tilpasse tiden til den aktuelle clockfrekvens, så hvert tælleskridt sker med 12 us interval.
Timeren kan så indstilles med PR2 registeret, hvor en indstillen på 77 giver 924 us, 127 giver 1524 us og 177 giver 2124 us, så den ønskede puls kan laves ved at tage procent-værdien og lægge 77 til.
Pausen etableres ved at sætte PR2 til resten af tiden op til 2124 us, og derefter at lade den gennemføre 7 intervaller á 2124 us, så den totale periodetid ligger fast på ca. 17 ms.
Anvendelsen af softwaremodulet
For af angive hvilken værdi der skal ud på servoen er der en simpel interface-rutine, der kan lægges ind i ens kode som vist her:
include servo
forever loop
-- kode der regner ud hvilken procentværdi der skal angives, og gemmer det i pct
set_servo_procent(pct)
end loop
Softwaren ligger i en ZIP-fil med modulet og et Demo eksempel som illustrerer funktionen.
Demokoden til servomodulet
Koden er lavet til at vise temperaturen på et ALCD display, så i initialiseringen hentes disse to moduler ind:
include ALCD
ALCD_clear_screen() -- (to first line)
include Servo
Herefter køres der i et forever-loop, hvor procentværdien kan køres i begge retninger ud fra knappen på PIC-boardet.
Hele loopet ser ud som følger:
forever loop
ALCD_cursor_position(0,0) -- start of first line
-- Skriv pct i displayet
ALCD_Dec_3(pct)
delay_100ms(3)
if kontakt then
pct = pct + 1
if pct > 100 then
pct = 0
end if
else
pct = pct - 1
if pct > 100 then
pct = 100
end if
end if
set_servo_procent(pct)
end loop
Interfacefil til Servo-modulet
Der skal i interface-filen hvilket ben man ønsker output på. Det angives i Servo_def.jal som følger:
alias servo_out is pin_a2
alias servo_out_dir is pin_a2_direction
Koden i Servo modulet
I starten defineres de interne variabler i modulet og de sættes til fornuftige værdier. Outputtet sættes op, så det fungerer.
Herefter kommer initialiseringen af interruptet.
Den indstiller de to justerbare delere, hvor post-scaleren indstilles efter clock-frekvensen, og prescaleren indstilles til fast at dele med 4.
Herefter aktiveres timer 2, så den tæller og interruptet enables gennem de ekstra interrupt, inden det globale interrupt slås til.
Initialiseringen af interruptet ser ud som følger:
-- Indstil timer 2 til at bestemme pulslængde
if target_clock == 4_000_000 then
T2CON_TOUTPS = 0b_0010 -- Postscaler til / 3
elsif target_clock == 8_000_000 then
T2CON_TOUTPS = 0b_0101 -- Postscaler til / 6
elsif target_clock == 20_000_000 then
T2CON_TOUTPS = 0b_1110 -- Postscaler til / 15
else
pragma error "Oscillatorfrekvens ikke defimeret"
end if
T2CON_TMR2ON = true -- Tænd timer 2
T2CON_T2CKPS = 0b_01 -- Prescale 4
PIE1_TMR2IE = true -- Enable interrupt
INTCON_PEIE = true -- Aktiver ekstra interrupt (bl.a. timer 2)
INTCON_GIE = true -- Enable alle interrupt
Timer-interruptet skrives som en interrupt-rutine, som det vises i den efterfølgende kode.
Først filtreres ud, så den kun reagerer på timer2 inetrrupt, det gøres for at modulet kan eksistere sammen med andre interrupts.
Så tælles statet frem og der skilles ad hvor man er henne i sekvensen.
State 1 starter den pause der er efter pulsen op til 2124 us.
State 2-8 er den lange del af pausen.
State 9 er starter selve pulsen, og genstarter sekvensen.
procedure timer_2_int is pragma interrupt
if PIR1_TMR2IF then -- Reager på Timer 2 interrupt
PIR1_TMR2IF = false
servo_state = servo_state + 1 -- Næste trin i interruptet
if servo_state == 1 then -- I førate trin
servo_out = low -- stop pulsen
if servo_pause == 0 then -- hvis der ikke er mere tilbage af de 2 ms
servo_state = 2 -- gå til næste trin
PR2 = 177 -- sæt intervallet til 2 ms
else
PR2 = servo_pause -- ellers aktiver resten af de 2 ms
end if
elsif servo_state == 2 then -- for resten af pausen fortsæt i 2ms
PR2 = 177 -- intervaller
elsif servo_state == 9 then
servo_out = high -- Afslut efter 16 ms og start en ny puls
servo_state = 0
PR2 = servo_puls
end if
end if
end procedure
Service-rutinen set_servo_procent indstiller de to tider for pulsen og pausen efter pulsen, så man kan interface modulet ved blot at angive den procent-værdi man ønsker modulet skal stå på.
-- Servicerutine - kaldes fra hoved-koden
procedure set_servo_procent (byte in procent) is
if procent > 100 then -- Begræns procenten til mellem 0 og 100
procent = 100
end if
servo_puls = 77 + procent -- sæt pulstiden til mellem 1 og 2 ms
servo_pause = 177 - servo_puls -- sæt pausetiden til resten af de 2 ms
end procedure
Referencer
Tastaturer | Displays | AD-konvertering | I/O-ekspander | Serielt | Interface | Færdige | Andre |
---|---|---|---|---|---|---|---|
RC-tast - AD-tast - M_tast | ALCD - LCD | ADC_holst - ADC mcp3201 - mcp3208 |
input - output | Seriel_holst - Serial hardware Serial hw int cts - Serial software |
Stepmotor - RFID RGB - RF-link - Afstand |
Humidity - Analog temp - Dig temp Accelerometer |
Rotary Encoder |