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
Jeg 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.
Samlingen er fikst lavet så motorerne / hjulene bliver holdt af nogle plexiglasstumper.
Motor / gearkasse er fint integreret og ultra simple.
Motor driver
H-bro
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…
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.
Jeg 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.
Til 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.
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:
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.
“FastPWM”: Tæller fra 0 til 255 og starter så forfra. Output Capture giver dermed ét skift per kanal per periode.
“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.
Den 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:
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:
Varierende dutycycle -max til +max:
Igen varierende – tættere på med PWM detaljer:














Gul: rising / falling flanke




Der var den centralt placeret til at modtage “tryk” fra afbrydere (der skulle opgraderes med en fjeder) og havde adgang til lamperne der skulle styres. Mock-up og prototyperne på billederne er af dette modul. Vi designede et ret fedt koncept hvor printene fungerede både som køleflader og stik-forbindelser.



Arduino er et “format” som reelt bare dækker over en Atmel ATmega processer hvor det grundlæggende (oscillator og forsyning) ligger på boardet og alle pins er ført ud til pinheaders så det er nemt at slutte andre enheder til.
Stifterne bag Arduino røg for nogle år siden i totterne på hinanden. Det var noget med at de hver især mente at eje domæne og registrerede varemærker. Så i dag kan Arduino også købes under navnet Genuino…
Arduino giver faktisk ret meget for pengene. Og kan man ikke være i formatet kan man skifte til Arduino Mega2560 der er baseret på ATmega2560. Den har 16 analoge inputs og 54 digitale i/o. Det kan man hurtigt få lyst til hvis man begynder at sætte display, 2-3 temperatursensorer, relæudgange og andet sjov på samme controller…
Uanset hviket miljø man vælger er der utroligt mange ting der bare virker “out of the box”. Ting man som traditionel udvikler selv må klare – såsom biblioteker med adgang til hardwaren og håndtering af interrupts etc. Alt det og meget mere er der taget hånd om – men som gammel embedded udvikler kræver det altså lidt tilvænning ikke at have indflydelse på alting 🙂
Et lille tip til brug af ebay… Hvis du vælger “Lowest price + P&P” så får du alle dem med gratis fragt 🙂 først i listen.
Nano har ikke indbygget USB-adaptor – så det første var at slutte USB-serial port til. Det var ret nemt 🙂 – 6 ben lige igennem. Det er her “female to female jumper cables” kommer i brug. Det er en dejligt nem måde at klaske ting sammen på. Ikke egnet til den endelige applikation men fin til test.
Jeg stod for nylig med en udfordring – en af mine arduino sensorer holdt op med at virke når jeg kommunikerede med den for hurtigt… Min eneste indsigt i kommunikationen var gennem det softwaren gav – og det bragte mig ikke videre… Interfacet er via SPI som jeg bit-banger – dvs. styrer manuelt i stedet for at bruge den indbyggede SPI-controller i ATmega microcontrolleren.

Da jeg fik den opstod der ca. en halv times total forvirring om drivere. Pulseview ville ikke genkende min logikanalysator… Det viste sig at Hobby Components har lavet en opdatering i efteråret og forvirringen skyltes dels at jeg ikke vidste hvilken version jeg havde og dels at jeg ikke tænkte på at tage USB-stikket ud og ind og genstarte Pulseview flere gange. Så – hermed viderebragt 🙂



Tiden bliver så samplerate * samples… “Run” knappen sætter det hele i gang. Hvis man ikke gør andet starter sampling med det samme – men man kan også definere triggere. Det gøres ved at clicke på et signal og definere hvilke flanker der skal fungere som triggere.











