- Kredsløbsdiagram
- Generering af PWM-signaler på GPIO-pin til servomotorstyring
- Programmering PIC16F8771A til robotarm
- Simulering af PIC-robotarmkode
- PCB-design ved hjælp af EasyEDA
- Beregning og bestilling af prøver online
- Arbejde med PIC Robotic Arm
Fra samlebåndet i bilindustrien til telekirurgirobotterne i rummet findes robotarmene overalt. Mekanismerne i disse robotter ligner et menneske, som kan programmeres til lignende funktion og øgede kapaciteter. De kan bruges til at udføre gentagne handlinger hurtigere og mere præcist end mennesker eller kan bruges i barske miljøer uden at risikere menneskeliv. Vi har allerede bygget en Record and Play Robotic Arm ved hjælp af Arduino, som kunne trænes i at udføre en bestemt opgave og fået til at gentage for evigt.
I denne vejledning bruger vi industristandarden PIC16F877A 8-bit Microcontroller til at styre den samme robotarm med potentiometre. Udfordringen med dette projekt er, at PIC16F877A kun har to PWN-kompatible ben, men vi har brug for at kontrollere omkring 5 servomotorer til vores robot, som kræver 5 individuelle PWM-ben. Så vi er nødt til at bruge GPIO-benene og generere PWM-signaler på PIC GPIO-ben ved hjælp af timer-afbrydelser. Nu kunne vi selvfølgelig opgradere til en bedre mikrocontroller eller bruge en de-multiplexer IC for at gøre tingene meget lettere her. Men alligevel er det værd at prøve dette projekt på læringsoplevelsen.
Den mekaniske struktur af robotarmen, som jeg bruger i dette projekt, blev fuldstændigt 3D-trykt til mit tidligere projekt; Du kan finde de komplette designfiler og samleproceduren her. Alternativt, hvis du ikke har en 3D-printer, kan du også bygge en simpel robotarm ved hjælp af pap som vist i linket. Forudsat at du på en eller anden måde har fået fat i din robotarm, kan vi fortsætte med projektet.
Kredsløbsdiagram
Det komplette kredsløbsdiagram for denne PIC Microcontroller-baserede robotarm er vist nedenfor. Skemaerne blev tegnet ved hjælp af EasyEDA.
Kredsløbsdiagrammet er ret simpelt; hele projektet er drevet af 12V adapteren. Denne 12V konverteres derefter til + 5V ved hjælp af to 7805 spændingsregulatorer. Den ene er mærket som + 5V, og den anden er mærket som + 5V (2). Årsagen til at have to regulatorer er, at når servoen roterer, trækker den meget strøm ind, hvilket skaber et spændingsfald. Dette spændingsfald tvinger PIC'en til at genstarte sig selv, og derfor kan vi ikke betjene både PIC og servomotorer på den samme + 5V-skinne. Så den, der er mærket som + 5V, bruges til at drive PIC-mikrocontroller, LCD og potentiometre, og en separat regulatorudgang, der er mærket som + 5V (2), bruges til at drive servomotorer.
De fem udgangsben på potentiometrene, der tilvejebringer en variabel spænding fra 0V til 5V, er forbundet til de analoge ben An0 til AN4 i PIC. Da vi planlægger at bruge timere til at generere PWM, kan servomotorer tilsluttes enhver GPIO-pin. Jeg har valgt ben fra RD2 til RD6 til servomotorer, men det kan være enhver GPIO efter eget valg.
Da programmet involverer meget fejlretning, er en 16x2 LCD-skærm også grænseflade til portB på PIC. Dette viser driftscyklussen for de servomotorer, der styres. Bortset fra dette har jeg også udvidet forbindelser til alle GPIO og analoge ben, bare i tilfælde af at sensorer skal grænseflade i fremtiden. Endelig har jeg også tilsluttet programmeringsstift H1 for direkte at programmere PIC med pickit3 ved hjælp af ICSP-programmeringsmuligheden.
Generering af PWM-signaler på GPIO-pin til servomotorstyring
Når kredsløbet er klart, skal vi finde ud af, hvordan vi genererer PWN-signaler på GPIO-stiften på PIC for at styre servomotoren. Vi har allerede træt noget lignende ved hjælp af Timer interrupt-metoden og havde succes. Her skal vi bare bygge oven på det, så hvis du er ny her, vil jeg kraftigt anbefale dig at læse denne tidligere vejledning, inden du fortsætter videre.
Alle hobby servomotorer arbejder med en frekvens på 50Hz. Det betyder, at en komplet pulscyklus for en servomotor er 1/50 (F = 1 / T), hvilket er 20 ms. Af disse komplette 20 ms er styresignalet kun fra 0 til 2 ms, mens resten af signalet altid er slukket. Nedenstående figur viser, hvordan ON-tiden kun varierer fra 0 til 2 ms for at rotere motoren fra 0 grader til 180 grader af den samlede varighed på 20 ms.
Med dette i tankerne er vi nødt til at skrive programmet på en sådan måde, at PIC læser i 0 til 1204 fra potentiometeret og kortlægger det til 0 til 100, hvilket er servomotorens driftscyklus. Ved hjælp af denne driftscyklus kan vi beregne servomotorens ON-tid. Derefter kan vi initialisere timer-afbrydelsen for at løbe over med et regelmæssigt interval, så den fungerer svarende til millis () -funktionen i Arduino. Med det kan vi skifte status GPIO-pin til at være høj i en ønsket varighed og slukke for den efter 20 ms (en komplet cyklus) og derefter gentage den samme proces. Nu hvor vi har forstået logikken, lad os komme ind i programmet.
Programmering PIC16F8771A til robotarm
Som altid kan det komplette program med en video findes i slutningen af denne side, kode kan også downloades herfra med alle de nødvendige filer. I dette afsnit vil vi diskutere logikken bag programmet. Programmet anvender ADC-modulet, timermodulet og LCD-modulet til at styre robotarmen. Hvis du ikke er klar over, hvordan du bruger ADC-funktionerne eller Timer-funktionerne eller til at interface en LCD med PIC, kan du falde tilbage til de respektive links for at lære dem. Nedenstående forklaring gives under forudsætning af, at læseren er fortrolig med disse begreber.
Timer 0-portkonfiguration
Det vigtigste afsnit i koden er at indstille Timer 0 til overflow for hver specifik forsinkelse. Formlerne til beregning af denne forsinkelse kan gives som
Forsinkelse = ((256-REG_val) * (Prescal * 4)) / Fosc
Ved at bruge OPTION_REG og TMR0 registeret har vi indstillet Timer 0 til at fungere med en prescalar værdi på 32, og REG val er indstillet til 248. Krystalfrekvensen (Fosc), der bruges i vores hardware er 20 MHz. Med disse værdier kan forsinkelsen beregnes som
Forsinkelse = ((256-248) * (32 * 4)) / (20000000) = 0,0000512 sekunder (eller) = 0,05 msek
Så nu har vi indstillet timeren til at løbe over ved hver 0,05 ms. Koden til at gøre det samme er angivet nedenfor
/ ***** Portkonfiguration til timer ****** / OPTION_REG = 0b00000100; // Timer0 med ekstern freq og 32 som prescalar // Aktiverer også PULL UPs TMR0 = 248; // Indlæs tidsværdien for 0,0001s; delayValue kan være mellem 0-256 kun TMR0IE = 1; // Aktivér timerinterruptbit i PIE1-registeret GIE = 1; // Aktiver Global Interrupt PEIE = 1; // Aktivér den perifere afbrydelse / *********** ______ *********** /
Ud af servomotorens samlede 0 ms til 2 ms kontrolvindue kan vi styre det med en opløsning på 0,05 ms, hvilket giver os mulighed for at have (2 / 0,05) 40 forskellige positioner for motoren mellem 0 grader og 180 grader. Du kan reducere denne værdi yderligere, hvis din MCU kan understøtte den for at opnå flere positioner og præcis kontrol.
Interrupt Service Routine (ISR)
Nu hvor vi har Timer 0 indstillet til overflow for hver 0,05 ms, vil vi have TMR0IF-afbrydelsesflaget sat til 0,05 ms. Så inden i ISR-funktionen kan vi nulstille det flag og forøge en variabel kaldet count by one. Så nu øges denne variabel med 1 for hver 0,05 ms.
ugyldig afbryd timer_isr () { hvis (TMR0IF == 1) // Timer-flag er udløst på grund af timeroverløb -> indstillet til overløb for hver 0,05 ms { TMR0 = 248; // Indlæs timeren Værdi TMR0IF = 0; // Ryd timer afbryde flagantal ++; // Tæl intervaller med 1 for hver 0,05 ms }
Beregning af arbejdscyklus og tid
Derefter skal vi beregne arbejdscyklus og til tiden for alle fem servomotorer. Vi har fem servomotorer, som hver bruges til at styre den enkelte armsektion. Så vi er nødt til at læse ADC-værdien af alle fem og beregne driftscyklus og til tiden for hver.
ADC-værdien vil være i området fra 0 til 1024, som kan konverteres til 0% til 100% arbejdscyklus ved simpelthen at multiplicere 0,0976 (100/1024 = 0,0976) til den opnåede værdi. Denne 0 til 100% driftscyklus skal derefter konverteres til ON-tid. Vi ved, at ved 100% driftscyklus skal ON-tiden være 2 ms (i 180 grader), så multiplicering af 0,02 (2/100 = 0,02) vil konvertere 0 til 100 driftscyklus til 0 til 2 ms. Men så er vores timervariabeltal indstillet til at stige en gang for hver 0,05 ms. Dette betyder, at tællingsværdien vil være 20 (1 / 0,05 = 20) for hver 1 ms. Så vi er nødt til at multiplicere 20 med 0,02 for at beregne det nøjagtige tidspunkt for vores program, som giver os værdien 0,4 (0,02 * 20 = 0,4). Koden for det samme er vist nedenfor, du kan se det gentages 5 gange for alle 5 potter ved hjælp af en for loop. De resulterende værdier er gemt i T_ON-arrayet.
for (int pot_num = 0; pot_num <= 3; pot_num ++) { int Pev_val = T_ON; POT_val = (ADC_Read (pot_num)); // Læs værdien af POT ved hjælp af ADC Duty_cycle = (POT_val * 0,0976); // Kort 0 til 1024 til 0 til 100 T_ON = Duty_cycle * 0,4; // 20 * 0,02
Valg af, hvilken motor der skal drejes
Vi kan ikke kontrollere alle fem motorer sammen, da det vil gøre ISR-koden tung og bremse hele mikrocontrolleren. Så vi skal kun dreje en servomotor ad gangen. For at vælge, hvilken servo der skal roteres, overvåger mikrokontrolleren ON-tiden for alle fem servomotorer og sammenligner den med den forrige tid. Hvis der er en ændring i ON-tiden, kan vi konkludere, at den bestemte servo skal flyttes. Koden for det samme er vist nedenfor.
hvis (T_ON! = Pev_val) { Lcd_Clear (); servo = pot_num; Lcd_Set_Cursor (2,11); Lcd_Print_String ("S:"); Lcd_Print_Char (servo + '0'); hvis (pot_num == 0) {Lcd_Set_Cursor (1,1); Lcd_Print_String ("A:");} ellers hvis (pot_num == 1) {Lcd_Set_Cursor (1,6); Lcd_Print_String ("B:");} ellers hvis (pot_num == 2) {Lcd_Set_Cursor (1,11); Lcd_Print_String ("C:");} ellers hvis (pot_num == 3) {Lcd_Set_Cursor (2,1); Lcd_Print_String ("D:");} ellers hvis (pot_num == 4) {Lcd_Set_Cursor (2,6); Lcd_Print_String ("E:");} char d2 = (Duty_cycle)% 10; char d1 = (Duty_cycle / 10)% 10; Lcd_Print_Char (d1 + '0'); Lcd_Print_Char (d2 + '0');
Vi udskriver også servo duty cycle på LCD-skærmen, så brugeren kunne være opmærksom på sin aktuelle position. Baseret på ændringen i ON-tid opdateres den variable servo med tal fra 0 til 4, der hver repræsenterer individuelle motorer.
Styring af servomotor inde i ISR
Inde i ISR har vi variabeltællingen stigende for hver 0,05 ms, det betyder, at for hver 1 ms vil variablen blive forøget med 20. Brug af dette er vi nødt til at kontrollere benene til at producere PWM-signal. Hvis tællingsværdien er mindre end til tiden, tændes motorens GPIO ved hjælp af nedenstående linje
PORTD = PORTD - servokode;
Her har array servo_code pin-detalje for alle fem servomotorer og baseret på værdien i variabel servo, vil koden for den pågældende servomotor blive brugt. Det er derefter logisk ELLER (-) med eksisterende PORTD-bits, så vi ikke forstyrrer værdierne for anden motor og kun opdaterer denne bestemte motor. Tilsvarende til at slukke for stiften
PORTD = PORTD & ~ (servokode);
Vi har vendt bitværdien ved hjælp af den logiske inverse (~) operator og har derefter udført en AND (&) -operation på PORTD for kun at slukke for den ønskede pin, mens de andre ben forlades i deres tidligere tilstand. Det komplette kodestykke vises nedenfor.
ugyldig afbrydelse timer_isr () { hvis (TMR0IF == 1) // Timer-flag er udløst på grund af timeroverløb -> indstillet til overløb for hver 0,05 ms { TMR0 = 248; // Indlæs timeren Værdi TMR0IF = 0; // Ryd timer afbryde flagantal ++; // Tæl forøgelser med 1 for hver 0,05 ms -> tællingen vil være 20 for hver 1 ms (0,05 / 1 = 20)) } int servo_code = {0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100}; hvis (count> = 20 * 20) count = 0; hvis (count <= (T_ON)) PORTD = PORTD - servokode; ellers PORTD = PORTD & ~ (servo_code); }
Vi ved, at den samlede cyklus skal vare i 20 ms, før GPIO-stiften tændes igen. Så vi kontrollerer, om optællingen har overskredet 20ms ved at sammenligne tællingsværdien med 400 (samme beregning som beskrevet ovenfor), og hvis ja, skal vi initialisere optællingen til at være nul igen.
Simulering af PIC-robotarmkode
Det er altid bedre at simulere koden, før du tager den til den rigtige hardware. Så jeg brugte Proteus til at simulere min kode og bekræftede, at den fungerede korrekt. Kredsløbet, der bruges til simulering, er vist nedenfor. Vi har brugt et oscilloskop til at kontrollere, om PWM-signalerne genereres efter behov. Vi kan også kontrollere, om LCD- og servomotorer roterer som forventet.
Som du kan se LCD-skærme pligt cyklus af motor D til at være 07 baseret på gryden værdi, som er den 3 rd motor. Lignende, hvis en anden gryde flyttes, vises grydsens arbejdscyklus og dens motornummer på LCD'et. PWM-signalet vist på oscilloskopet er vist nedenfor.
Den samlede cyklusperiode måles til at være 22,2 ms ved hjælp af markørindstillingen på oscilloskopet, som er meget tæt på de ønskede 20 ms. Endelig er vi sikre på, at koden fungerer, så for at fortsætte med kredsløbet kan vi enten lodde den på et perf-kort eller bruge et printkort. Det fungerer ikke let på brødbrættet, fordi POT'en altid har tendens til at give nogle problemer på grund af dårlige forbindelser.
PCB-design ved hjælp af EasyEDA
For at designe denne PIC-robotarm har vi valgt det online EDA-værktøj kaldet EasyEDA. Jeg har brugt det i lang tid nu og finder det meget praktisk på grund af dets store tilgængelighed af fodaftryk og let at bruge naturen. Efter design af PCB kan vi bestille PCB-prøver ved hjælp af deres billige PCB-fabrikationstjenester. De tilbyder også komponentsourcingtjeneste, hvor de har et stort lager af elektroniske komponenter, og brugere kan bestille deres nødvendige komponenter sammen med printkortordren.
Mens du designer dine kredsløb og printkort, kan du også gøre dit kredsløb og printkortdesign offentligt, så andre brugere kan kopiere eller redigere dem og drage fordel af dit arbejde, vi har også gjort vores hele kredsløbs- og printkortlayouts offentlige for dette kredsløb, tjek nedenstående link:
easyeda.com/circuitdigest/pic-development-board-for-robotic-arm
Ved hjælp af dette link kan du direkte bestille det samme printkort, som vi bruger i dette projekt, og bruge det. Når designet er færdigt, kan tavlen ses som 3D-model, hvilket vil være meget nyttigt at visualisere, hvordan tavlen ser ud efter fabrikation. 3D-modellen af det kort, vi bruger, er vist nedenfor. Bortset fra dette kan du også se det øverste og nederste lag på tavlen for at kontrollere, om den glatte skærm er som forventet.
Beregning og bestilling af prøver online
Efter at have afsluttet designet af denne PIC Robot PCB, kan du bestille printkortet via JLCPCB.com. For at bestille printkortet fra JLCPCB skal du have Gerber File. For at downloade Gerber-filer på din PCB skal du blot klikke på Generer fabrikationsfil- knappen på EasyEDA-redigeringssiden, og derefter downloade Gerber-filen derfra, eller du kan klikke på Bestil på JLCPCB som vist i billedet nedenfor. Dette omdirigerer dig til JLCPCB.com, hvor du kan vælge antallet af printkort, du vil bestille, hvor mange kobberlag du har brug for, PCB-tykkelsen, kobbervægt og endda PCB-farven, som det viste øjebliksbillede:
Når du har valgt alle indstillingerne, skal du klikke på "Gem i kurv" og derefter føres til den side, hvor du kan uploade din Gerber-fil, som vi har downloadet fra EasyEDA. Upload din Gerber-fil og klik på "Gem i kurv". Og endelig klik på Checkout sikkert for at gennemføre din ordre, så får du dine printkort et par dage senere. De fabrikerer printkortet med meget lav hastighed, hvilket er $ 2. Deres byggetid er også meget mindre, hvilket er 48 timer med DHL-levering på 3-5 dage, dybest set får du dine printkort inden for en uge efter bestilling.
Efter bestilling af printkortet kan du kontrollere produktionsforløbet for dit printkort med dato og klokkeslæt. Du tjekker det ved at gå til kontosiden og klikke på "Produktionsfremgang".
Efter få dage med bestilling af printkort fik jeg printkortprøverne i pæn emballage som vist på nedenstående billeder.
Og efter at have fået disse stykker, har jeg loddet alle nødvendige komponenter over printkortet. Jeg lodde også direkte POTEN direkte i stedet for at bruge forbindelsesledninger, fordi de kvindelige til kvindelige ledninger, som jeg oprindeligt brugte, hvor jeg gav underlige analoge udgangsspændinger sandsynligvis på grund af løse kontakter. Når alle komponenterne var samlet, så min PCB sådan ud.
Du har måske bemærket, at der kun er en 7805 på dette tavle. Det skyldes, at jeg oprindeligt troede, at jeg kunne slippe af sted med bare regulator til at drive både PIC og servomotor, og senere indså jeg, at jeg havde brug for to. Så jeg har brugt et eksternt kredsløb til at drive servomotorer gennem de grønne ledninger, du ser her.
Ikke desto mindre behøver du ikke bekymre dig meget om det, fordi; Jeg har foretaget ændringerne af printkortet nu. Du kan gøre brug af det modificerede printkort og lodde begge regulatorer om bord selv.
Arbejde med PIC Robotic Arm
Efter alt det trættende arbejde er det tid til at betale sig. Lod alle komponenterne på tavlen, og upload programmet til PIC-controlleren. Komplet kode er angivet nedenfor eller kan downloades herfra. Programmeringskonnektoren på tavlen skal hjælpe dig med at uploade programmet direkte ved hjælp af Pickit 3 uden meget besvær. Når programmet er uploadet, skal du se LCD'et, der viser den servo, der i øjeblikket styres. For at lære mere om programmering af PIC Microcontroller, skal du bare følge den foregående vejledning.
Derfra kan du blot dreje potten og kontrollere, hvordan servomotorer reagerer på hvert potentiometer. Når du først har forstået formatet, kan du styre robotarmen til at udføre den handling, du har brug for, for at udføre og have det sjovt. Du kan finde den komplette bearbejdning af projektet i den linkede video nedenfor.
Det er det, gutter håber, at du forstod projektet og lærte noget nyt af det. Hvis du har spørgsmål, skal du lade dem være i kommentarfeltet eller bruge fora til andre tekniske diskussioner.