Controlul mișcării cu Arduino motorizarea unui glisor al camerei

Disponibilitatea motoarelor de pasageri ieftine și a șoferilor în aceste zile oferă oportunități ample de a experimenta în afara proiectelor de tăiere și tipărire 2D / 3D mai scumpe și mai complicate. 

Pentru acest proiect, voi lua slider-ul de cameră OpenBuilds (consultați construirea unui videoclip în Construirea unui slider video de bază cu componente CNC deschise) și motorizați-l. De asemenea, voi crea un sistem autonom pentru controlul motorului.

Acest tutorial acoperă în mod special punerea împreună a hardware-ului, dar în primul rând construirea unui grafic rudimentar 16x2 LCD folosind biblioteca LiquidCrystal și un sistem de meniuri simplu pentru afișare, urmat de funcționarea șoferului Stepper A4988 și cum se poate controla cu Arduino. 

Acest proiect este greu pe bucle și pași și, în general, proiectul este mai intermediar, am încercat să-l explic în așa fel încât începătorii să poată funcționa relativ repede.

Lista de echipamente

Componente

  • Arduino Uno
  • Ecranul tastaturii LCD sau ecranul separat 16x2 și butoanele dacă știți cum să faceți acest lucru
  • Pololu A4988 [Black Edition] Stepper Driver
  • Mici radiatoare de aluminiu autocolant mic
  • Plăci de bord, fire de sârmă pentru bărbați și femei, etc
  • 220-330 ohm rezistor (1 / 4W va face probabil), NPN tranzistor standard (am folosit un BC109)
  • Soclu stereo TRS de 3,5 mm
  • Cablu adaptor TRS stereo de 3,5 mm la 2,5 mm
  • Cablu de prelungire de 3,5 mm necesar pentru lungimea cursorului
  • 9V, dacă doriți să scoateți dispozitivul Arduino de la sursa USB a computerului
  • 12V 2A de alimentare pentru a rula motor pas cu pas
  • NEMA 17 motor pas cu pas

Părți

  • Curea de distribuție GT2 de 5 mm: 2 ori lungimea cursorului plus un picior pentru siguranță (11 picioare pentru mine)
  • Setul de scripete netede
  • Dacă întâmpinați dificultăți în menținerea tensiunii centurii pe o perioadă lungă de timp, arcul de torsiune cu tensiune arsă
  • 2x clemă de criptare a benzii (poate fi înlocuită cu zipuri mici)
  • GT2, cu lățimea de 7 mm și 20 de dinți din aluminiu, având aceeași dimensiune ca și axul motorului
  • Mașini de șurub cu cap-șurub 4x 30 mm M3-0.5

Unelte

  • Computer cu Arduino IDE (folosesc Win7, Arduino 1.0.5 r2)
  • Fier de călcat cu vârf de daltă mic, lipire, etc
  • Cheie hexagonală 2,5 mm pentru șuruburile M5
  • Cheie hexagonală 2 mm pentru șuruburile M3
  • Cheie hexagonală de 1,5 mm pentru șuruburile de fixare din scripetele GT2
  • multimetru pentru depanare și ajustare curentă
  • Cleste înguste pentru strângere în spații mici

Prezentare generală funcțională

Voi acoperi adăugarea motorului și a scripeților pe cursor, înșurubând cureaua în jurul ei și fixând totul. Este o modificare simplă. 

Apoi voi studia cum să pun împreună un kit Pololu A4988 Black Edition și cum să-l conectez pe un panou împreună cu toate celelalte plăci externe, precum și o placă de placaj simplu pe care am bătut-o în câteva minute pentru puterea mea de 12V (enumerate mai sus) pentru a preveni șocurile pe măsură ce sunt expuse terminalele de cablare.

În lateral, astfel încât să rămână suficient de mare încât numerele de pini să fie încă vizibile!

Meniul permite introducerea distanța de a călători, timp pentru a călători, numărul de pași pentru a călători în și direcția de deplasare. La sfârșitul fiecărui pas, glisorul se oprește în timp ce aparatul foto este declanșat.

Modificarea cursorului

