Bewegungssteuerung mit Arduino Motorisieren eines Kamera-Schiebereglers

Die Verfügbarkeit billiger Schrittmotoren und Treiber bietet heutzutage reichlich Gelegenheit, außerhalb der teureren und komplizierteren 2D / 3D-Schneid- und Druckprojekte zu experimentieren. 

Für dieses Projekt nehme ich den OpenBuilds-Kamera-Schieberegler (siehe Build-Video unter Erstellen eines Standard-Videoschiebereglers mit Open Source-CNC-Teilen) und motorisiere ihn. Ich werde auch ein in sich geschlossenes System zur Steuerung des Motors erstellen.

Dieses Tutorial befasst sich speziell mit dem Zusammensetzen der Hardware. In erster Linie wird jedoch eine rudimentäre 16x2-LCD-GUI mit der LiquidCrystal-Bibliothek und einem einfachen Menüsystem für die Anzeige erstellt. Anschließend wird die Funktionsweise des A4988-Steppertreibers sowie die Steuerung mit Arduino beschrieben. 

Dieses Projekt ist schwer in Loops und Schritten, und obwohl das Projekt insgesamt eher mittelmäßig ist, habe ich versucht, es so zu erklären, dass Anfänger relativ schnell einsatzbereit sind.

Ausrüstungsliste

Komponenten

  • Arduino Uno
  • LCD-Tastaturabschirmung oder separate 16x2-LCD-Anzeigen und Tasten, wenn Sie wissen, wie dies funktioniert
  • Pololu A4988 [Black Edition] Stepper Driver
  • Kleiner selbstklebender Kühlkörper aus Aluminium
  • Breadboards, männliche und weibliche Schaltdrähte usw
  • 220-330 Ohm Widerstand (1 / 4W wird wahrscheinlich ausreichen), Standard-NPN-Transistor (ich habe einen BC109 verwendet)
  • 3,5 mm Stereo-Klinkenbuchse
  • 3,5 mm bis 2,5 mm Stereo-TRS-Adapterkabel
  • 3,5 mm Verlängerungskabel je nach Länge des Schiebers
  • 9-V-Fasssteckdose, wenn Sie das Arduino von der USB-Stromversorgung des Computers trennen möchten
  • 12V 2A Stromversorgung zum Betrieb des Schrittmotors
  • NEMA 17 Schrittmotor

Teile

  • GT2 5 mm breiter Zahnriemen mit 2 mm Abstand: doppelte Länge des Schiebers plus Sicherheitsfuß (11 Fuß für mich)
  • Glatte Umlenkrolle
  • Riemenspannungs-Torsionsfeder, wenn Sie Schwierigkeiten haben, die Riemenspannung über längere Zeit aufrechtzuerhalten
  • 2x Gürtelklemmschelle (kann durch kleine Zipties ersetzt werden)
  • GT2 7 mm breite, 20-zahnige Aluminium-Riemenscheibe mit gleicher Bohrungsgröße wie die Motorwelle
  • 4x 30 mm M3-0.5 Zylinderschrauben

Werkzeuge

  • Computer mit Arduino IDE (Ich verwende Win7, Arduino 1.0.5 r2)
  • Lötkolben mit kleiner Meißelspitze, Löten usw
  • 2,5 mm Inbusschlüssel für M5-Schrauben
  • 2mm Inbusschlüssel für M3-Schrauben
  • 1,5-mm-Inbusschlüssel für Gewindestifte in der GT2-Rolle
  • Multimeter zur Fehlersuche und Stromeinstellung
  • Schmale Zange zum Spannen in kleinen Räumen

Funktionsüberblick

Ich werde darauf eingehen, den Motor und die Riemenscheiben dem Schieber hinzuzufügen, den Riemen herumzuschnüren und alles zu befestigen. Es ist eine einfache Modifikation. 

Dann werde ich überlegen, wie man ein Pololu A4988 Black Edition-Kit zusammensetzt und wie man es zusammen mit allen anderen externen Boards auf einem Steckbrett aufdrahtet, sowie mit einem einfachen Sperrholzgehäuse, das ich in ein paar Minuten für meine 12-V-Stromversorgung zusammengeschlagen habe Versorgung (oben aufgeführt), um Stöße zu vermeiden, wenn die Verdrahtungsklemmen freigelegt werden.

Seitlich bleibt es also groß genug, dass die Pin-Nummern noch sichtbar sind!

