Motion Control met Arduino een cameraschuifje motoriseren

De beschikbaarheid van goedkope stappenmotoren en drivers biedt tegenwoordig voldoende gelegenheid om te experimenteren buiten de duurdere en gecompliceerdere 2D / 3D-snij- en drukprojecten.. 

Voor dit project neem ik de schuifregelaar van de OpenBuilds-camera (raadpleeg de buildvideo bij het bouwen van een eenvoudige videoschuifmachine met open source CNC-onderdelen) en motoriseer deze. Ik maak ook een zelfstandig systeem voor het besturen van de motor.

Deze tutorial behandelt specifiek het samenstellen van de hardware, maar in de eerste plaats het bouwen van een rudimentaire 16x2 LCD GUI met behulp van de LiquidCrystal-bibliotheek en een eenvoudig menusysteem om weer te geven, gevolgd door de werking van de A4988-stepperdriver en hoe deze te besturen met Arduino. 

Dit project is zwaar op loops en steps, en hoewel het project over het algemeen wat meer intermediair is, heb ik geprobeerd het zo uit te leggen dat beginners relatief snel aan de slag kunnen..

Uitrustingslijst

Components

  • Arduino Uno
  • LCD-toetsenbord Shield of afzonderlijke 16x2 LCD en knoppen als je weet hoe je dat moet laten werken
  • Pololu A4988 [Black Edition] Stepper Driver
  • Kleine aluminium zelfklevende warmteafvoer
  • Breadboards, mannelijke en vrouwelijke springerdraden, enz
  • 220-330 ohm-weerstand (waarschijnlijk 1 / 4W), standaard NPN-transistor (ik gebruikte een BC109)
  • 3,5 mm stereo TRS-aansluiting
  • 3,5 mm naar 2,5 mm stereo TRS-adapterkabel
  • 3,5 mm verlengkabel, indien nodig voor de schuiflengte
  • 9V-vataansluitingenvoeding als u de Arduino uit de USB-stroom van de computer wilt verwijderen
  • 12V 2A-voeding om de stappenmotor te laten werken
  • NEMA 17 stappenmotor

Onderdelen

  • GT2 5 mm brede, 2 mm-pitch distributieriem: dubbele schuiflengte plus een voet voor veiligheid (11 voet voor mij)
  • Gladde spanrollen kit
  • Belt-tension torsieveer als u problemen ondervindt om de spanning van de riem op lange termijn te handhaven
  • 2x Belt crimp clamp (kan worden vervangen door kleine zipties)
  • GT2 7 mm brede, 20 tandige aluminiumschijf met dezelfde boring als motoras
  • 4x 30 mm M3-0.5 dopkop machineschroeven

Hulpmiddelen

  • Computer met Arduino IDE (ik gebruik Win7, Arduino 1.0.5 r2)
  • Soldeerbout met kleine beitelpunt, soldeer, enz
  • 2.5mm inbussleutel voor M5-schroeven
  • 2 mm inbussleutel voor M3-schroeven
  • Inbussleutel van 1,5 mm voor stelschroeven in GT2-riemschijf
  • multimeter voor het oplossen van problemen en de huidige aanpassing
  • Smalle tang om te spannen in kleine ruimtes

Functioneel overzicht

Ik zal het toevoegen van de motor en de katrollen aan de slider afdekken, de riem omsnoeren en alles vastmaken. Het is een eenvoudige wijziging. 

Daarna zal ik bespreken hoe je een Pololu A4988 Black Edition-kit samenstelt en hoe je hem samen met alle andere externe kaarten op een breadboard kunt aansluiten, evenals een eenvoudige multiplexbehuizing die ik in een paar minuten heb samengeslagen voor mijn 12V-vermogen. voeding (hierboven vermeld) om schokken te voorkomen wanneer de bedradingsterminals worden blootgesteld.

Zijdelings zodat het groot genoeg blijft dat de pinnummers nog zichtbaar zijn!

Het menu staat invoer toe van afstand om te reizen, tijd om te reizen, aantal stappen om in te reizen en rijrichting. Aan het einde van elke stap wordt de schuif gepauzeerd terwijl de camera wordt geactiveerd.

De schuifregelaar aanpassen

Stap 1: Motor assemblage