Pasul 1: Ansamblul motorului

Suportul de acționare a dispozitivului de acționare a slotului OpenBuilds V are găuri de dimensiune NEMA 17, astfel că sunt necesare toate cele patru șuruburi cu cap de cap M3 de 30 mm pentru a monta motorul la el.

Suportul de acționare a dispozitivului de acționare OpenBuilds pentru capătul V

Asigurați-vă că scripetele de 20 de dinți GT2 se găsește în interiorul suportului înainte de a introduce arborele motorului, deoarece montura nu este suficient de largă pentru ao adăuga ulterior. Odată ce motorul este înșurubat în partea inferioară, strângeți șuruburile de fixare cu unul dintre ele pe partea plană a arborelui motorului, asigurându-vă că dinții sunt în linie directă cu centrul întregii unități de extrudare.

Pasul 2: Setul de scripeți

Setul de scripeți de rotire se alimentează împreună ca un set de roți, iar sloturile în capătul opus. Servomotor:

Setul de scripeți pentru roată

Pasul 3: Îmbrățișarea

Alimentați centura prin centrul slotului V, în linie cu roțile, asigurându-vă că dinții sunt orientați în sus. 

Apoi, alimentați-l și peste cele două scripeți și aduceți-l înapoi la mijloc până la placa de dolly.

Dinții se strânge unul în celălalt.

Aici înfășurați o parte prin slotul curelei și fixați-o sau fixați cu fermoar, apoi folosiți-o pentru a strânge întreaga curea prin întregul sistem înainte de a conecta cealaltă parte. Nu prea strâns pentru ca motorul să se rotească, dar nu suficient de liber pentru a sări peste dinții de pe scripetele de acționare!

Asamblarea electronicii

Pasul 1: Asamblați driverul Stepper

Driverul Stepper de la Pololu A4988 Black Edition (din punct de vedere tehnic, placa de transport A4988 - modelul A4988 este chipul în sine) vine de obicei în formă de kit, ceea ce înseamnă pur și simplu că anteturile trebuie lipite. Deoarece aceasta este o componentă de alimentare, deși nu conduce unitatea la capacitatea maximă, este o idee bună să adăugați un radiator pentru a contribui la creșterea duratei sale de viață.
Pauză rândul antet în jumătate pentru a avea două rânduri de opt. Introduceți-le în orificii din placă și apoi introduceți-le cu atenție în panoul de paie. Îndepărtați știfturile în poziție în timp ce panza păstrează totul frumos și perpendicular.

Împreună cu Stepper Driver

Odată ce acest lucru este complet, tăiați colțul unui radiator mic de auto-stick, folosind un ferăstrău sau un scrolsaw (cu atenție, într-o clemă!) Pentru a monta la A4988 IC.

Tăiați colțul unui radiator mic de auto-stick

Pasul 2: Placa de bord - Montați componentele

Acum, totul trebuie să fie montat pe panouri pentru a putea fi conectat împreună într-un cicuit funcțional. Folosesc plăci separate pentru fiecare parte din motive de claritate în imagini, dar nu ezitați să le potriviți într-o singură placă dacă doriți.
Ecranul LCD al tastaturii nu poate fi montat pe o placă, grație alegerii ciudate a lui Arduino de a adera la un defect de design, mai degrabă decât să respecte standardele. Acest lucru va fi păstrat separat, deși înșurubarea acestuia pe o bucată de lemn sau ceva pentru a proteja pinii ar putea să nu fie o idee rea.

Circuitul de declanșare a aparatului foto este cel mai simplu compus dintr-un rezistor, un tranzistor și un conector sub-mini TRS de 2,5 mm. Am adăugat un LED care va clipi când pinul de declanșare atinge înălțime și un jack mini TRS de 3,5 mm pentru a permite flexibilitate. 

Dacă cumpărați componente pentru această construcție, o priză de 3,5 mm destinată plăcilor de înălțime de 0,1 "ar fi o idee bună, dar a mea este din grămada interceptată, așa că am sudat un conector.
Stingeți totul, gata să-l conecteze.

Pasul 3: Conectați totul împreună