Das Menü ermöglicht die Eingabe von Entfernung zu reisen, Zeit zu reisen, Anzahl der Schritte, in denen Sie reisen müssen und Fahrtrichtung. Am Ende jedes Schrittes hält der Schieberegler an, während die Kamera ausgelöst wird.

Ändern des Schiebereglers

Schritt 1: Motormontage

Die Endmontage des OpenBuilds-V-Slot-Aktuators verfügt über NEMA-Löcher mit 17 Abmessungen, so dass nur vier 30-mm-M3-Kopfschrauben für die Montage des Motors erforderlich sind.

Der OpenBuilds V-Slot-Aktuator-Endhalter

Stellen Sie sicher, dass sich die GT2-Riemenscheibe mit 20 Zähnen in der Halterung befindet, bevor Sie die Motorwelle einschieben, da die Halterung nicht breit genug ist, um sie danach wieder anzubringen. Wenn der Motor unten angeschraubt ist, ziehen Sie die Gewindestifte mit einer von ihnen gegen den flachen Teil der Motorwelle an, und stellen Sie sicher, dass die Zähne direkt mit der Mitte der gesamten Extrusionseinheit übereinstimmen.

Schritt 2: Umlenkrollen-Kit

Das Umlenkrollen-Kit passt wie ein Rad-Kit zusammen und wird in die gegenüberliegende Ende der Stellantriebshalterung gesteckt:

Das Umlenkrollen-Kit

Schritt 3: Anschnallen

Führen Sie den Riemen durch die Mitte des Keilschlitzes in einer Linie mit den Riemenscheiben, und stellen Sie dabei sicher, dass die Zähne nach oben zeigen. 

Füttern Sie es dann über die beiden Rollen und bringen Sie es zurück in die Mitte der Dolly-Bauplatte.

Die Zähne greifen ineinander.

Hier wickeln Sie eine Seite durch den Gurtschlitz und klemmen ihn fest oder befestigen Sie ihn mit einem Reißverschluss. Anschließend ziehen Sie den gesamten Gurt durch das gesamte System, bevor Sie die andere Seite anschließen. Nicht zu fest für den Motor, um sich zu drehen, aber nicht locker genug, um die Zähne an der Antriebsscheibe zu überspringen!

Elektronik montieren

Schritt 1: Montieren Sie den Stepper Driver

Der Pololu A4988 Black Edition-Schrittmotortreiber (technisch gesehen die A4988-Trägerplatine - der A4988 ist der Chip selbst) wird in der Regel als Bausatz geliefert, was lediglich bedeutet, dass die Header aufgelötet werden müssen. Da es sich hierbei um eine Leistungskomponente handelt, die das Gerät nicht mit maximaler Kapazität antreibt, ist es eine gute Idee, einen Kühlkörper hinzuzufügen, um die Lebensdauer zu erhöhen.
Teilen Sie die Kopfzeile in zwei Hälften, um zwei Reihen von acht zu erhalten. Stecken Sie diese in die Durchgangslöcher in der Platine und dann vorsichtig in das Steckbrett. Löten Sie die Stifte an Ort und Stelle, während das Steckbrett alles schön und senkrecht hält.

Stepper Driver zusammenstellen

Wenn dies abgeschlossen ist, schneiden Sie die Ecke eines kleinen selbstklebenden Kühlkörpers mit einer Bügelsäge oder einer Bandsäge (vorsichtig in einer Klemme!) Ab, um den A4988 IC zu montieren.

Schneiden Sie die Ecke eines kleinen Self-Stick-Kühlkörpers ab

Schritt 2: Breadboard-Montage der Komponenten

Jetzt muss alles auf Breadboards montiert werden, damit es zu einem funktionierenden Schaltkreis zusammengeschaltet werden kann. Ich benutze separate Platinen für jedes Teil, um die Bilder klarer zu gestalten. Sie können jedoch alles in eine einzige Platine einfügen, wenn Sie dies wünschen.
Die Abschirmung der LCD-Tastatur kann nicht auf einer Platine montiert werden, da Arduino sich seltsam dazu entschieden hat, einen Konstruktionsfehler zu befolgen, anstatt Standards zu erfüllen. Dies wird getrennt gehalten, obwohl das Anschrauben an ein Stück Holz oder etwas zum Schutz der Stifte keine schlechte Idee ist.