De OpenBuilds V-sleuf actuator eindmontage heeft NEMA 17 maatgaten erin, dus vier 30 mm M3 kapschroeven zijn alles wat nodig is om de motor erop te monteren.

De OpenBuilds V-sleuf Actuator End Mount

Zorg dat de tweetandige GT2-poelie in de steun zit voordat u de motoras erin steekt, omdat de steun niet breed genoeg is om deze later op te kunnen zetten. Nadat de motor onderaan is vastgeschroefd, draait u de stelschroeven met één tegen het vlakke gedeelte van de motoras aan, waarbij u ervoor zorgt dat de tanden recht in lijn liggen met het midden van de hele extrusie-eenheid.

Stap 2: Spanrolenset

De riempoelieset gaat samen als een wielset en past in het tegenovergestelde uiteinde Actuator Mount:

De riemschijfkit

Stap 3: Belting Up

Voer de riem door het midden van de V-gleuf in lijn met de poelies, zorg ervoor dat de tanden naar boven gericht zijn. 

Voer het dan op en over de twee katrollen en breng het terug naar het midden van de dolly build plate.

De tanden grijpen in elkaar.

Hier wikkelt u een kant door de riemsleuf en klemt u vast, of trekt u deze vast, en gebruikt u die om de hele riem door het hele systeem aan te spannen voordat u de andere kant aansluit. Niet te strak om de motor te laten draaien, maar niet los genoeg om tanden op de aandrijfpoelie over te slaan!

De elektronica assembleren

Stap 1: monteer de stappendriver

De Pololu A4988 Black Edition stappenmotor driver (technisch gezien is de A4988 carrier board - de A4988 is de chip zelf) meestal in de vorm van een kit, wat simpelweg betekent dat de headers moeten worden gesoldeerd. Aangezien dit een vermogenscomponent is, is het een goed idee om een ​​koellichaam toe te voegen om de levensduur te verlengen, ook al leidt dit niet tot maximale capaciteit..
Breek de koprij doormidden om twee rijen van acht te krijgen. Steek deze in de vergulde gaten in het bord en schuif deze voorzichtig in het breadboard. Soldeer de pennen op hun plaats terwijl het breadboard alles mooi en loodrecht houdt.

De Stepper Driver samenstellen

Zodra dit is voltooid, snijd de hoek van een kleine zelfklevende koellichaam af met een ijzerzaag of scrollsaw (voorzichtig, in een klem!) Om te monteren op de A4988 IC.

Snijd de hoek af van een kleine zelfklevende warmteafleider

Stap 2: Breadboard - Monteer de componenten

Nu moet alles op breadboards worden gemonteerd, zodat het samen kan worden bedraad tot een functionerende cicuit. Ik gebruik afzonderlijke borden voor elk onderdeel omwille van de duidelijkheid in afbeeldingen, maar voel je vrij om alles in een enkel bord te plaatsen als je dat wilt.
Het schild van het LCD-toetsenbord kan niet op een bord worden bevestigd, dankzij de vreemde keuze van Arduino om zich aan een ontwerpfout te houden in plaats van aan de normen te voldoen. Dit wordt apart gehouden, hoewel het schroeven op een stuk hout of iets om de pinnen te beschermen misschien geen slecht idee is.

Het camera-triggerschakeling op zijn eenvoudigste bestaat uit een weerstand, een transistor en een 2,5 mm TRS sub-miniplug. Ik heb een LED toegevoegd die gaat knipperen als de triggerpen omhoog komt, en een 3,5 mm TRS mini-aansluiting om flexibiliteit mogelijk te maken. 

Als je componenten voor deze build koopt, is een 3,5 mm-socket ontworpen voor 0,1 "pitch-boards een goed idee, maar de mijne is van de weggegooide stapel, dus ik heb er een connector aan gesoldeerd.
Leg alles neer, klaar om alles in te pakken.

Stap 3: Alles samen bedraden

Tijd om alle startkabels te pakken. Als u genoeg heeft om de dingen in kleur te houden, wordt het leven gemakkelijker tijdens het oplossen van problemen. Raadpleeg het schakelschema bovenaan als de volgende beschrijving u op elk moment verwart.

Alles samen bedraden

