Robotbil del 1 (Chassis / hjul / motor / motordriver)

Når man vil bygge en robotbil er der forskellige elementer man skal have styr på…

  • Chassis / hjul / motor
  • Motor driver
  • Hastighedsbestemmelse / obstackle detection
  • Navigation / intelligens…

Denne blog handler om Chassis, motor og motordrive

Chassis / hjul / motor

robotbilJeg fandt et kit på ebay – så det tænkte jeg var et godt udgangspunkt 🙂

Hvis du vil finde den på ebay så søg efter “Robot Car Chassis Kit”. Den koster 4-10 GPB.

Bemærk at en del af de kit man kan få er uden speed encoder skiverne. Det er lidt ærgerligt at få fat i et kit uden…

Den jeg bestilte var MED encodere… Desværre var de ikke med i kassen :-(. Jeg skrev til leverandøren og de ville sende mig et nyt kit – men med 20-30 dages shipping så får man jo gråt hår inden den dukker op…

Kittet inkluderer chassis, hjul, 2x gearet dc-motor, møbelhjul (forhjul) og speed encoder skiver.

20160213_203652Samlingen er fikst lavet så motorerne / hjulene bliver holdt af nogle plexiglasstumper.
Motor / gearkasse er fint integreret og ultra simple.

 

Motor driver

H-bro

2016-02-13 (2)Motoren er en 3-6V DC-motor. Det betyder at man kan bruge PWM (pulsbredde modulation) til at justere hastigheden og fortegnet kan vende retningen.

For at kunne justere både pulsbredde og fortegn så bruger man en såkaldt H-bro. En H-bro er et kredsløb som gør at hver side af motorviklingen kan sættes til hhv. 0V og 5V. Det samme kunne man jo principelt opnå ved at bruge to digitale udgange direkte – med den lille detalje at de digitale udgange ikke kan levere strøm nok til det…

2016-02-13 (5)Der er en lille detalje man er nødt til at tage hensyn til “i den virkelige verden”. Nemlig det at en transistor (eller FET) tager lidt tid om at gå fra on til off og tilbage igen. Som vist i billedet betyder det at både A og B er tændt samtidig i et kort stykke tid. Med andre ord er der det man kalder “gennemtænding”. Når der både er strøm og spænding samtidig vil der afsættes effekt i transistoren. Det holder de sjældent til i længden… En yderligere detalje er at de fleste transistorer og FET’er er hurtigere til at tænde end til at slukke.

Løsningen er at lægge et “dead band” ind. Altså et kort stykke tid fra den ene er sat off før man tænder den anden. Tiden er meget afhængig af transistor/FET valget – men ofte i omegnen af 1-2us.

Når man skal dimensionere sin H-bro har man brug for at vide hvor meget strøm motoren trækker. Man har dels brug for at vide hvad motoren trækker ved “normal” belastning – men også worstcase. Det værste der kan ske er at moteren bliver blokeret da det betyder at der er en kortslutning af motoren. Så er det kun den ohmske-modstand i motoren og forsyningens kapacitet der begrænser strømmen.

En hurtig måling med 6V og hhv. belastet og blokeret motor viser at strømmen er ca. 250mA ubelastet, 800mA tungt belastet, 1A lige før blokering, 1.3A blokeret.
L9110SJeg har købte nogle H-broer færdige på Ebay. Søg på “arduino L9110” og “arduino L298N”. Begge er 2-kanals hvilket vil sige at de hver har 2 H-broer og dermed kan styre to motorer.

L9110 kan drive 800 mA kontinuert (2A peak) på hver kanal. Forsyningsspændingen skal ligge mellem 2,5-12V.
L298N kan levere 2A continous, 3A peak, supply 2.5-46V.

Det fede ved begge moduler er at de klarer det praktiske omkring dødbånd – så det eneste vi skal er at sende en PWM til hver side af H-broen.

L298NTil denne applikation er det fikst at vi kan drive begge motorer med samme modul.

De markedsføres nogle steder som “stepper drivers”. Hvis man vælger at “håndstyre” stepmotorer kan man også gøre det med en enkelt af driverne. Personligt foretrækker jeg godt nok at slippe for at skulle styre pulstogene til stepmotoren – altså ved at bruge en driver der tager sig af det praktiske… En blog om stepmotorer kommer senere.

Nå – men den “lille” – L9110 – er helt fin til disse motorer – så den monterer jeg.

20160214_135035

L298N ligger på bordet ved siden af.

Hastighedskontrol – PWM

Helt kort om PWM – pulsbreddemodulation. Det går helt enkelt ud på at hvis man har et signal med konstant frekvens men varierer pulsbredden, så vil gennemsnittet blive afhængigt af pulsbredden. Det kan bruges til at bestemme lysstyrken på en pære eller lysdiode – eller justere hastigheden på en motor.

De 4 styresignaler er parvis inverterede – A og B i forhold til C og D. Tænder man både A og B (eller C og D) vil det give en kortslutning af forsyningsspændingen. Som nævnt håndterer hardwaren denne kompleksitet – så styringen kan nøjes med at fokusere på A og C signalerne.

Spændingen over motoren er differencen mellem A/B og C/D:

2016-02-13 (4)

Så – så længe broen er i 50% dutycycle på både A/B og C/D vil spændingen over motoren være 0V. Først når broen går “ud af balance” – altså at A/B siden kører med anderledes pulsbredde end C/D siden. Hvis A/B siden er mere “positiv” end C/D vil resultatet være at motoren oplever en positiv spænding. Omvendt hvis C/D-siden er mest positiv vil motoren opleve negativ spænding – og dreje “baglæns”…

Arduino PWM-kontrol

PWM funktionen er linket til ATmega processorerens timere. Jeg har ledt rundt – men det er ikke så nemt at finde et simpelt library… Der er nogle guides – men jeg tror at fordi der er så mange muligheder så er det svært at lave et ordentligt generelt library. OG det er nogle rasende avancerede enheder – så det jeg beskriver herunder er kun en lille flig af helheden – den flig jeg skal bruge 🙂

Der er tre timere i ATmega 328. De fleste funktioner virker på alle tre timere – så jeg bruger notationen “x” hvis det er underordnet hvilket register der vælges.

Det smarte ved at der er to compare registre per timer er at man kan få to ben til at vippe synkront – det skal vi bruge :-). Det man bruger når man skal have en timer til at virke som PWM-kanal er “output capture”-funktionalitet. Der er to compare registre – dem benævner jeg “y” når det ikke er vigtigt hvilket af registrene der anvendes. Output Compare går helt enkelt ud på at sammenligne et compare register (OCxy) med timerens værdi (TCNTx). Når de er ens sættes det tilknyttede “flag” (OCFxy). Afhængigt af settings for “waveform generatoren”  kan dette flag kobles sammen med et output ben – og voila har vi et PWM output.