Este timpul să apucați toate cablurile jumperului. Având suficient pentru a păstra lucrurile colorate codate va face viața mai ușoară atunci când rezolvarea problemelor. Consultați schema de circuite din partea superioară dacă următoarea descriere vă confundă în orice moment.

Conectați totul împreună

Mai întâi introduceți ecranul LCD. Luați 10 jumperi de sex feminin și conectați-le la următoarele pinii de protecție: pinii digitali 4-9, pinii magistralei de resetare (dacă doriți să utilizați butonul de resetare LCD), 5V și unul dintre GND-urile. 

Dacă aveți jumperi de sex feminin, puteți să-l lăsați acolo. În caz contrar, conectați jumperii de sex masculin - la celălalt capăt al femelelor - pentru a le conecta în prizele corespunzătoare ale antenei Arduino. Dacă aveți un ecran LCD cu tastatură care are anteturi de tip feminin instalate în partea superioară, puteți sări peste acest pas deoarece scutul dvs. nu blochează nimic.
Apoi, placa Pololu A4988. Acest lucru are nevoie de opt jumperi pe o parte, am folosit negru și roșu pentru logica / puterea motorului la capătul estic, și roșu / verde / albastru / galben în centrul patru pentru a se potrivi cu serverele motorului pas cu pas. 

Pini de putere logică merge la 3.3V pe arduino, deoarece LCD de mai sus este folosind PIN 5V. Motoarele de alimentare ale motorului merg la sursa de alimentare de 12V. Pe de altă parte, în apropierea chipului A4988, folosesc albastru și portocaliu pentru STP și DIR pentru a contrasta cu culorile relativ uniforme oriunde altundeva. Ei merg la pinii Arduino 11 și respectiv 12, cu excepția cazului în care modificați codul. Apoi scurt RST și SLP împreună pentru a păstra placa activată; Am folosit plumbul alb aici.

Când ați terminat, ar trebui să arate așa ceva.

În cele din urmă, conectați circuitul comutatorului declanșatorului camerei. Aici firele negre sunt împământate - firul de linie A de la Arduino, cablul de linie C la soclul de 3,5 mm. Galbenul trece la pinul 13 Arduino (deci există un indicator LED pe placă, precum și la comutator!), Iar firul roșu merge pe cealaltă parte a prizei de 3,5 mm (sau plumb de 2,5 mm dacă mergeți că traseul).
Conectați motorul pas cu pas la firele colorate în conformitate cu diagrama de bord A4988 și fișa tehnică a pas cu pas. Pentru mine, a fost așa:

Ca și cititorul de butoane, schița de rotație a testului este inclusă în partea superioară a fermoarului.

Prudență: amintiți-vă că firele care furnizează electricitate motorului vor fi probabil trăgând 1-2A la tensiunea aleasă, deci asigurați-vă că firele utilizate sunt evaluate pentru aceasta. Cipul A4988 și bordul în jurul acestuia pot deveni fierbinți! Potențiometrul încorporat în placă oferă limitarea curentului pentru a proteja atât motorul A4988, cât și motorul, deci asigurați-vă că îl setați corespunzător înainte de utilizare utilizând un multimetru.

Configurarea programului

Odată ce componentele au fost asamblate, puteți trece la codificare. Descărcați zipul inclus în acest tutorial sau verificați acest rezumat GitHub dacă preferați. Voi descrie modul în care am pus-o împreună pentru a înțelege fluxul general al programelor și modul în care modulele funcționează împreună.

Pasul 1: include și definițiile de bază

Singurele elemente necesare pentru aceasta au fost biblioteca LCD LiquidCrystal.h. Aceasta oferă acces la lcd.xxxx () funcții. E a pow () în program, și am constatat că inclusiv biblioteca C ++ math.h nu este necesar deoarece câteva din funcțiile sale cele mai utile sunt incluse în mediul Arduino de stoc, inclusiv pow ().