Die Kamera-Triggerschaltung besteht in ihrer einfachsten Form aus einem Widerstand, einem Transistor und einem 2,5-mm-TRS-Submini-Stecker. Ich habe eine LED hinzugefügt, die blinkt, wenn der Trigger-Pin hoch ist, und eine 3,5-mm-TRS-Minibuchse, um Flexibilität zu ermöglichen. 

Wenn Sie Komponenten für diesen Build kaufen, wäre ein 3,5-mm-Sockel für 0,1-Zoll-Pitchboards eine gute Idee, aber meiner stammt vom gespülten Haufen. Ich habe stattdessen einen Steckverbinder daran gelötet.
Legen Sie alles aus und machen Sie alles fertig.

Schritt 3: Alles miteinander verbinden

Zeit, alle Überbrückungskabel zu ergreifen. Wenn Sie genug Farbe haben, um farbcodiert zu bleiben, wird das Leben bei der Fehlerbehebung einfacher. Beachten Sie das Schaltbild oben, wenn die folgende Beschreibung Sie an einem beliebigen Punkt verwirrt.

Alles miteinander verbinden

Verdrahten Sie zuerst das LCD. Schnappen Sie sich 10 weibliche Steckbrücken und verbinden Sie sie mit den folgenden Schirmstiften: Digitale Stifte 4-9, Power-Bus-Stifte werden zurückgesetzt (wenn Sie die LCD-Reset-Taste verwenden möchten), 5 V und einer der GNDs. 

Wenn Sie Springer von Frau zu Mann haben, können Sie sie dort belassen. Andernfalls verbinden Sie männliche Jumper mit dem anderen Ende der Weibchen, um sie in die entsprechenden Arduino-Header-Buchsen zu stecken. Wenn Sie über eine LCD-Tastaturabschirmung verfügen, auf der Durchgangsbuchsen mit Durchgangskontakten installiert sind, können Sie diesen Schritt überspringen, da Ihr Schild nichts blockiert.
Als nächstes das Pololu A4988 Board. Dazu werden acht Jumper auf einer Seite benötigt. Ich habe Schwarz und Rot für Logik / Motorleistung am Ende des Eschens verwendet, und Rot / Grün / Blau / Gelb in der Mitte vier, um mit den Servokabeln des Schrittmotors übereinzustimmen. 

Der Logik-Power-Pin geht beim Arduino auf 3,3 V, da der LCD-Bildschirm oben den 5 V-Pin verwendet. Die Motorkabel führen zu Ihrer 12V-Stromversorgung. Auf der anderen Seite, in der Nähe des A4988-Chips, verwende ich für STP und DIR jeweils Blau und Orange, um sich mit den relativ einheitlichen Farben überall in Kontrast zu setzen. Sie gehen zu den Arduino-Pins 11 und 12, sofern Sie den Code nicht ändern. Dann kurz RST und SLP zusammen, um die Platine aktiviert zu halten. Ich habe hier die weiße Mine benutzt.

Wenn Sie fertig sind, sollte es ungefähr so ​​aussehen.

Schließen Sie schließlich den Kameraauslöseschaltkreis an. Hier sind die schwarzen Drähte geerdet - das A-Row-Kabel zu Arduino, das C-Row-Kabel zur 3,5-mm-Buchse. Das Gelbe geht an Arduino Pin 13 (es gibt sowohl auf der Platine als auch am Schalter eine LED-Anzeige!), Und der rote Draht geht auf die andere Seite der 3,5-mm-Buchse (oder 2,5-mm-Steckerleitung, wenn Sie gehen.) diese Route).
Stecken Sie den Schrittmotor gemäß dem A4988-Platinenplan und dem Datenblatt Ihres Steppers in die farbigen Drähte. Für mich war das so:

Wie beim Tastenleser ist die Testrotationsskizze im Reißverschluss oben enthalten.

Vorsicht: Denken Sie daran, dass die Drähte, die den Motor mit Strom versorgen, bei Ihrer gewählten Spannung wahrscheinlich 1-2 A ziehen. Stellen Sie daher sicher, dass die verwendeten Drähte dafür ausgelegt sind. Der A4988-Chip und die Platine können heiß werden! Das in die Platine eingebaute Potentiometer bietet eine Strombegrenzung zum Schutz des A4988 und des Motors. Stellen Sie daher sicher, dass Sie ihn vor der Verwendung eines Multimeters richtig eingestellt haben.

Einrichten des Programms