Der er to PWM-modes: “Fast PWM” og “Phase correct PWM”. Forskellen er illustreret her.

2016-02-14

“FastPWM”: Tæller fra 0 til 255 og starter så forfra. Output Capture giver dermed ét skift per kanal per periode.

 

2016-02-14 (1)

“Phase correct PWM”: Tæller fra 0-255-0. Det betyder at der er to skift per periode per kanal. Perioden er dog den dobbelte af fast-pwm og det vigtigste er at outputtet er symmetrisk. Dvs. begge flanker flytter når output capture registeret ændres.

Phase correct PWM er fint i mange situationer – men uden betydning her – så jeg holder mig til Fast PWM.

MEN MEN MEN… Og det er så her bagsiden af Arduino rammer en i nakken hvis man ikke er opærksom… Arduino er før med et 1kHz interrupt der søger for at delay() funktionen virker. Dette interrupt hænger på timer 0 – så hvis man bruger den til pwm – og sætter frekvensen til andet end SCLK/64 – ja så vil delay() ikke give korrekte forsinkelser længere…

PWM outputs

Hver timer er relateret til nogle ben:

Timer Pins
0  5, 6
1 9, 10
2 3, 11

Register configuration

TCCRxA (Timer/Counter Control Register A):

7 6 5 4 3 2 1 0
COMxA1 COMxA0 COMxB1 COMxB0 WGMx1 WGMx0
1 0 1 0 0 0 1 1

Se herunder for detaljer om begge control registrene.

