- Schakelschema
- PWM-signalen genereren op GPIO-pin voor servomotorbesturing
- PIC16F8771A programmeren voor robotarm
- Simulatie van PIC Robotarmcode
- PCB-ontwerp met EasyEDA
- Monsters online berekenen en bestellen
- Werking van PIC Robotarm
Van de assemblagelijn van de automobielindustrie tot de teleschirurgierobots in de ruimte, robotarmen zijn overal te vinden. De mechanismen van deze robots zijn vergelijkbaar met een mens die kan worden geprogrammeerd voor een vergelijkbare functie en verhoogde mogelijkheden. Ze kunnen worden gebruikt om herhaalde acties sneller en nauwkeuriger uit te voeren dan mensen, of ze kunnen in ruwe omgevingen worden gebruikt zonder mensenlevens te riskeren. We hebben al een Record and Play-robotarm gebouwd met Arduino die kan worden getraind om een bepaalde taak uit te voeren en die voor altijd kan worden herhaald.
In deze tutorial zullen we de industriestandaard PIC16F877A 8-bit Microcontroller gebruiken om dezelfde robotarm met potentiometers te besturen. De uitdaging bij dit project is dat de PIC16F877A slechts twee PWN-compatibele pinnen heeft, maar we moeten ongeveer 5 servomotoren voor onze robot besturen, waarvoor 5 individuele PWM-pinnen nodig zijn. We moeten dus de GPIO-pinnen gebruiken en PWM-signalen genereren op PIC GPIO-pinnen met behulp van de timer-interrupts. Nu kunnen we natuurlijk upgraden naar een betere microcontroller of een de-multiplexer IC gebruiken om het hier een stuk gemakkelijker te maken. Maar toch is het de moeite waard om dit project uit te proberen voor de leerervaring.
De mechanische structuur van de robotarm die ik in dit project gebruik, is volledig 3D geprint voor mijn vorige project; de volledige ontwerpbestanden en montageprocedure vindt u hier. Als alternatief, als u geen 3D-printer heeft, kunt u ook een eenvoudige robotarm bouwen met karton, zoals weergegeven in de link. Ervan uitgaande dat u op de een of andere manier uw robotarm in handen heeft, gaan we verder met het project.
Schakelschema
Het volledige schakelschema voor deze op PIC Microcontroller gebaseerde robotarm wordt hieronder weergegeven. Het schema is getekend met EasyEDA.
Het schakelschema is vrij eenvoudig; het complete project wordt gevoed door de 12V-adapter. Deze 12V wordt vervolgens omgezet naar + 5V met behulp van twee 7805 spanningsregelaars. De ene is gelabeld als + 5V en de andere is gelabeld als + 5V (2). De reden voor het hebben van twee regelaars is dat wanneer de servo draait, deze veel stroom trekt, waardoor een spanningsval ontstaat. Deze spanningsval dwingt de PIC om zichzelf opnieuw te starten, daarom kunnen we niet zowel de PIC als de servomotoren op dezelfde + 5V-rail bedienen. Dus degene met het label + 5V wordt gebruikt om de PIC-microcontroller, LCD en potentiometers van stroom te voorzien en een afzonderlijke regulatoruitgang die is gelabeld als + 5V (2) wordt gebruikt om de servomotoren van stroom te voorzien.
De vijf uitgangspennen van de potentiometers die een variabele spanning van 0V tot 5V leveren, zijn verbonden met de analoge pennen An0 tot AN4 van de PIC. Omdat we van plan zijn timers te gebruiken om PWM te genereren, kunnen de servomotoren op elke GPIO-pin worden aangesloten. Ik heb pinnen van RD2 tot RD6 geselecteerd voor de servomotoren, maar het kan elke GPIO van jouw keuze zijn.
Omdat het programma veel debuggen met zich meebrengt, is er ook een 16x2 LCD-scherm aangesloten op poortB van de PIC. Dit geeft de werkcyclus weer van de servomotoren die worden aangestuurd. Afgezien hiervan heb ik ook uitgebreide aansluitingen voor alle GPIO- en analoge pinnen, voor het geval dat er in de toekomst sensoren moeten worden aangesloten. Ten slotte heb ik ook de programmeerpen H1 aangesloten om de PIC direct met pickit3 te programmeren met behulp van de ICSP-programmeeroptie.
PWM-signalen genereren op GPIO-pin voor servomotorbesturing
Zodra het circuit klaar is, moeten we erachter komen hoe we PWN-signalen kunnen genereren op de GPIO-pin van PIC om de servomotor te besturen. We hebben iets soortgelijks al moe met de Timer-interrupt-methode en waren succesvol. Hier gaan we er gewoon bovenop bouwen, dus als je hier nieuw bent, raad ik je ten zeerste aan om deze vorige tutorial te lezen voordat je verder gaat.
Alle hobby- servomotoren werken met een frequentie van 50Hz. Dit betekent dat een complete pulscyclus voor een servomotor 1/50 (F = 1 / T) is, wat 20 ms is. Van deze volledige 20 ms is het stuursignaal slechts van 0 tot 2 ms terwijl de rest van het signaal altijd uit is. De onderstaande afbeelding laat zien hoe de AAN-tijd alleen varieert van 0 tot 2 ms om de motor van 0 graden tot 180 graden van de totale duur van 20 ms te laten draaien.
Met dit in gedachten moeten we het programma zo schrijven dat de PIC 0 tot 1204 van de potentiometer inleest en toewijst aan 0 tot 100, wat de inschakelduur van de servomotor zal zijn. Met behulp van deze duty-cycle kunnen we de AAN-tijd van de servomotor berekenen. Vervolgens kunnen we de timer-interrupt initialiseren zodat deze met een regelmatig interval overloopt, zodat deze op dezelfde manier werkt als de millis () -functie in Arduino. Daarmee kunnen we de status GPIO-pin hoog zetten voor een gewenste duur en deze na 20 ms (één volledige cyclus) uitschakelen en vervolgens hetzelfde proces herhalen. Nu we de logica hebben begrepen, gaan we naar het programma.
PIC16F8771A programmeren voor robotarm
Zoals altijd is het complete programma met een video te vinden aan het einde van deze pagina, ook hier kan de code worden gedownload met alle benodigde bestanden. In deze sectie bespreken we de logica achter het programma. Het programma maakt gebruik van de ADC-module, de timermodule en de LCD-module om de robotarm te besturen. Als u niet weet hoe u de ADC-functies of Timer-functies moet gebruiken of een LCD met PIC moet verbinden, dan kunt u terugvallen op de respectievelijke links om ze te leren. De onderstaande uitleg wordt gegeven in de veronderstelling dat de lezer bekend is met deze concepten.
Timer 0 poortconfiguratie
De belangrijkste sectie in de code is het instellen van de timer 0 op overflow voor elke specifieke vertraging. De formules om deze vertraging te berekenen, kunnen worden gegeven als
Vertraging = ((256-REG_val) * (Prescal * 4)) / Fosc
Door het OPTION_REG- en TMR0-register te gebruiken, hebben we de Timer 0 ingesteld om te werken met een prescalaire waarde van 32 en de REG-waarde is ingesteld op 248. De kristalfrequentie (Fosc) die in onze hardware wordt gebruikt, is 20Mhz. Met deze waarden kan de vertraging worden berekend als
Vertraging = ((256-248) * (32 * 4)) / (20000000) = 0,0000512 seconden (of) = 0,05 msec
Dus nu hebben we de timer ingesteld om elke 0,05 ms over te lopen. De code om hetzelfde te doen wordt hieronder gegeven
/ ***** Poortconfiguratie voor timer ****** / OPTION_REG = 0b00000100; // Timer0 met externe freq en 32 als prescalar // Activeert ook PULL UPs TMR0 = 248; // Laad de tijdwaarde voor 0.0001s; delayValue kan tussen 0-256 liggen alleen TMR0IE = 1; // Schakel timer-interruptbit in PIE1-register GIE = 1 in; // Schakel Global Interrupt PEIE = 1 in; // Schakel de perifere onderbreking in / *********** ______ *********** /
Van het totale besturingsvenster van 0 ms tot 2 ms van de servomotor kunnen we deze besturen met een resolutie van 0,05 ms, waardoor we (2 / 0,05) 40 verschillende posities voor de motor kunnen hebben tussen 0 graden en 180 graden. U kunt deze waarde verder verlagen als uw MCU dit zou kunnen ondersteunen om meer posities en nauwkeurige controle te verkrijgen.
Onderbrekingsserviceroutine (ISR)
Nu we Timer 0 hebben ingesteld op overflow voor elke 0,05 ms, hebben we de TMR0IF-interruptvlag ingesteld op 0,05 ms. Dus binnen de ISR-functie kunnen we die vlag opnieuw instellen en een variabele met de naam count met één verhogen. Dus nu wordt deze variabele verhoogd met 1 voor elke 0,05 ms.
void interrupt timer_isr () { if (TMR0IF == 1) // Timervlag is geactiveerd vanwege timeroverloop -> ingesteld op overloop voor elke 0,05 ms { TMR0 = 248; // Laad de timerwaarde TMR0IF = 0; // Wis timer-interruptvlaggetelling ++; // Tel wordt verhoogd met 1 voor elke 0,05 ms }
Berekening van inschakelduur en op tijd
Vervolgens moeten we de inschakelduur en op tijd berekenen voor alle vijf servomotoren. We hebben vijf servomotoren die elk worden gebruikt om een afzonderlijk deel van de arm te besturen. We moeten dus de ADC-waarde van alle vijf aflezen en de duty-cycle en op tijd voor elk berekenen.
De ADC-waarde ligt in het bereik van 0 tot 1024, wat kan worden geconverteerd naar 0% tot 100% inschakelduur door simpelweg 0,0976 (100/1024 = 0,0976) te vermenigvuldigen met de verkregen waarde. Deze inschakelduur van 0 tot 100% moet vervolgens worden omgezet in AAN-tijd. We weten dat bij een inschakelduur van 100% de AAN-tijd 2 ms moet zijn (voor 180 graden), dus vermenigvuldigen met 0,02 (2/100 = 0,02) zal 0 tot 100 inschakelduur omzetten in 0 tot 2 ms. Maar dan is het aantal timervariabelen zo ingesteld dat deze eenmaal per 0,05 ms toeneemt. Dit betekent dat de waarde van de telling 20 (1 / 0,05 = 20) zal zijn voor elke 1 ms. Dus we moeten 20 vermenigvuldigen met 0,02 om de exacte tijd voor ons programma te berekenen, wat ons de waarde 0,4 (0,02 * 20 = 0,4) geeft. De code voor hetzelfde wordt hieronder getoond, je kunt het 5 keer zien herhalen voor alle 5 de pot met een for-lus. De resulterende waarden worden opgeslagen in de T_ON-array.
for (int pot_num = 0; pot_num <= 3; pot_num ++) { int Pev_val = T_ON; POT_val = (ADC_Read (pot_num)); // Lees de waarde van POT met behulp van ADC Duty_cycle = (POT_val * 0.0976); // Kaart 0 tot 1024 tot 0 tot 100 T_ON = Duty_cycle * 0.4; // 20 * 0.02
Selecteren welke motor moet draaien
We kunnen niet alle vijf de motoren samen besturen, omdat dit de ISR-code zwaar maakt en de hele microcontroller vertraagt. We hoeven dus maar één servomotor tegelijk te draaien. Om te selecteren welke servo moet worden gedraaid, controleert de microcontroller de AAN-tijd van alle vijf servomotoren en vergelijkt deze met de vorige op tijd. Als er een verandering in de AAN-tijd is, kunnen we concluderen dat de betreffende servo moet worden verplaatst. De code voor hetzelfde wordt hieronder weergegeven.
if (T_ON! = Pev_val) { Lcd_Clear (); servo = pot_num; Lcd_Set_Cursor (2,11); Lcd_Print_String ("S:"); Lcd_Print_Char (servo + '0'); if (pot_num == 0) {Lcd_Set_Cursor (1,1); Lcd_Print_String ("A:");} else if (pot_num == 1) {Lcd_Set_Cursor (1,6); Lcd_Print_String ("B:");} else if (pot_num == 2) {Lcd_Set_Cursor (1,11); Lcd_Print_String ("C:");} else if (pot_num == 3) {Lcd_Set_Cursor (2,1); Lcd_Print_String ("D:");} else if (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');
We drukken ook de servo-duty-cycle op het LCD-scherm af, zodat de gebruiker op de hoogte kan zijn van zijn huidige positie. Op basis van de verandering in AAN-tijd wordt de variabele servo bijgewerkt met getallen van 0 tot 4 die elk afzonderlijke motoren vertegenwoordigen.
Besturen van de servomotor in de ISR
Binnen de ISR hebben we het aantal variabelen dat wordt opgehoogd voor elke 0,05 ms, dit betekent dat voor elke 1 ms de variabele wordt verhoogd met 20. Hiermee moeten we de pinnen besturen om een PWM-signaal te produceren. Als de waarde van count kleiner is dan de aan-tijd, wordt de GPIO van die motor ingeschakeld met behulp van de onderstaande regel
PORTD = PORTD - servo_code;
Hier heeft de array servo_code het pindetail van alle vijf de servomotoren en op basis van de waarde in de variabele servomotor wordt de code voor die bepaalde servomotor gebruikt. Het is dan logisch OF (-) met bestaande PORTD-bits zodat we de waarden van andere motoren niet verstoren en alleen deze specifieke motor bijwerken. Evenzo voor het uitdraaien van de pin
PORTD = PORTD & ~ (servo_code);
We hebben de bitwaarde omgekeerd met behulp van de logica-inverse (~) operator en hebben vervolgens een AND (&) -bewerking op de PORTD uitgevoerd om alleen de gewenste pin uit te schakelen terwijl de andere pinnen in hun vorige staat blijven. Het volledige codefragment wordt hieronder weergegeven.
void interrupt timer_isr () { if (TMR0IF == 1) // Timervlag is geactiveerd vanwege timeroverloop -> ingesteld op overloop voor elke 0,05 ms { TMR0 = 248; // Laad de timerwaarde TMR0IF = 0; // Wis timer-interruptvlaggetelling ++; // Het aantal wordt met 1 verhoogd voor elke 0,05 ms -> het aantal wordt 20 voor elke 1 ms (0,05 / 1 = 20)) } int servo_code = {0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100}; if (count> = 20 * 20) count = 0; if (count <= (T_ON)) PORTD = PORTD - servo_code; anders PORTD = PORTD & ~ (servo_code); }
We weten dat de totale cyclus 20 ms moet duren voordat de GPIO-pin weer wordt ingeschakeld. Dus we controleren of de telling 20 ms heeft overschreden door de waarde van count te vergelijken met 400 (dezelfde berekening als hierboven besproken) en zo ja, dan moeten we de telling opnieuw initialiseren om nul te zijn.
Simulatie van PIC Robotarmcode
Het is altijd beter om de code te simuleren voordat u deze naar de echte hardware brengt. Dus ik heb Proteus gebruikt om mijn code te simuleren en heb gecontroleerd of deze correct werkt. Het circuit dat voor simulatie wordt gebruikt, wordt hieronder getoond. We hebben een oscilloscoop gebruikt om te controleren of de PWM-signalen worden gegenereerd zoals vereist. We kunnen ook controleren of de LCD- en servomotoren draaien zoals verwacht.
Als u het LCD-scherm kunt zien dat de duty cycle van de motor D tot 07 zijn op basis van de pot waarde die de 3 rd motor. Hetzelfde als een andere pot wordt verplaatst, de duty-cycle van die pot en zijn motornummer worden weergegeven op het LCD-scherm. Het PWM-signaal dat op de oscilloscoop wordt weergegeven, wordt hieronder weergegeven.
De totale cyclusperiode wordt gemeten op 22,2 ms met behulp van de cursoroptie op de oscilloscoop, wat zeer dicht bij de gewenste 20 ms ligt. Eindelijk weten we zeker dat de code werkt, dus om verder te gaan met het circuit kunnen we deze ofwel op een perf board solderen of een PCB gebruiken. Het zal niet gemakkelijk werken op een breadboard omdat de POT altijd de neiging heeft om wat problemen te geven vanwege slechte verbindingen.
PCB-ontwerp met EasyEDA
Om deze PIC Robotarm te ontwerpen, hebben we gekozen voor de online EDA-tool genaamd EasyEDA. Ik gebruik het nu al een lange tijd en vind het erg handig vanwege de enorme beschikbaarheid van footprint en de gebruiksvriendelijke aard. Na het ontwerpen van de PCB, kunnen we de PCB-monsters bestellen via hun goedkope PCB-fabricagediensten. Ze bieden ook een service voor het sourcen van componenten, waarbij ze een grote voorraad elektronische componenten hebben en gebruikers hun vereiste componenten samen met de PCB-bestelling kunnen bestellen.
Terwijl u uw circuits en PCB's ontwerpt, kunt u ook uw circuit- en PCB-ontwerpen openbaar maken, zodat andere gebruikers ze kunnen kopiëren of bewerken en kunnen profiteren van uw werk.We hebben ook onze hele circuit- en PCB-lay-outs openbaar gemaakt voor dit circuit. de onderstaande link:
easyeda.com/circuitdigest/pic-development-board-for-robotic-arm
Via deze link kunt u direct dezelfde print bestellen die we in dit project gebruiken en deze gebruiken. Zodra het ontwerp is voltooid, kan het bord worden bekeken als een 3D-model, wat erg nuttig zal zijn bij het visualiseren hoe het bord eruit zou zien na fabricage. Het 3D-model van het bord dat we gebruiken, wordt hieronder weergegeven. Afgezien hiervan kun je ook de bovenste en onderste laag van het bord bekijken om te controleren of het gladde scherm is zoals verwacht.
Monsters online berekenen en bestellen
Nadat u het ontwerp van deze PIC Robot PCB heeft afgerond, kunt u de PCB bestellen via JLCPCB.com. Om de print bij JLCPCB te bestellen heeft u Gerber File nodig. Om Gerber-bestanden van uw PCB te downloaden, klikt u op de Generate Fabrication File- knop op de EasyEDA-editorpagina en downloadt u het Gerber-bestand van daaruit of u kunt op Order at JLCPCB klikken, zoals weergegeven in onderstaande afbeelding. Hiermee wordt u doorgestuurd naar JLCPCB.com, waar u het aantal PCB's dat u wilt bestellen, het aantal koperlagen dat u nodig heeft, de PCB-dikte, het kopergewicht en zelfs de PCB-kleur kunt selecteren, zoals de onderstaande momentopname:
Nadat u alle opties heeft geselecteerd, klikt u op "Opslaan in winkelwagen" en wordt u naar de pagina geleid waar u uw Gerber-bestand kunt uploaden dat we hebben gedownload van EasyEDA. Upload uw Gerber-bestand en klik op "Opslaan in winkelwagen". En klik ten slotte op Veilig afrekenen om uw bestelling af te ronden, dan ontvangt u uw PCB's een paar dagen later. Ze fabriceren de printplaat tegen een zeer lage prijs, namelijk $ 2. Hun bouwtijd is ook erg kort, dat is 48 uur met een DHL-levering van 3-5 dagen, in principe ontvangt u uw PCB's binnen een week na bestelling.
Nadat u de print heeft besteld, kunt u de productievoortgang van uw print met datum en tijd controleren. U controleert het door naar de Accountpagina te gaan en op "Voortgang van de productie" te klikken.
Na een paar dagen PCB's te hebben besteld, kreeg ik de PCB-samples in een mooie verpakking, zoals te zien is op onderstaande foto's.
En na het verkrijgen van deze stukjes heb ik alle benodigde componenten over de print gesoldeerd. Ik heb de POT ook direct gesoldeerd in plaats van verbindingsdraden te gebruiken, omdat de vrouw-naar-vrouw-draden die ik aanvankelijk gebruikte, rare analoge uitgangsspanningen gaven, waarschijnlijk vanwege losse contacten. Toen alle componenten eenmaal waren gemonteerd, zag mijn print er ongeveer zo uit.
Het is je misschien opgevallen dat er maar één 7805 op dit bord staat. Dat komt omdat ik aanvankelijk dacht dat ik weg kon komen met alleen een regelaar voor het aandrijven van zowel PIC als servomotor en later besefte ik dat ik er twee nodig had. Dus ik heb een extern circuit gebruikt om de servomotoren van stroom te voorzien via de groene draden die je hier ziet.
Toch hoef je je er niet veel zorgen over te maken, want; Ik heb nu de wijzigingen op de printplaat aangebracht. U kunt gebruik maken van de gemodificeerde printplaat en de beide regelaars zelf aan boord solderen.
Werking van PIC Robotarm
Na al het vermoeiende werk is het tijd om af te betalen. Soldeer alle componenten op het bord en upload het programma naar de PIC-controller. De volledige code wordt hieronder gegeven of kan vanaf hier worden gedownload. De programmeerconnector op het bord zou je moeten helpen het programma rechtstreeks met Pickit 3 zonder veel gedoe te uploaden. Zodra het programma is geüpload, zou u het LCD-scherm moeten zien met de servo die momenteel wordt bestuurd. Volg de vorige tutorial om meer te leren over het programmeren van de PIC Microcontroller.
Van daaruit kun je eenvoudig aan de pot draaien en kijken hoe de servomotoren op elke potentiometer reageren. Zodra u het formaat begrijpt, kunt u de robotarm besturen om de gewenste actie uit te voeren en plezier te hebben. U kunt de volledige werking van het project vinden in de onderstaande video.
Dat is het, jongens hopen dat je het project hebt begrepen en er iets nieuws van hebt geleerd. Als je vragen hebt, laat ze dan achter in het commentaargedeelte of gebruik de forums voor andere technische discussies.