Nachdem die Komponenten zusammengebaut wurden, können Sie zur Kodierung wechseln. Laden Sie die in diesem Tutorial enthaltene ZIP-Datei herunter, oder überprüfen Sie dieses GitHub-Repository, wenn Sie möchten. Ich werde beschreiben, wie ich es zusammensetze, damit Sie den allgemeinen Programmablauf verstehen und wie die Module zusammenarbeiten.

Schritt 1: Includes und grundlegende Definitionen

Das einzige notwendige dazu war die LCD-Schreibbibliothek LiquidCrystal.h. Dies gibt Zugriff auf die lcd.xxxx () Funktionen. Da ist ein pow () im Programm, und ich fand das einschließlich der C ++ - Bibliothek math.h Dies ist nicht unbedingt erforderlich, da einige der hilfreichsten Funktionen in der Standard-Arduino-Umgebung enthalten sind, einschließlich pow ().


#umfassen  Flüssigkristall-LCD (8, 9, 4, 5, 6, 7); // LCD-Ausgangspins setzen // Stepper-Treiberpins definieren const int stp = 11; // kann Pin 10 nicht mit dem SS-LCD verwenden, da dies die Hintergrundbeleuchtung ist. // Wenn es niedrig wird, schaltet sich die Hintergrundbeleuchtung aus! const int dir = 12; // Abzugsstift definieren const int trig = 13; // BUTTONS // Tastenwerte definieren const int btnUp = 0; const int btnDn = 1; const int btnL = 2; const int btnR = 3; const int btnSel = 4; const int btnNone = 5; // Definiere Tastenlesevariablen int btnVal = 5; int adcIn = 0;

Ich setze die LCD-Ausgangspins, die Stepper-Treiberausgangspins und den Kamera-Trigger-Ausgangspin. Nachdem die eigentliche Hardwareschnittstelle eingerichtet wurde, fügte ich Variablen für Schaltflächenereignisse hinzu, gefolgt von der Funktion zum Lesen der Schaltflächen, die ich aus dem DFRobot-Wiki an ihren identischen LCD-Tastaturschild angepasst habe. Beachten Sie, dass SainSmart keine Dokumentation bereitstellt.

Schritt 2: Setup () Loop

Das ist super geradlinig. Initialisieren Sie die LCD-Anzeige und die entsprechenden Ausgangspins, gefolgt von einem einfachen Begrüßungsbildschirm, und wechseln Sie in den Startbildschirm: Menüoption 1 mit Nullwerten.

void setup () lcd.begin (16, 2); // LCD lib Vollbild initialisieren lcd.setCursor (0,0); // Cursorposition setzen pinMode (stp, OUTPUT); // Stepper-Pins initialisieren pinMode (dir, OUTPUT); PinMode (Trigger, OUTPUT); // Trigger-Pin initialisieren digitalWrite (Trig, LOW); // Sicherstellen, dass der Trigger deaktiviert ist lcd.print ("Welcome to"); // Begrüßungsbildschirm lcd.setCursor (0,1); lcd.print ("SliderCam v0.2!"); Verzögerung (1000); lcd.clear (); lcd.print (menuItemsTop [0]); Verzögerung (100); lcd.setCursor (0,1); für (int i = 0; i < 4; i++)  lcd.setCursor(i, 1); lcd.print(currentDistance[i]);  lcd.setCursor(4,1); lcd.print("mm(max 1300)"); 

Schritt 3: Überwachen Sie die Tasten

Der Vorteil dabei ist, dass das Gerät ohne Benutzereingaben überhaupt nichts tun muss. Was bedeutet, dass das allererste einfach eine ewige Knopfabfrageschleife sein kann. Anrufen der readLcdButtons () Die Funktion funktioniert immer und immer wieder, bis sich der Wert ändert, und die Programmleistung wird dadurch nicht beeinträchtigt. Sie müssen sich keine Sorgen machen, Interrupt-Pins verfügbar zu lassen.

void loop () do btnVal = readLcdButtons (); // lese die Tasten ständig… while (btnVal == 5); //… bis etwas gedrückt wird
// Deklarieren der Button-Abfragefunktion int readLcdButtons () delay (90); // Debounce-Verzögerung, experimentell abgestimmt. delay ist in Ordnung, da das Programm sowieso nichts anderes tun sollte // an dieser Stelle sowieso adcIn = analogRead (0); // Wert von Pin A0 / * lesen. Schwellenwerte, die durch Experimentieren bestätigt wurden. Die Kalibrierungsskizze der Tasten gibt die folgenden ADC-Lesewerte zurück: Rechts: 0 bis: 143 unten: 328 links: 504 select: 741 * / if (adcIn> 1000) liefert btnNone ; 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 () hat eine Verzögerung von 90ms um entprellen die Knöpfe. Tatsächlich ist dies keine Entprellung, da die ADC-Messung nach einer bestimmten Zeit nicht erneut durchgeführt wird, sondern die Tasten eher selten abgefragt werden, um selten mehr als einen einzigen Klick zu registrieren. 