#include  LiquidCrystal lcd (8, 9, 4, 5, 6, 7); // set LCD iesiri de iesire / / defini pasii conducatorului pasului const int stp = 11; // nu poate folosi pinul 10 cu LCD SS, deoarece este controlul luminii de fundal. // dacă scădea, lumina de fundal se oprește! const int dir = 12; // definește pinul de declanșare const int trig = 13; // BUTTONS // definiți valorile butoanelor const int btnUp = 0; const int btnDn = 1; const int btnL = 2; const int btnR = 3; const int btnSel = 4; const int btnNone = 5; // definește variabilele de citire a butonului int btnVal = 5; int adcIn = 0;

Am setat pinii de ieșire LCD, pinii de ieșire ale driverului pas cu pas și pinul de ieșire al declanșatorului camerei. Odată ce este instalată interfața hardware reală, am adăugat variabile pentru evenimente de buton, urmate de funcția de citire a butoanelor, pe care le-am adaptat din wiki-ul DFRobot pe ecranul identic al tastaturii LCD. Rețineți că SainSmart nu furnizează nicio documentație.

Pasul 2: Configurare () Buclă

Acest lucru este super drept. Inițializați ecranul LCD și pinii de ieșire relevanți, urmat de un ecran de întâmpinare de bază, apoi plasați ecranul de start: opțiunea de meniu 1 cu valori zero.

void setup () lcd.begin (16, 2); // initialize LCD lib plin-ecran lcd.setCursor (0,0); // setați poziția cursorului pinMode (stp, OUTPUT); // inițializa pinii pinului pinMode (dir, OUTPUT); pinMode (trig, OUTPUT); // inițializați pinul de declanșare digitalWrite (trig, LOW); // asigurați declanșarea este dezactivată lcd.print ("Bun venit la"); // ecranul de întâmpinare lcd.setCursor (0,1); lcd.print ("SliderCam v0.2!"); întârziere (1000); lcd.clear (); lcd.print (menuItemsTop [0]); întârziere (100); lcd.setCursor (0,1); pentru (int i = 0; i < 4; i++)  lcd.setCursor(i, 1); lcd.print(currentDistance[i]);  lcd.setCursor(4,1); lcd.print("mm(max 1300)"); 

Pasul 3: Butoanele monitorului

Avantajul aici de codificare este că echipamentul nu are nevoie să facă nimic deloc fără intrarea utilizatorului. Ceea ce înseamnă că primul lucru poate fi pur și simplu o buclă eternă a sondajului. Apelarea readLcdButtons () funcționează mereu până când modificările valorii sale nu afectează în mod negativ performanța programului și nu trebuie să vă faceți griji în legătură cu lăsarea piniilor de întrerupere disponibile.

void loop () do btnVal = readLcdButtons (); // citește continuu butoanele ... în timp ce (btnVal == 5); // ... până când se apasă ceva
// declare funcția sondaj buton int readLcdButtons () întârziere (90); // delay delay, tuned experimental. întârziere este bine ca programul nu ar trebui să facă altceva // la acest punct oricum adcIn = analogRead (0); // citi valoarea de la pin A0 / * valorile pragului confirmate prin experimentarea cu schița calibrării butonului returnând următoarele valori citite ADC: dreapta: 0 sus: 143 jos: 328 stânga: 504 selectare: 741 * / if (adcIn> 1000) retur btnNone ; dacă (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 () are o întârziere de 90 ms pentru a debounce butoanele. În realitate, acest lucru nu este un debounce, deoarece nu re-lua măsurarea ADC după o perioadă de timp stabilit, ci mai degrabă chestionează butoanele destul de rar pentru a înregistra rareori mai mult de un singur clic. 

Realizează același lucru dintr-o vizualizare practică UX. Este mai mult de a butoanele de sondaj la fiecare 90 ms, mai degrabă decât în ​​mod constant, care este motivul pentru care utilizarea întârziere() nu este, în general, considerată o bună practică în scopuri de dezbatere, însă problema a fost rezolvată (numai la fiecare capăt al meniurilor au fost accesibile).

Pasul 4: Reîmprospătarea ecranului

Odată ce unitatea poate reacționa la intrare, trebuie să existe o modalitate de a afișa aceste reacții. 