TCCRxB (Timer/Counter Control Register B):

7 6 5 4 3 2 1 0
FOCxA FOCxB WGMx2 CSx2 CSx1 CSx0
0 0 0 0 0  X  X  X

COMxy[1:0] – Compare output match; non-inverting: 0b10

WGMx[2:0] – Waveform generation mode; Fast PWM; 0-255 count: 0b011

FOCxy – Not used in PWM mode: 0b00

CSx[2:0] – Clock source; afhænger af den valgte timer (bemærk at det tager 256 cycles at foretage en komplet cycle):

Clock source Timer 0

CS0[2:0]

Timer 1

CS1[2:0]

Timer 2

CS1[2:0]

Off 0b000 0b000 0b000
SCLK/1 (62.5 kHz) 0b001 0b001 0b001
SCLK/8 (7812.5 Hz) 0b010 0b010 0b010
SCLK/32 (1953.1 Hz) NA NA 0b011
SCLK/64 (976.6 Hz) 0b011 0b011 0b100
SCLK/128 (488.3 Hz) NA NA 0b101
SCLK/256 (244.1 Hz) 0b100 0b100 0b110
SCLK/1024 (61.0 Hz) 0b101 0b101 0b111

TCNTx (Timer/Counter Register):

Momentan timer værdi. Timer 0 og 2 er 8 bit. Timer 1 er 16 bit.

Dette register skal man normalt ikke bruge i PWM-mode. Det kører frihjul af sig selv…

OCRxy (Output capture register):

PWM-værdi. Timer 0 og 2 er 8 bit. Timer 1 er 16 bit. 1 er en smal puls 255 (eller 65535 for Timer 1) er fuld bredde (all-on).

Strømforsyning

Dummefejl… Eller i hvert fald ubetænksomhed… Da jeg testede mit library snurrede hjulene fint – i 1-2 sekunder hvorefter printet rebootede…
Meeeen – nu var min opstilling strømforsynet fra USB… Og USB kan ikke levere motorernes startstrøm… Desuden havde jeg ikke sat nogen ekstra kapacitet (kondensator) på ude ved H-broen. Så alle strømtræk (dynamiske som statiske) skulle gennem Arduino-printets USB forsyning. Ikke smart.

20160220_092124Den dårlige undskyldning er selvfølgelig at jeg ikke tænkte på det fordi mit robot-kit blev leveret uden (ved en fejl)… Jammerligt dårlig undskyldning 🙂

Så – jeg hittede nogle forsyningsledninger til batterier…

C++ library

Såe… jeg har klappet et simpelt library sammen med det ene formål at styre én H-bro med to PWM-kanaler.

Du kan hente h-bro library’et (med eksemple) her: Download

Kernen i biblioteket er konfiguration og ændring af dutycycle. Her i en forsimplet kode:

Interfacet er en klasse (class):

Her en stump testkode der skifter fra -100% til +100% og tilbage igen:

Du kan ændre til timer 0 i linje 3.
Hastigheden der ændres med kan ændres i de to linjer med “sign=+/-10”.

Test af biblioteket

Testene er lavet med min USB-logikanalysator (se mere her: link).

50% dutycycle og så skulle jeg lige vise PWM signal analysatoren i Pulseview:

2016-02-20

Der er to lidt bemærkelsesværdige observationer her. For det første burde frekvensen være 976.6Hz (16MHZ/256/64) – men den er faktisk 1 kHz (freq = 1/periode; f=1/1ms=1kHz). Det er lidt uklart for mig hvorfor. Det må jeg lige grave i på et andet tidspunkt. Det andet interessante er at dutycyclen er 50.39Hz og ikke 50.00%. Årsagen er at dutycyclen for 50% er 128. 0 er 0%; 255 er 100%. Hældningskvotienten er alpha=100/255 så ved 128 får vi y=alpha*x= 50.20%. 127 giver 49.80%.

En del af fejlen skyldes dog også at jeg brugte for lille sample rate i pulseview…

Høj dutycycle:

2016-02-20 (1)

Varierende dutycycle -max til +max:

2016-02-20 (2)

Igen varierende – tættere på med PWM detaljer:

2016-02-20 (4)