Dasselbe erreicht man aus einer praktischen UX-Ansicht. Es ist mehr ein Poll-Buttons alle 90ms statt ständig, Deshalb verwenden Sie verzögern() wird im Allgemeinen nicht als bewährtes Verfahren zum Entprellen angesehen, aber es wurde das Problem behoben (nur an jedem Ende der Menüs war ein Zugriff möglich).

Schritt 4: Bildschirmaktualisierung

Sobald das Gerät auf Eingaben reagieren kann, muss es eine Möglichkeit geben, diese Reaktionen anzuzeigen. 

Nach dem Ausführen von Sofortaktualisierungen stellte ich fest, dass eine konsistente Bildschirmaktualisierung wie bei einem echten Betriebssystem bei den Versuchen einer modularen aufrüstbaren Struktur einfacher zu verwalten ist. Dies ist so einfach wie das Löschen des Bildschirms und das erneute Erstellen anhand der aktuellen Parameter.
Das hört sich kompliziert an, erleichtert aber in der Praxis das Leben. Es entfernt eine große Anzahl von LCD-Befehlen an anderen Stellen des Programms und erstellt eine agnostische Zone mit variablem Typ, die durch Programmaktualisierungen außerhalb dieses Programms nur minimal beeinträchtigt wird.
Der eigentliche Auffrischungsabschnitt bestand aus vier verschiedenen Schritten:
Parameter zurücksetzen…

// NEUE BILDSCHIRMWERTE DRUCKEN btnVal = btnNone; lcd.clear ();

… Die oberste Zeile drucken…

lcd.setCursor (0, 0); lcd.print (menuItemsTop [currentMenuItem]); // Menüpunkt der obersten Ebene drucken

… Drucken Sie die untere Zeile aus, die ich später erklären werde…

 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

… Und fügen Sie bildschirmspezifische Befehle über das bereits Gedruckte hinzu.

if (currentMenuItem == 0) lcd.setCursor (4,1); lcd.print ("mm (max. 1300)"); // Max. Wagenlauf mit verwendetem Schieberegler einfügen if (currentMenuItem == 1) lcd.setCursor (6,1); lcd.print ("s (3600 / h)");  if (currentMenuLevel == 1) lcd.setCursor (currentCursorPos, 1); lcd.blink ();  else lcd.noBlink ();

Ein Menü erstellen: Hauptüberschriften

Natürlich schreibt der genaue Abschnitt für die Bildschirmaktualisierung nicht selbst, und wir müssen wissen, welches Menü auf den Bildschirm geschrieben wird, bevor es abgeschlossen werden kann. Die Hauptüberschriften sind einfach, da sie sich in Abhängigkeit von den Benutzereingaben nicht wirklich ändern. Dies bedeutet, dass es sich einfach um ein String-Array handeln kann - technisch ein Zeichenzeiger-Array oder ein Array von Arrays:

// MENÜ-GUI // Festlegen von Menüelement-Strings auf oberster Ebene für numerische Navigationszeichen * 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;

Dies bedeutet, dass dies menuItemsTop Array kann einfach durch Ändern der Zahl in den eckigen Klammern zur Bildschirmaktualisierungszeit navigiert werden. Was genau so geschieht, da alles nullindiziert ist, um mit der ganzen Zahl identisch zu verfolgen currentMenuItem

Manipulieren currentMenuItem on button events ermöglicht uns eine eindimensionale Navigation, also wenn Sie sehen menuItemsTop [aktuellesMenuItem] es ist offensichtlich aktuelle Menüüberschrift.