Sluit eerst het LCD aan. Grijp 10 vrouwelijke jumpers en verbind ze met de volgende schildpennen: digitale pinnen 4-9, reset powerbus-pinnen (als u de LCD-resetknop wilt gebruiken), 5V & een van de GND's. 

Als je een vrouw-naar-man-jumpers hebt, kun je die daar laten. Sluit anders mannelijke jumpers aan op het andere uiteinde van de vrouwtjes om deze in de corresponderende Arduino-headerbussen te steken. Als je een LCD-toetsenbordschild hebt waarop vrouwelijke headers zijn geïnstalleerd, kun je deze stap overslaan omdat je schild niets blokkeert.
Vervolgens het bord van Pololu A4988. Dit heeft acht jumpers aan de ene kant nodig, ik heb zwart en rood gebruikt voor logica / motorvermogen aan easch einde, en rood / groen / blauw / geel in het midden vier om overeen te komen met de servodraden van de stappenmotor. 

De logische voedingspen gaat naar 3.3V op de Arduino, omdat het bovenstaande LCD-scherm de 5V-pin gebruikt. De voedingskabels van de motor gaan naar uw 12V-voeding. Aan de andere kant, in de buurt van de A4988-chip, gebruik ik blauw en oranje voor STP en DIR om te contrasteren met de relatief uniforme kleuren overal elders. Ze gaan naar respectievelijk Arduino pins 11 en 12, tenzij u de code wijzigt. Dan korte RST en SLP samen om het bord ingeschakeld te houden; Ik heb de witte draad hier gebruikt.

Als je klaar bent, ziet het er ongeveer zo uit.

Verbind ten slotte het cameratriggerschakelcircuit. Hier worden de zwarte draden geaard - de A-rijdraad naar Arduino, de C-rijdraad naar de 3,5 mm-aansluiting. Het gele gaat naar Arduino pin 13 (dus er is een LED-indicator op het bord en op de schakelaar!), En de rode draad gaat naar de andere kant van de 3,5 mm-aansluiting (of 2,5 mm plug-aansluiting als je gaat die route).
Steek de stappenmotor in de gekleurde draden volgens het bordschema van de A4988 en de datasheet van uw stepper. Voor mij was dat zo:

Net als de knoplezer is de schets van de testrotatie opgenomen in de bovenkant met ritssluiting.

Voorzichtigheid: Onthoud dat de draden die de motor van stroom voorzien waarschijnlijk 1-2A zullen trekken op de door u gekozen spanning, zorg er dus voor dat de gebruikte draden hiervoor geschikt zijn. De A4988-chip en -plank eromheen kunnen heet worden! De potentiometer die in het bord is ingebouwd, biedt een stroombeperking om zowel de A4988 als de motor te beschermen, dus zorg ervoor dat je hem op de juiste manier instelt voordat je hem gebruikt met een multimeter.

Het programma instellen

Nadat de componenten zijn gemonteerd, kunt u naar de codering gaan. Download de zip die bij deze zelfstudie wordt meegeleverd, of bekijk deze GitHub-repository als je dat liever hebt. Ik zal beschrijven hoe ik het heb samengevoegd, zodat je de algemene programmastroom en de manier waarop de modules samenwerken, kunt begrijpen.

Stap 1: Inclusief en basisdefinities

Het enige dat hiervoor nodig was, was de LCD-schrijfbibliotheek LiquidCrystal.h. Dit geeft toegang tot de lcd.xxxx () functies. Er is een pow () in het programma en ik vond dat inclusief de C ++ -bibliotheek math.h is niet nodig, omdat een paar van de meest nuttige functies zijn opgenomen in de Arduino-voorraadomgeving, inclusief pow ().


#include  LiquidCrystal lcd (8, 9, 4, 5, 6, 7); // stel LCD output pinnen in // definieer stepper driver pinnen const int stp = 11; // kan pin 10 niet gebruiken met de SS LCD omdat het de achtergrondverlichting is. // als het laag wordt, gaat de achtergrondverlichting uit! const int dir = 12; // definieer trigger pin const int trig = 13; // KNOPPEN // definieer knopwaarden const int btnUp = 0; const int btnDn = 1; const int btnL = 2; const int btnR = 3; const int btnSel = 4; const int btnNone = 5; // definieer variabelen voor het aflezen van knopen int btnVal = 5; int adcIn = 0;

