Servo

Fra Kommunikation-IT Holstebro HTX
Skift til: navigering, søgning
Servomotor til anvendelse i f.x. fly

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:

Servo-pulse.png
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:

Servo-timing.png
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

  1. Artikel om servoer fra Lehigh university
  2. Arduinos tutorial om Servoer
Moduler på Holstebro HTX
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