if (currentMenuLevel == 0) switch (btnVal) Fall btnL: if (currentMenuItem == 0) break; // kann von hier nicht nach links gehen sonst currentMenuItem--; brechen;  case btnR: if (currentMenuItem == 4) break; // kann von hier aus nicht weitergehen else currentMenuItem ++; brechen;  case btnSel: currentMenuLevel ++; if (currentCursorPos> 3 && (currentMenuItem == 0 || currentMenuItem == 2)) currentCursorPos = 3; // Das Ende der Zahlen für die vierstelligen Zahlen darf nicht überschritten werden, wenn (currentCursorPos> 0 && (currentMenuItem> 2)) currentCursorPos = 0; // Setzen Sie den blinkenden Cursor für textbasierte Optionen auf links, wenn (currentMenuItem == 4) motion = 1; Bewegungskontrolle(); brechen;  // Ende des Schalters // Ende der Ebene 0

Sie können sich also nach links und rechts bewegen und losfahren in ein Menü oder im Fall von Gehen! dann ist die Bewegungssteuerung aktiviert. Das ist alles was hier benötigt wird.

Ein Menü erstellen: Untermenü

Das Untermenüsystem machte dank seiner internen Komplexität etwas mehr Arbeit. Die ersten drei Einträge, Entfernung, Dauer und Schritte, bestehen technisch aus einem Unter-Untermenü, von dem jedes die Navigation des mehrstelligen Werts sowie jedes einzelnen Zeichens ermöglicht.

Dies wird dadurch abgedeckt, dass jeder Untermenüeintrag ein eigenständiges System mit geschalteten Überschriften ist. Dies ist zwar ein weiter Weg, aber es ist eine einfache und konsistente Methode, um eine solche Navigation auf niedriger Ebene zu ermöglichen. Da habe ich die wirklich nur rausgefunden Entfernung Untermenü und kopierte es dann für die anderen Untermenüs, hier ist ein Blick darauf.

else // d. h. "else if currentMenuLevel = 1" if (currentMenuItem == 0) // 01 DISTANCE-Schalter (btnVal) case btnUp: currentChar = currentDistance [currentCursorPos]; adjustDigit (currentChar, 1); currentDistance [currentCursorPos] = currentChar; brechen;  case btnDn: currentChar = currentDistance [currentCursorPos]; adjustDigit (currentChar, 0); currentDistance [currentCursorPos] = currentChar; brechen;  case btnL: if (currentCursorPos == 0) break; // kann von hier nicht weitergehen, sonst currentCursorPos--; brechen;  case btnR: if (currentCursorPos == 3) break; // kann von hier nicht weitergehen, sonst currentCursorPos ++; brechen;  case btnSel: parseArrayDistance (); currentMenuLevel--;  // Endschalter // DISTANCE beenden

Links und rechts entsprechen im Wesentlichen dem Menü der obersten Ebene. Sie bewegen sich einfach auf dieselbe Weise vor und zurück, indem Sie die Nummer tatsächlich eine Menge von Ziffern in einem int-Array und der aktuelle Ort in einem int gespeichert werden currentCursorPos Dies ermöglicht das Blinken, wie im Bildschirmaktualisierungsmodul oben gezeigt. 

Das Drucken dieser Arrays entlang der unteren LCD-Reihe ist das, wofür die for-Schleifen im Bildschirmaktualisierungsabschnitt waren. ich von 0 zu 3, LCD-Säule von 0 zu 3, currentDistance [] von 0 zu 3.

int adjustDigit (int x, int dir) // Stellenanpassungsfunktion if (dir == 0 && x> 0) x--; // subtrahiere von digit auf 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 

Das Erhöhen und Verringern der Anzahl wird durch Speichern der aktuellen Ziffer in der Variablen erreicht currentChar, das wird dann an die übergeben adjustDigit () Funktion zusammen mit einem booleschen Wert, der die Richtung angibt; zum Erhöhen oder Verringern des Motors. 

Dadurch wird die Ziffer einfach an den booleschen Wert angepasst und das Ergebnis gespeichert, woraufhin der Fluss zur Hauptschleife zurückkehrt, wo der currentChar-Wert wieder an der korrekten Position des Originals gespeichert wird currentDistance [] Array und die neue eingestellte Ziffer wird bei der Bildschirmaktualisierung gedruckt.

Analysieren von Anzeigearraywerten

Wenn Select aus einem der Zahlenfeld-Untermenüs getroffen wird, löst es die entsprechende Parsing-Funktion aus - in diesem Fall parseArrayDistance (). Sie müssen das zur bequemen Anzeige und Bearbeitung verwendete Array in eine Ganzzahl für tatsächliche Bewegungsberechnungen analysieren. Ich entschied mich, dies jetzt zu tun und nicht weiter Gehen! UX fühlt sich gut an.