Ik heb de LCD-uitvoerpinnen, de uitvoerpinnen van de stepperdriver en de uitvoerpinnen van de camera-trigger ingesteld. Nadat de feitelijke hardware-interface is ingesteld, heb ik variabelen toegevoegd voor knopgebeurtenissen gevolgd door de knopleesfunctie, die ik heb aangepast vanaf de DFRobot-wiki op hun identieke LCD-toetsenbordschild. Merk op dat SainSmart geen documentatie biedt.

Stap 2: Setup () Loop

Dit is super rechttoe rechtaan. Initialiseer het LCD-scherm en de relevante uitgangspennen, gevolgd door een standaard welkomstscherm en ga vervolgens naar het startscherm: menuoptie 1 met waarden op nul.

void setup () lcd.begin (16, 2); // initialiseer LCD lib lcd-setcursor met volledig scherm (0,0); // stel cursorpositie pinMode in (stp, OUTPUT); // initialiseer stepper pins pinMode (dir, OUTPUT); pinMode (trig, OUTPUT); // initialiseer trigger pin digitalWrite (trig, LOW); // zorg ervoor dat trigger uitgeschakeld is lcd.print ("Welcome to"); // welkomstscherm lcd.setCursor (0,1); lcd.print ("SliderCam v0.2!"); delay (1000); lcd.clear (); lcd.print (menuItemsTop [0]); vertraging (100); lcd.setCursor (0,1); voor (int i = 0; i < 4; i++)  lcd.setCursor(i, 1); lcd.print(currentDistance[i]);  lcd.setCursor(4,1); lcd.print("mm(max 1300)"); 

Stap 3: Monitor knoppen

Het voordeel hiervan is dat de apparatuur helemaal niets hoeft te doen zonder gebruikersinput. Wat betekent dat het allereerste ding eenvoudigweg een eeuwige knooppeilinglus kan zijn. Oproep aan de readLcdButtons () functioneer steeds opnieuw totdat de waarde verandert, heeft geen negatieve invloed op de prestaties van het programma en u hoeft zich geen zorgen te maken over het beschikbaar stellen van interrupt-pinnen.

void loop () do btnVal = readLcdButtons (); // lees continu de knoppen ... while (btnVal == 5); // ... totdat iets wordt ingedrukt
// declareer button poll-functie int readLcdButtons () delay (90); // debounce delay, experimenteel afgestemd. vertraging is goed, want het programma zou niets anders moeten doen // op dit moment toch adcIn = analoogRead (0); // lees waarde van pin A0 / * drempelwaarden bevestigd door experimenten met knopkalibratieschets die de volgende ADC-leeswaarden retourneert: rechts: 0 omhoog: 143 omlaag: 328 links: 504 selecteren: 741 * / if (adcIn> 1000) retourneren btnNon ; if (adcIn < 50) return btnR; if (adcIn < 250) return btnUp; if (adcIn < 450) return btnDn; if (adcIn < 650) return btnL; if (adcIn < 850) return btnSel; return btnNone; //if it can't detect anything, return no button pressed 

ReadLcdButtons () heeft een vertraging van 90ms om ontdendering de knoppen. In werkelijkheid is dit geen debounce, omdat het de ADC-meting niet opnieuw neemt na een ingestelde tijd, maar eerder de knoppen niet vaak genoeg peilt om zelden meer dan één klik te registreren. 