După ce am încercat actualizările de pe zbor, am stabilit că actualizarea consistentă a ecranului ca un sistem de operare real a fost mai ușor de gestionat în încercările mele de a avea o structură modulară care poate fi actualizată. Acest lucru este la fel de simplu ca și curățarea ecranului, apoi reconstruirea pe baza unor parametri actuali cunoscuți.
Acest lucru pare complicat, dar în practică face viața mult mai ușoară. Elimină un număr mare de comenzi LCD din alte părți ale programului și creează o zonă de tip agnostic de tip variabil, care este afectată cel puțin de actualizările programului externe.
Partea actuală de revigorare a evoluat astfel încât să cuprindă patru etape distincte:
Resetați parametrii ...

// PRINT VALOAREA SCREENULUI NOU btnVal = btnNone; lcd.clear ();

... imprimați linia de sus ...

lcd.setCursor (0, 0); lcd.print (menuItemsTop [currentMenuItem]); // tipăriți elementul de meniu de nivel superior

... imprima linia de jos, pe care o voi explica mai târziu ...

 lcd.setCursor (0,1); switch (curentMenuItem) caz 0: pentru (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

... și adăugați comenzi specifice ecranului în partea de sus a ceea ce este deja imprimat.

dacă (currentMenuItem == 0) lcd.setCursor (4,1); lcd.print ("mm (max 1300)"); // introduceți călătoria maximă a căruței pe cursorul folosit dacă (currentMenuItem == 1) lcd.setCursor (6,1); lcd.print ( "s (3600 / hr)");  dacă (currentMenuLevel == 1) lcd.setCursor (currentCursorPos, 1); lcd.blink ();  altceva lcd.noBlink ();

Construirea unui meniu: titluri principale

Bineînțeles, acea secțiune de actualizare a ecranului exact nu se scrie și trebuie să cunoaștem meniul pe care scrie pentru a fi afișat înainte de a putea fi completat. Principalele titluri sunt ușor, deoarece nu se schimbă de fapt, în funcție de intrarea utilizatorului. Aceasta înseamnă că poate fi pur și simplu o matrice de șir - din punct de vedere tehnic o matrice de pointer de caractere sau o matrice de matrice:

// GUI MENU // definește șiruri de elemente de meniu de nivel superior pentru navigația numerică char * menuItemsTop [] = "01 Distanță>",< 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;

Asta înseamnă că asta menuItemsTop array pot fi navigate pur și simplu prin modificarea numărului în paranteze pătrate la timpul de reîmprospătare a ecranului. Ceea ce se întâmplă, deoarece totul este indexat la zero, pentru a urmări identic cu întregul currentMenuItem

manipulând currentMenuItem Evenimentele pe buton ne permit navigarea unidimensională, așa că atunci când vedeți menuItemsTop [currentMenuItem] este evident meniul actual al meniului.

dacă (curentMenuLevel == 0) comutator (btnVal) caz btnL: if (currentMenuItem == 0) pauză; // nu poate merge la stânga de aici altceva currentMenuItem--; pauză;  caz btnR: if (currentMenuItem == 4) pauză; // nu poate merge direct de aici altceva currentMenuItem ++; pauză;  caz btnSel: currentMenuLevel ++; dacă (currentCursorPos> 3 && (currentMenuItem == 0 || currentMenuItem == 2)) currentCursorPos = 3; // nu treceți de la sfârșitul numerelor pentru numerele de 4 cifre dacă (currentCursorPos> 0 && (currentMenuItem> 2)) currentCursorPos = 0; // setarea cursorului în stânga pentru opțiunile bazate pe text dacă (currentMenuItem == 4) motion = 1; controlul miscarii(); pauză;  // sfârșitul comutării // sfârșitul nivelului 0

Deci poți să te muți la stânga și la dreapta, și du-te în un meniu sau în cazul Merge! atunci controlul mișcării este activat. Care este tot ceea ce este necesar aici.

Crearea unui meniu: Submeniu

Sistemul de submeniuri a făcut ceva mai mult, datorită complexității sale interne. Primele trei intrări, Distanţă, Durată și paşi, constau din punct de vedere tehnic dintr-un sub-meniu, fiecare permițând navigarea cu valoarea mai multor cifre, precum și cu fiecare caracter individual.

Acest lucru este acoperit prin efectuarea fiecărei intrări de submeniu a unui sistem de rutere cu comutare în sine. În timp ce acest lucru a fost un drum lung, este o metodă simplă și consecventă de a permite astfel de navigare la nivel scăzut. Din moment ce tocmai mi-am dat seama Distanţă submeniul și apoi copiați-l pentru celelalte submeni, iată o privire la acel.

altfel // adică "else if currentMenuLevel = 1" dacă (currentMenuItem == 0) // 01 DISTANCE comutator (btnVal) caz btnUp: currentChar = currentDistance [currentCursorPos]; adjustDigit (curentChar, 1); actualDistanță [actualCursorPos] = actualChar; pauză;  caz btnDn: currentChar = actualDistance [currentCursorPos]; adjustDigit (curentChar, 0); actualDistanță [actualCursorPos] = actualChar; pauză;  caz btnL: if (currentCursorPos == 0) pauză; // nu poate merge la stânga de aici altceva currentCursorPos--; pauză;  caz btnR: if (currentCursorPos == 3) pauză; // nu poate merge la stânga de aici altceva curentCursorPos ++; pauză;  caz btnSel: parseArrayDistance (); currentMenuLevel--;  // comutator de sfârșit / / termină DISTANCE

Stânga și dreapta sunt, în esență, aceleași ca și meniul de nivel superior, pur și simplu în mișcare înainte și înapoi de-a lungul numărului în același mod, număr de fapt, un set de cifre într-un tablou int și locația curentă stocată într-un int numit currentCursorPos care permite clipește, așa cum se vede în modulul de actualizare a ecranului de mai sus. 

Imprimarea acestor tablouri de-a lungul rândului LCD de jos este ceea ce pentru buclele de for a fost în secțiunea de reîmprospătare a ecranului; eu din 0 la 3, Coloană LCD din 0 la 3, currentDistance [] din 0 la 3.

int setDigit (int x, int dir) // funcția de reglare a cifrei dacă (dir == 0 && x> 0) x--; // scădea din cifre pe btnDn dacă (dir == 1 && x < 9) x++; // add to digit on btnUp lcd.setCursor(currentCursorPos, 1); lcd.print(x); currentChar = x; return currentChar; //return new digit 

Creșterea și scăderea numărului este realizată prin stocarea cifrei curente în variabilă currentChar, care este apoi trecut la adjustDigit () funcționează împreună cu o valoare booleană indicând direcția; pentru a mări sau a micșora motorul. 

Acest lucru ajustează pur și simplu cifra în funcție de valoarea booleană și salvează rezultatul, unde fluxul revine la bucla principală, unde valoarea curentăChar este salvată în poziția corectă a originalului currentDistance [] și noua cifră ajustată este imprimată la reîmprospătarea ecranului.

Parsarea valorilor array afișate

Când selectați este lovit de la unul dintre submeniurile de numere de matrice, acesta declanșează funcția de analiză relevantă - în acest caz parseArrayDistance (). Trebuie să parseze matricea, utilizată pentru afișarea și editarea convenabilă, într-un întreg util pentru calculele de mișcare reale. Am ales să fac acest lucru acum, mai degrabă decât pe Merge! pentru a menține UX senzațional.

int setDigit (int x, int dir) // funcția de reglare a cifrei dacă (dir == 0 && x> 0) x--; // scădea din cifre pe btnDn dacă (dir == 1 && x < 9) x++; // add to digit on btnUp lcd.setCursor(currentCursorPos, 1); lcd.print(x); currentChar = x; return currentChar; //return new digit 

Am venit cu această funcție de la un comentariu de trecere utilă pe care l-am găsit după ce am epuizat-o pe Google căutând funcții standard de tip array-to-int, ajungând goale și eliminând mizeria dintre funcțiile array-to-char-to-int o soluție ineficientă. Pare destul de scurtă și ușoară, având în vedere că se bazează literalmente pe temelia matematicii zecimale, dar dacă știți o metodă mai bună, eu sunt urechi.

Controlul mișcării și declanșarea camerei

Toate valorile sunt setate și ați lovit Merge! Ce se întâmplă în continuare? Trebuie să calculați exact ce ar trebui să facă numerele date pentru a executa mișcarea finală. Această parte este funcțională, dar o lucrare în desfășurare; Cred că trebuie să existe mai multe opțiuni pentru diferite tipuri de mișcare.

int miControl () totalMotorSteps = actualDistanceInt * 5; // calculați pașii totali (0.2mm = 20 de viteze dințate pe o curea cu pas de 2mm; 40mm pe rev, 200 trepte pe rev, ergo 1/5 mm pe pas) pulseDelay = (1000L * (curentDurationInt - (currentStepsInt * shutterDuration) / totalMotorSteps; // timpul de pauză în ms între impulsurile STP la intervalul driverului motoruluiDistance = totalMotorSteps / currentStepsInt;

Ce se întâmplă în această funcție este destul de clară din comentarea, cred. Am pus un a shutterDuration de 2 secunde în software, în principal pentru a menține testarea destul de rapidă. Dacă fotografiați noaptea, la o valoare ISO mai mică, este posibil ca aceasta să dureze mai mult de 25-35 de secunde, în funcție de viteza exactă a obturatorului.

pulseDelay este înmulțită cu 1000 la sfârșit pentru a converti de la secunde la milisecunde, desigur. L pentru a converti int constant la un lung este mai mult eroare pe partea de prudență decât de fapt fiind strict necesar. Deoarece este o schiță relativ mică, nu mă prea preocupă de utilizarea memoriei variabile.

Aceste calcule presupun că bucla în sine necesită o perioadă neglijabilă de timp pentru a rula în comparație cu pulseDelay timp, care, odată ce am scos butonul de chestionare, pare să fie adevărat.

// o dată pe run general dacă (travelDir == 0) digitalWrite (dir, LOW); altfel dacă (travelDir == 1) digitalWrite (dir, HIGH); //Serial.begin(9600); //Serial.println(pulseDelay); // step loop do digitalWrite (stp, HIGH); // întârziere pas întoarcere șofer motor (pulseDelay); digitalWrite (stp, LOW); // reset driver // btnVal = readLcdButtons (); // verificați dacă nu există nicio oprire - aceasta durează prea mult și încetinește semnificativ motorul; utilizați resetul pentru oprire! currentStep ++; // la sfarsitul fiecarui pas daca (curenteStep% intervalDistance == 0) // daca numarul curent de pasi al motorului este divizibil prin numarul de pasi de motor intr-o etapa a camerei, incendiati camera digitalWrite (trig, HIGH); // întârzierea declanșării declanșatorului camerei (80); digitalWrite (trig, LOW); // resetare întârziere pin declanșator ((shutterDuration * 1000) -80); // întârziere necesită schimbarea la cronometru, astfel încât butonul stop poate fi interogat în timp ce (currentStep < totalMotorSteps);  //end motion control

În cele din urmă, rețineți currentSteps valoare setată la 1. Nu am creat o funcție de verificare a erorilor pentru acest lucru, dar simțul bun simț spune mărimea pasului devine infinit dacă curentStepsInt == 0, deci este mai bine să o păstrați la unu dacă doriți o mișcare continuă. Am adăugat deja o înregistrare de îmbunătățire pentru acest lucru.

Rularea produsului final

Pentru ceva care rulează pe cod scrise mai mult sau mai puțin de la zero în două zile și bugfixed peste încă două, funcționează ca un vis! Dovada este în budincă, totuși. De fapt, merită înregistrată o perioadă de timp utilă, iar unitatea de control funcționează cu adevărat bine pe teren?

În testele mele, răspunsul pare a fi un răspuns cu toată inima. Mai jos este o perioadă de timp de două ore, de 650 de cadre, primul test. Glisorul a finalizat, de asemenea, un test de 9 ore pe 720 de cadre fără nici un fel, dar, din păcate, bateria camerei nu a făcut așa bine după 2 ore în ... pe care nu am aflat până la marcajul de 8.5 ore,.

Dacă am stabilit timpul și pașii în mod corespunzător, mișcarea poate fi continuă pentru mișcări lentă de dolly în filmul de acțiune live, deși capetele tanguibile au nevoie de editare sau de viteză. 

Sunetul poate fi o problemă, cu excepția cazului în care pasagerul tău este foarte liniștit, dar pentru a adăuga valoare de producție auto-înregistrărilor, este o opțiune.

îmbunătăţiri

Ca și în cazul tuturor, sunt posibile îmbunătățiri care trebuie făcute. Am enumerat aceste informații în partea de sus a paginii .eu nu fișier, deși, fără îndoială, fără deosebire de fezabilitate și fără nici un fel de importanță. 

Unele dintre acestea am considerat de stabilire înainte de a elibera acest tutorial cu v0.2, dar mă simt ca ele însele sunt o experiență de învățare să se uite în termeni de dezmembrare mentală utilitatea unui program.

 ÎMBUNĂTĂȚIRI ȘI CONSIDERAȚII CĂTRE V1.0: 1) Eficiența codului de răspuns al butonului de submeniu pentru primele trei anteturi de meniu 2) Utilizarea timpului de expunere al becului ca opțiune de meniu suplimentară, trecând la shutterDuration int 3) Durata declanșatorului trebuie să fie temporizată, ) - nu se poate opri butonul de oprire! 4) Utilizați funcțiile bibliotecii EEPROM pentru a salva cantități, puteți astfel simplifica secțiunea de control al mișcării și utilizați Resetați ca "oprire" 5) Scoateți comutatorul din submeniul "Go", înlocuiți cu o declarație logică mai adecvată 6) mai degrabă decât călătoria totală? "durata" fiind mai mult ca 15 sec sau 2 min 30 min sau 4 ore? 7) Orice const ints care ar fi mai bine ca #define sau ints mai bine ca boolean? Făcându-se aproape de limitele spațiului SRAM la 8kB, totuși. 8) Tweening / relaxare pentru curbele de accelerație, în special pentru utilizarea video 9) Verificarea erorilor pentru dimensiunea zero pas, sau pur și simplu adăugați una la intervalDistance dacă valoarea este zero înainte de calcule- altul sfârșit de Distanța este încă 1 pas 10) ar sub-16ms întârziere () s fi mai bine ca delayMicroseconds ()? Cât de mult întrerupe distrugerea calendarului? 11) Utilizarea somnului pe A4988 pentru a reduce consumul de energie în câmp? 12) Verificați eroarea pentru curentDurațieInt <= currentStepsInt*shutterDuration, allowing no time for movement or even negative pulseDelay! */