int adjustDigit (int x, int dir) // Stellenanpassungsfunktion if (dir == 0 && x> 0) x--; // subtrahiere von digit auf 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 

Ich kam mit dieser Funktion aus dem einen nützlichen Passing-Kommentar, den ich gefunden hatte, nachdem ich Google erschöpft nach Standard-Array-to-Int-Funktionen gesucht hatte, leer kam und das Chaos der Array-to-Char-to-Int-Funktionen loswurde ein ineffektiver Workaround. Es erscheint ziemlich kurz und leicht, wenn man bedenkt, dass es buchstäblich auf der Grundlage der Dezimalmathematik basiert. Wenn Sie jedoch eine bessere Methode kennen, bin ich ganz Ohr.

Bewegungssteuerung und Kameraauslösung

Alle Werte sind eingestellt und Sie treffen Gehen! Was passiert als nächstes? Sie müssen genau berechnen, was die Zahlen tun sollen, um die letzte Bewegung auszuführen. Dieser Teil ist funktional, aber noch in Arbeit. Ich habe das Gefühl, dass es mehr Optionen für verschiedene Bewegungsarten geben muss.

int motionControl () totalMotorSteps = currentDistanceInt * 5; // Gesamtschritte berechnen (0,2 mm Zahnrad mit 20 Zähnen auf 2 mm Teilungsband; 40 mm pro Umdrehung, 200 Schritte pro Umdrehung, dh 1/5 mm pro Schritt) pulseDelay = (1000L * (currentDurationInt - (currentStepsInt * shutterDuration))) / totalMotorSteps; // wie lange in ms zwischen STP-Impulsen zum Motortreiberintervall pausiert werdenDistance = totalMotorSteps / currentStepsInt;

Was in dieser Funktion passiert, ist aus dem Kommentar ziemlich klar, denke ich. Ich habe ein gesetzt Verschlusszeit von 2 Sekunden in der Software, hauptsächlich um das Testen ziemlich schnell zu halten. Wenn Sie bei Nacht und bei niedrigeren ISO-Werten aufnehmen, muss dies je nach Ihrer genauen Verschlusszeit möglicherweise mehr als 25 bis 35 Sekunden betragen.

Das pulseDelay wird mit multipliziert 1000 am Ende natürlich von Sekunden in Millisekunden konvertieren. Das L Die Konstante int in eine long umzuwandeln, ist eher auf der Seite der Vorsicht als wirklich zwingend notwendig. Da es sich um eine relativ kleine Skizze handelt, bin ich über die Verwendung von variablem Speicher nicht allzu besorgt.

Bei diesen Berechnungen wird davon ausgegangen, dass die Schleife selbst im Vergleich zu der Methode eine zu vernachlässigende Zeit benötigt pulseDelay Zeit, die, sobald ich die Schaltfläche Polling herausgenommen habe, scheint wahr zu sein.

// einmal pro Gesamtlauf if (travelDir == 0) digitalWrite (dir, LOW); else if (travelDir == 1) digitalWrite (dir, HIGH); //Serial.begin(9600); //Serial.println(pulseDelay); // Schrittschleife do digitalWrite (stp, HIGH); // feuert die Verzögerung des Motorantriebs (pulseDelay); digitalWrite (stp, LOW); // Treiber zurücksetzen // btnVal = readLcdButtons (); // prüfen, dass es keine Unterbrechung gibt - dies dauert zu lange und verlangsamt den Motor erheblich; Reset für Stop verwenden! currentStep ++; // am Ende jedes Schritts if (currentStep% IntervallDistanz == 0) // Wenn die aktuelle Anzahl der Motorschritte durch die Anzahl der Motorschritte in einem Kameraschritt teilbar ist, feuere die Kamera digitalWrite (trig, HIGH); // Kamera-Verschlussverzögerung auslösen (80); DigitalWrite (Trig, LOW); // Reset der Trigger-Pin-Verzögerung ((shutterDuration * 1000) -80); // delay muss auf Timer umgestellt werden, so dass die Stopp-Taste abgefragt werden kann, während (currentStep < totalMotorSteps);  //end motion control

Schließlich beachten Sie die currentSteps Wert eingestellt auf 1. Ich habe keine Fehlerprüfungsfunktion dafür erstellt, aber der gesunde Menschenverstand sagt Schrittlänge unendlich wird, wenn currentStepsInt == 0, Wenn Sie also eine kontinuierliche Bewegung wünschen, ist es am besten, es auf einem Wert zu halten. Ich habe bereits einen Verbesserungseintrag dazu hinzugefügt.