Het bereikt hetzelfde vanuit een praktische UX-weergave. Het is meer een pollknoppen elke 90 ms in plaats van constant, dat is de reden waarom gebruik van vertraging() wordt over het algemeen niet beschouwd als goede praktijk voor redeneeringsdoeleinden, maar het loste het probleem op (alleen alle menu's waren toegankelijk).

Stap 4: scherm vernieuwen

Zodra het apparaat op input kan reageren, moet er een manier zijn waarop het die reacties kan weergeven. 

Na het uitproberen van on-the-fly updates, stelde ik vast dat een consistente schermvernieuwing zoals een echt besturingssysteem gemakkelijker te beheren was in mijn pogingen om een ​​modulaire upgradebare structuur te krijgen. Dit doen is net zo eenvoudig als het wissen van het scherm en vervolgens opnieuw opbouwen op basis van bekende actuele parameters.
Dit klinkt ingewikkeld, maar in de praktijk wordt het leven veel gemakkelijker. Het verwijdert een groot aantal LCD-opdrachten van elders in het programma en creëert een variabele-type-agnostische zone die minimaal wordt beïnvloed door externe programma-updates.
Het eigenlijke verfrissende deel is geëvolueerd en bestaat uit vier verschillende stappen:
Parameters opnieuw instellen ...

// PRINT NEW SCREEN VALUES btnVal = btnNone; lcd.clear ();

... druk de bovenste regel af ...

lcd.setCursor (0, 0); lcd.print (menuItemsTop [currentMenuItem]); // print menu-item op hoogste niveau

... druk de onderste regel af, wat ik later zal uitleggen ...

 lcd.setCursor (0,1); switch (currentMenuItem) case 0: for (int i = 0; i < 4; i++)  lcd.setCursor(i, 1); lcd.print(currentDistance[i]);  break;  case 1:  for (int i = 0; i < 6; i++)  lcd.setCursor(i, 1); lcd.print(currentDuration[i]);  break;  case 2:  for (int i = 0; i < 4; i++)  lcd.setCursor(i, 1); lcd.print(currentSteps[i]);  break;  case 3:  if (travelDir == 0) lcd.print("From Motor"); else lcd.print("To Motor"); break;  case 4:  lcd.print("Stop!"); break;   //end switch

... en schermspecifieke opdrachten toevoegen over de bovenkant van wat al is afgedrukt.

if (currentMenuItem == 0) lcd.setCursor (4,1); lcd.print ("mm (max 1300)"); // voeg max. verplaatsing van de wagen in met schuif gebruikt if (currentMenuItem == 1) lcd.setCursor (6,1); lcd.print ( "s (3600 / hr)");  if (currentMenuLevel == 1) lcd.setCursor (currentCursorPos, 1); lcd.blink ();  else lcd.noBlink ();

Een menu samenstellen: de belangrijkste kopjes

Natuurlijk schrijft die exacte schermvernieuwingssectie zichzelf niet, en we moeten weten welk menu het schrijft om te screenen voordat het kan worden voltooid. De belangrijkste koppen zijn eenvoudig, omdat ze niet echt veranderen, afhankelijk van de invoer van de gebruiker. Dit betekent dat het eenvoudig een tekenreeksreeks kan zijn, technisch gezien een char pointer array, of een array van arrays:

// MENU GUI // definiëren strings op het hoogste niveau voor numerieke navigatie char * menuItemsTop [] = "01 Distance>", "< 02 Duration >","< 03 Steps > ","< 04 Direction >","< 05 Go!"; int currentMenuLevel = 0; //top menu or submenu int currentMenuItem = 0; //x-axis position of menu selection int currentCursorPos = 0; //current lcd cursor position int currentDistance[4] =  0, 0, 0, 0; int currentDuration[6] =  0, 0, 0, 0, 0, 0; int currentSteps[4] =  0, 0, 0, 1;

Dit betekent dat dit menuItemsTop matrix kan eenvoudig worden genavigeerd door het aantal binnen de vierkante haken bij de schermvernieuwingstijd te wijzigen. Wat zo gebeurt, omdat alles geïndexeerd is, om identiek te volgen met het gehele getal currentMenuItem

manipuleren currentMenuItem bij knopgebeurtenissen kunnen we eendimensionale navigatie uitvoeren, dus als je het ziet menuItemsTop [currentMenuItem] het is overduidelijk huidige menunubriek.

if (currentMenuLevel == 0) switch (btnVal) case btnL: if (currentMenuItem == 0) break; // kan hier niet links vandaan gaan currentMenuItem--; breken;  case btnR: if (currentMenuItem == 4) pauze; // kan niet verder gaan vanaf hier anders currentMenuItem ++; breken;  case btnSel: currentMenuLevel ++; if (currentCursorPos> 3 && (currentMenuItem == 0 || currentMenuItem == 2)) currentCursorPos = 3; // ga niet van het einde van de getallen voor de 4-cijferige getallen als (currentCursorPos> 0 && (currentMenuItem> 2)) currentCursorPos = 0; // stel de knipperende cursor naar links in voor op tekst gebaseerde opties if (currentMenuItem == 4) motion = 1; beweging controle(); breken;  // einde van schakelaar // einde van niveau 0

Je kunt dus naar links en rechts gaan en gaan in een menu, of in het geval van Gaan! dan is motion control geactiveerd. Dat is alles wat hier nodig is.

Een menu bouwen: submenu

Het submenusysteem deed er iets meer aan, dankzij de interne complexiteit. De eerste drie inzendingen, Afstand, Looptijd en Stappen, technisch bestaat uit een sub-submenu, die elk navigatie van de meercijferige waarde mogelijk maakt, evenals elk individueel karakter.

Dit wordt gedekt door van elk submenu een zelfstandig geschakeld kopregelsysteem te maken. Hoewel dit een lange weg te gaan had, is het een eenvoudige en consistente methode om dergelijke navigatie op een laag niveau mogelijk te maken. Omdat ik het echt net heb begrepen Afstand submenu en vervolgens gekopieerd voor de andere submenu's, hier is een blik op die ene.

else // i.e. "else als currentMenuLevel = 1" if (currentMenuItem == 0) // 01 DISTANCE-switch (btnVal) case btnUp: currentChar = currentDistance [currentCursorPos]; adjustDigit (currentChar, 1); currentDistance [currentCursorPos] = currentChar; breken;  case btnDn: currentChar = currentDistance [currentCursorPos]; adjustDigit (currentChar, 0); currentDistance [currentCursorPos] = currentChar; breken;  case btnL: if (currentCursorPos == 0) pauze; // kan hier niet links vandaan blijven currentCursorPos--; breken;  case btnR: if (currentCursorPos == 3) pauze; // kan hier niet links vandaan currentCursorPos ++; breken;  case btnSel: parseArrayDistance (); currentMenuLevel--;  // eindschakelaar // einde AFSTAND

Links en rechts zijn in essentie hetzelfde als het menu op het hoogste niveau, eenvoudig heen en weer bewegen langs het nummer op dezelfde manier, door de aantal eigenlijk een reeks cijfers in een int-array en de huidige locatie is opgeslagen in een int genaamd currentCursorPos die knipperen mogelijk maakt zoals te zien is in de bovenstaande schermvernieuwingsmodule. 

Het afdrukken van deze arrays langs de onderste LCD-rij is wat de for-lussen waren voor in de sectie voor het vernieuwen van het scherm; ik van 0 naar 3, LCD-kolom van 0 naar 3, currentDistance [] van 0 naar 3.

int adjustDigit (int x, int dir) // digit adjust function if (dir == 0 && x> 0) x--; // aftrekken van cijfer op btnDn if (dir == 1 && x < 9) x++; // add to digit on btnUp lcd.setCursor(currentCursorPos, 1); lcd.print(x); currentChar = x; return currentChar; //return new digit 

Het verhogen en verlagen van het aantal wordt bereikt door het huidige cijfer in de variabele op te slaan currentChar, die vervolgens wordt doorgegeven aan de adjustDigit () functie samen met een booleaanse waarde die richting aangeeft; om de motor te verhogen of te verlagen. 

Dit past eenvoudig het cijfer aan volgens de Booleaanse waarde en slaat het resultaat op, waarna de flow terugkeert naar de hoofdlus, waar de currentChar-waarde wordt opgeslagen op de juiste positie van het origineel currentDistance [] array en het nieuwe aangepaste cijfer wordt afgedrukt bij het vernieuwen van het scherm.

Weergave van Array-waarden in de array

Wanneer Select wordt aangeroepen vanuit een van de subarrays van de nummerarray, wordt de relevante ontleedfunctie geactiveerd, in dit geval parseArrayDistance (). U moet de array parsen, die u handig kunt weergeven en bewerken, tot een geheel getal dat nuttig is voor daadwerkelijke bewegingsberekeningen. Ik heb ervoor gekozen dit nu in plaats van verder te doen Gaan! om UX een pittig gevoel te geven.

int adjustDigit (int x, int dir) // digit adjust function if (dir == 0 && x> 0) x--; // aftrekken van cijfer op btnDn if (dir == 1 && x < 9) x++; // add to digit on btnUp lcd.setCursor(currentCursorPos, 1); lcd.print(x); currentChar = x; return currentChar; //return new digit 

Ik bedacht deze functie met de enige bruikbare passerende opmerking die ik vond nadat ik Google had uitgeput op zoek naar standaard array-naar-int-functies, leeg kwam te staan ​​en de puinhoop van array-naar-char-naar-int-functies kwijt was die een niet-effectieve oplossing. Het lijkt vrij kort en licht, aangezien het letterlijk gebaseerd is op de basis van decimale wiskunde, maar als je een betere methode kent, ben ik helemaal in de oren.

Motion Control en camerariggering

Alle waarden zijn ingesteld en u raakt Gaan! Wat gebeurt er nu? Je moet precies berekenen wat de nummers die eraan zijn gegeven moeten doen om de laatste beweging uit te voeren. Dit deel is functioneel, maar een werk in uitvoering; Ik vind dat er meer opties moeten zijn voor verschillende soorten beweging.

int motionControl () totalMotorSteps = currentDistanceInt * 5; // bereken de totale stappen (0,2 mm = tandwiel met 20 tanden op een spoedband van 2 mm, 40 mm per omwenteling, 200 stappen per omw, ergo 1 / 5e mm per stap) pulseDelay = (1000L * (currentDurationInt - (currentStepsInt * shutterDuration))) / totalMotorSteps; // hoe lang om te pauzeren in ms tussen STP-pulsen naar de motordriver intervalDistance = totalMotorSteps / currentStepsInt;

Wat er gebeurt in deze functie is vrij duidelijk uit de opmerking, denk ik. Ik heb een shutterDuration van 2 seconden in de software, voornamelijk om redelijk snel te blijven testen. Als u s'nachts fotografeert, bij lagere ISO-waarden, moet dit wellicht ongeveer 25-35 seconden zijn, afhankelijk van uw exacte sluitersnelheid.

De pulseDelay wordt vermenigvuldigd met 1000 aan het einde om te converteren van seconden naar milliseconden, natuurlijk. De L om de constante int in een lange om te zetten is meer me dwalend aan de kant van voorzichtigheid dan eigenlijk strikt noodzakelijk. Omdat het een relatief kleine schets is, ben ik niet al te bezorgd over het variabele geheugengebruik.

Deze berekeningen gaan ervan uit dat de lus zelf een verwaarloosbare hoeveelheid tijd nodig heeft om te werken in vergelijking met de pulseDelay tijd, die, nadat ik de knop polling had gehaald, waar lijkt te zijn.

// een keer per algemene run als (travelDir == 0) digitalWrite (dir, LOW); else if (travelDir == 1) digitalWrite (dir, HIGH); //Serial.begin(9600); //Serial.println(pulseDelay); // step loop do digitalWrite (stp, HIGH); // Vertraging brandbesturing machinist (pulseDelay); digitalWrite (stp, LOW); // reset stuurprogramma // btnVal = readLcdButtons (); // controleer of er geen onderbreking is - dit duurt te lang en vertraagt ​​de motor aanzienlijk; gebruik reset voor stop! currentStep ++; // aan het einde van elke stap if (currentStep% intervalDistance == 0) // als het huidige aantal motorstappen deelbaar is door het aantal motorstappen in een camerastap, ontsteek dan de camera digitalWrite (trig, HIGH); // activeer de sluitervertraging van de camera (80); digitalWrite (trig, LOW); // reset trigger pin delay ((shutterDuration * 1000) -80); // vertraging moet worden gewijzigd in timer, zodat stopknop kan worden gepold while (currentStep < totalMotorSteps);  //end motion control

Let ten slotte op de currentSteps waarde ingesteld op 1. Ik heb hier geen foutcontrolefunctie voor gecreëerd, maar simpel gezond verstand zegt stapgrootte wordt oneindig als currentStepsInt == 0, dus het is het beste om het bij één te houden als continue beweging gewenst is. Ik heb hier al een verbetering voor toegevoegd.

Het eindproduct uitvoeren

Voor iets dat draait op code die in twee dagen helemaal opnieuw is geschreven en meer dan twee keer gecorrigeerd is, werkt het als een droom! Het bewijs zit echter in de pudding. Krijgt het echt de moeite waard timelapse beelden, en werkt de besturingseenheid echt goed in het veld?

In mijn tests lijkt het antwoord een volmondig ja te zijn. Hieronder volgt een timelapse van 650 uur met twee frames, de allereerste test. De schuifregelaar voltooide ook een 9-uurs 720 frametest foutloos, maar helaas deed de batterij van de camera het niet zo goed na 2 uur in ... wat ik pas in de 8,5 uurmarkering wist, uiteraard.

Als ik de tijd en de juiste stappen instel, kan de beweging continu zijn voor langzame bewegingen van de dolly in live-action video, hoewel de schokkerige uiteinden moeten worden bewerkt of snel worden verhoogd. 

Geluid kan een probleem zijn tenzij je stepper erg stil is, maar voor het toevoegen van productiewaarde aan zelfopnames is dit een optie.

verbeteringen

Zoals met alles, kunnen er nog verbeteringen worden aangebracht. Ik heb deze bovenaan de lijst weergegeven .ino bestand, hoewel weliswaar zonder enige zorg boven de uitvoerbaarheid, noch besteld door enige vorm van belang. 

Sommige van deze overwogen om voorafgaand aan het loslaten van deze tutorial met v0.2 te overwegen, maar ik heb het gevoel dat ze op zichzelf een leerervaring zijn om naar te kijken in termen van het mentaal ontmantelen van de bruikbaarheid van een programma.

 VERBETERINGEN EN OVERWEGINGEN NAAR V1.0: 1) Efficiëntie van submenu knopreactiecode voor eerste drie menukoppen 2) Gebruik van bulb-sluitertijd als een extra menu-optie, doorgegeven aan shutterDuration int 3) sluitertijd moet worden ingesteld op pauze, niet op vertraging ( ) - kan de stopknop niet opvragen! 4) Gebruik EEPROM library-functies om hoeveelheden te besparen, kan zo het motion control-gedeelte vereenvoudigen en Reset gebruiken als "stop" 5) Verwijder de schakelaar uit het submenu "Go", vervang met meer geschikte logische verklaring 6) Zou het beter zijn om camerastappen te timen? in plaats van totale reizen? "duur" is meer als 15 sec of 2 min. dan 30 min of 4 uur? 7) Elke const ints die beter zou zijn als #define of ints beter als boolean? Nauwelijks echter tegen de grenzen van SRAM-ruimte aan 8kB aangelopen. 8) Tweening / easing voor versnellingscurven, met name voor videogebruik 9) Foutcontrole voor nulstapgrootte, of voeg eenvoudig een toe aan intervalDistance als de waarde nul is vóór berekeningen - het andere einde van de afstand is nog steeds 1 stap 10) Zou sub-16ms vertraging () is beter als delayMicroseconds ()? Hoeveel tijd gooien interrupts af? 11) Slaapgebruik op A4988 om het stroomverbruik in het veld te verminderen? 12) Foutcontrole voor currentDurationInt <= currentStepsInt*shutterDuration, allowing no time for movement or even negative pulseDelay! */