Acestea sunt doar îmbunătățirile pe care le-am crezut până acum, într-un efort de a ghida codul de bază de la o rudimentară dar funcțională v0.2 spre o versiune mai optimizată și mai capabilă v1.0. Puteți observa mai multe. Simțiți-vă liber să le lăsați în comentariile de mai jos sau pe GitHub.

Înfășurarea în sus

Dacă ați urmat de la început până la sfârșit, inclusiv porțiunea Photo Tuts + a construirii, acum sunteți proprietarul mândru al unui slider de cameră motorizat de înaltă calitate, care poate produce înregistrări temporale și mișcări subtile. Dacă utilizați codul pentru un alt proiect, mi-ar plăcea să îl văd.

În acest tutorial, am analizat diferite forme de control al debitului bazate pe buclă, creând o interfață grafică rudimentară și actualizând un ecran LCD bazat pe intrarea utilizatorului. De asemenea, m-am uitat la controlarea simultană a mai multor dispozitive mecanice externe prin plăci de rupere. 

Ați văzut fluxul și ușurința de programare a codului modular, precum și vedeți idei pentru îmbunătățirea codului care este funcțional, dar nu este optimizat, atât din punctul de vedere al UX cât și al eficienței procesorului. Aceste instrumente ar trebui să vă servească bine pentru o varietate de proiecte de comunicare și interacțiune pe v