Ausführen des Endprodukts

Für etwas, das auf Code läuft, der in zwei Tagen mehr oder weniger von Grund auf neu geschrieben und über zwei weitere Fehler behoben wurde, funktioniert es wie ein Traum! Der Beweis liegt jedoch im Pudding. Bekommt es wirklich lohnendes Zeitraffer-Footage und funktioniert die Steuereinheit wirklich gut im Feld??

In meinen Tests scheint die Antwort ein volles Ja zu sein. Nachfolgend finden Sie einen Zeitraffer von zwei Stunden und 650 Bildern, der allererste Test. Der Slider absolvierte auch einen 9-Stunden-720-Frame-Test einwandfrei, aber nach zwei Stunden lief der Kamera-Akku leider nicht so gut… was ich natürlich erst nach 8,5 Stunden herausfand.

Wenn ich die Zeit und die Schritte richtig eingestellt habe, kann die Bewegung für langsame Dollybewegungen in Live-Action-Videos kontinuierlich sein, obwohl das Ruckeln aufhören muss, oder Geschwindigkeitsrampen zu machen. 

Der Ton kann ein Problem sein, es sei denn, Ihr Stepper ist sehr leise, aber um Eigenproduktionen den Produktionswert hinzuzufügen, ist dies eine Option.

Verbesserungen

Wie bei allem können auch Verbesserungen vorgenommen werden. Ich habe sie oben in der Liste aufgelistet .ino Akten, allerdings ohne besondere Sorgfalt in Bezug auf die Durchführbarkeit oder nach irgendeiner Art von Bedeutung. 

Einige davon habe ich vor der Veröffentlichung dieses Tutorials mit v0.2 in Betracht gezogen, aber ich habe das Gefühl, dass sie an sich schon eine Lernerfahrung sind, die in Bezug auf die geistige Demontage der Verwendbarkeit eines Programms betrachtet wird.

 VERBESSERUNGEN UND ÜBERLEGUNGEN ZU V1.0: 1) Effizienz des Antwortcodes der Untermenütasten für die ersten drei Menüüberschriften 2) Verwendung der Lampenverschlußzeit als zusätzliche Menüoption, die an den Auslöser übergeben wird. 3) Die Verschlusszeit sollte eine Pause sein, keine Verzögerung ( ) - Stopptaste kann nicht abgefragt werden! 4) Verwenden Sie die EEPROM-Bibliotheksfunktionen, um die Mengen zu speichern. Dadurch kann der Bewegungssteuerungsabschnitt vereinfacht und Reset als "Stopp" verwendet werden. 5) Entfernen Sie den Schalter aus dem Untermenü "Go", und ersetzen Sie ihn mit einer angemesseneren Logik anstatt Gesamtreise? "Dauer" mehr als 15 Sekunden oder 2 Minuten als 30 Minuten oder 4 Stunden? 7) Irgendwelche Konstanten, die besser als #define oder besser als boolean wären? Kaum gegen die Grenzen des SRAM-Speichers bei 8kB. 8) Tweening / Beschleunigung für Beschleunigungskurven, insbesondere für Videoanwendungen. 9) Fehlerprüfung für die Nullschrittgröße oder einfach eins zu Intervalldistanz hinzufügen, wenn der Wert vor den Berechnungen Null ist. Anderes Ende von Distance ist noch 1 Schritt 10) Würde eine Verzögerung von unter 16 ms verursachen () s besser als delayMicroseconds ()? Wie sehr lösen Interrupts das Timing aus? 11) Schlafmodus auf A4988 verwenden, um den Stromverbrauch im Feld zu reduzieren? 12) Fehlerprüfung für currentDurationInt <= currentStepsInt*shutterDuration, allowing no time for movement or even negative pulseDelay! */

Dies sind nur die Verbesserungen, an die ich bisher gedacht habe, um die Codebase von einer rudimentären, aber funktionalen Version 0.2 zu einer optimierten und leistungsfähigeren Version 1.0 zu führen. Sie können mehr bemerken. Fühlen Sie sich frei, sie in den Kommentaren unten oder auf GitHub zu hinterlassen.

Einpacken

Wenn Sie von Anfang bis Ende gefolgt sind, einschließlich des Abschnitts Photography Tuts + des Builds, sind Sie jetzt stolzer Besitzer eines hochwertigen motorisie