Dit zijn slechts de verbeteringen die ik tot nu toe heb bedacht, in een poging om de codebase te begeleiden van een rudimentaire maar functionele v0.2 naar een meer geoptimaliseerde en meer capabele release v1.0. Je zult meer opvallen. Je kunt ze gerust achterlaten in de reacties hieronder of op GitHub.

Afsluiten

Als je van begin tot eind hebt gevolgd, inclusief het gedeelte Fotografie Tuts + van de build, ben je nu de trotse eigenaar van een gemotoriseerde cameraslider van hoge kwaliteit die timelapse-opnamen en subtiele dolly moves kan produceren. Als u de code voor een ander project gebruikt, zou ik het graag willen zien.

In deze zelfstudie heb ik gekeken naar verschillende vormen van loop-gebaseerde flow control, het creëren van een rudimentaire GUI en het updaten van een LCD op basis van gebruikersinvoer. Ik keek ook naar het gelijktijdig besturen van meerdere externe mechanische apparaten via breakout-boards. 

U hebt de stroom en het gemak gezien van het programmeren van modulaire code, evenals het zien van ideeën om de code te verbeteren die functioneel is, maar niet geoptimaliseerd, zowel vanuit het oogpunt van UX- als processorefficiëntie. Deze tools zouden je in de toekomst goed van dienst kunnen zijn voor een verscheidenheid aan communicatie- en interactie-gebaseerde projecten.

Laat eventuele vragen of opmerkingen achter op de opmerkingen!