Управління рухом з Arduino: Автолюбитель камери слайдер
() translation by (you can also view the original English article)
Наявність дешевих крокові двигуни і драйвери в ці дні дає широкі можливості для експериментів за межами більш дорогі і складні 2D і 3D різання і друку проектів.
Для цього проекту, я візьму OpenBuilds повзунок камери (див. відео побудувати будинок в основну відео слайдер з відкритим вихідним кодом частини CNC) і motorise його. Я також буду створювати автономні системи управління двигуном.
Цей підручник охоплює воєдино обладнання, але в першу чергу побудуємо найпростіший 16x2 РК-інтерфейс з використанням бібліотеки LiquidCrystal і просте меню системи для того, щоб відобразити, а потім роботу водія a4988 крокового і як ним керувати з Arduino.
Цей проект важко на петлі і кроки, і хоча в цілому проект більше середнього, я намагався пояснити це таким чином, що новачки можуть бути запущений і працює досить швидко.
Цей проект важко на петлі і кроки, і хоча в цілому проект більше середнього, я намагався пояснити це таким чином, що новачки можуть бути запущений і працює досить швидко.Список Обладнання
Компоненти
- Ардуїнов Уно
- РК-Клавіатура щит або окремий РК-дисплей 16х2 і кнопки, якщо ви знаєте, як зробити цю роботу
- Водій З A4988 Pololu На [Чорний Видання] Степпер
- Невеликі алюмінієві самоклеючі тепловідвід
- Технологічні комплекти, чоловічий і жіночий джемпер дроти і т. д.
- 220-330 ом резистор (1/4ВТ, ймовірно, робити), стандартний NPN транзистор (я використовував BC109)
- 3.5 мм стерео ТРС роз'єм
- 3,5 мм до 2,5 мм стерео кабель ТРС адаптер
- Розширення 3,5 мм кабель, скільки необхідно для довжини слайдера
- 9В стовбура роз'єм живлення, якщо ви хочете взяти Ардуїнов від USB живлення комп'ютера
- 12В 2А джерела живлення для запуску крокового двигуна
- Stepper мотора nema 17
Частини
- ГТ2 5 мм шириною, 2 мм-крок зубчастого ременя: подвійний слайдер довжина плюс ноги для безпеки (11 футів для мене)
- Гладкий натяжний шків комплект
- Ремінь-натяг пружини кручення, якщо у вас є труднощі в підтримці натягу ременя більш довгостроковій перспективі
- 2х пояс обжимний хомут (можна замінити невеликою zipties)
- ГТ2 7 мм завширшки, 20-зуб алюміній шків однаковий Розмір свердловини вал мотора
- 4х 30мм м3-0.5 шапка-головний машині гвинти
Інструменти
- Комп'ютер середовищі розробки Arduino (я використовую Win7, в Ардуїнов 1.0.5 R2)
- Паяльник з невеликим зубилом наконечник, припій, і т. д
- Ключ шестигранний 2.5 мм для гвинти М5
- Ключові 2мм шестигранний для гвинтів M3
- Ключ шестигранний 1.5 мм для установки гвинтів в класі GT2 шків
- мультиметр для пошуку несправностей і регулювання струму
- Вузькі плоскогубці для стяжки в невеликих приміщеннях
Огляд Функціональних Можливостей
Я прикрию додавши мотора і шківів з повзунком, натягивающий ремінь і кріплення. Це проста модифікація.
Потім я розповім, як зібрати з a4988 pololu на чорний видання комплект і як прикрутити її на макетної платі разом з усіма іншими зовнішніми плит, а також простий фанери корпусу я збиваються в кілька хвилин для мого живлення 12В (перерахованих вище) для того, щоб запобігти удари, так як клеми піддаються.



Меню дозволяє введення дальності поїздки, поїздки, кількість кроків і напрямок руху. В кінці кожного кроку, повзунок паузи, коли камера спрацьовує.
Зміна повзунка
Крок 1: Збірка Двигуна
У OpenBuilds V-подібний ПАЗ, Привід кінець держателя має нема 17 Розмір отворів в ньому, так що чотири 30мм м3 головкою гвинти все, що потрібно підключити мотор до неї.



Забезпечити 20-зуб класі GT2 шків всередині гори перед вами слот з валом двигуна, а кріплення не достатньо широким, щоб додати його на потім. Як тільки двигун прикручена внизу, підтягти гвинти настановні з одним з них проти плоскої частини валу двигуна, гарантуючи, що зуби прямо в лінію з центром всього екструзії блок.
Крок 2: Натяжний Шків Комплект
Натяжний ролик комплект йде разом як комплект коліс і шліців на протилежному кінці приводу Кріплення:



Крок 3: Бельтинг Вгору
Годувати ремінь через центр V-подібний ПАЗ, у відповідності зі шківами, забезпечуючи зуби вгору.
Потім годувати його і двох шківів і повернути його в середину до Доллі побудувати плиту.



Тут ви обернути одного боку через щілину і затиск ременя, або стяжку, потім використовувати його, щоб затягнути всім пояси через всю систему, перш ніж підключити іншій стороні. Не надто туго для включити мотор, але не досить вільно, щоб пропустити зубів на приводний шків!
Збірка електроніки
Крок 1: зібрати драйвер крокового
В с a4988 pololu на чорний видання драйвер крокового двигуна (технічно з a4988 перевізник правління - a4988 є сам чіп), як правило, поставляється у вигляді комплекту, який просто означає, що заголовки повинні бути припаяні. Оскільки цей компонент харчування, навіть якщо це не схема блоку на максимальній потужності, це гарна ідея, щоб додати радіатор, щоб допомогти підвищити свою тривалість життя.
Розбити рядок заголовка в півтора-два ряди з восьми. Слот у металізованих отворів в платі, і тоді цей уважно на макет. Припаяти штирі на місці, поки макет тримає все красиво і перпендикулярно.



Після цього відрізати кутку невеликий самоклеючі радіатор, використовуючи ножівку і випилюємо (обережно, хомут!) для кріплення до з a4988 СК.



Крок 2: макет монтажу компонентів
Тепер все має бути встановлено в макетах, так що він може бути підключений разом у функціонуванні cicuit. Я використовую окремі списки для кожної частини для повної ясності в образах, але не соромтеся, щоб умістити його в один рада, якщо ви хочете.
РК-клавіатура щит не може бути встановлений на борту, завдяки дивним Ардуїнов вибір дотримуватися конструктивний недолік, а не відповідати стандартам. Це буде тримати окремо, хоча навинтив його на шматок дерева або що-то для захисту контактів не може бути поганою ідеєю.



Тригер камери ланцюги в її найбільш простій складається з резистора, транзистори та 2,5 мм ТРС суб-міні-штекер. Я додав світлодіод, який буде блимати, коли на курок штифт шипи висока, і 3,5 мм типу TRS міні-джек для того, щоб забезпечити гнучкість.
Якщо ви купуєте компоненти для цієї збірки, 3,5 мм роз'єм, призначений для 0.1 дошки тангажа б непогано, але у мене від продувають купу, так що замість нього я припаяв роз'єм до нього.
Витягни все, готовий до проводу все.
Крок 3: Проводка Всі Разом
Час, щоб захопити всі сполучні кабелі. Маючи достатньо тримати речі з колірним кодуванням полегшує життя при пошуку та усунення несправностей. Зверніться до схемі вгорі, якщо наступне опис бентежить вас у будь-який момент.



Перший провід до РК. Візьміть 10 жіночі джемпери та підключити їх до наступних щит контактів: контакти 4-9, шини живлення штирі Reset (якщо ви хочете використовувати кнопку скидання РКІ), 5В і один з GNDs.
Якщо у вас є жінка-чоловік джемпери, ви можете залишити його там. В іншому випадку, підключіть чоловічий джемпер—на інший кінець самки—для того, щоб підключити їх до відповідного Ардуїнов гніздо розетки. Якщо у вас є РК-клавіатура щит, який має наскрізну розеткові встановлений зверху, ви можете пропустити цей крок, так як ваш щит не блокує.
Потім дошку з a4988 pololu. Це має вісім стрибунів з одного боку, я використовувала чорний і червоний за логікою/Потужність двигуна easch кінця, і червоний/зелений/синій/жовтий у центрі чотирьох до матчу з ШД-х сервоприводів.
Логіка-контактний роз'єм живлення йде до 3.3 V на Arduino, як РК вище, використовуючи висновок 5V. Потужність двигуна дроти йдуть на своє джерело живлення 12В. На іншій стороні, біля чіпа з a4988, я використовую синій і помаранчевий НТП і дір відповідно на відміну від відносно однорідного кольору скрізь. Вони йдуть до Arduino штирі 11 і 12 відповідно, якщо ви змінити код. Потім короткі RST і СЛП разом, щоб тримати рада включений; я використовував свинцеві білила тут.



Нарешті, проводи запуску камери вимикача. Тут чорного дроту масу - поспіль дроти до Arduino, з рядка проводу на гніздо 3.5 мм Жовтий колір вільно переходить до Arduino висновку 13 (значить, є світлодіодний індикатор на платі, а також на вимикачі!), і червоний провід йде до іншої сторони гніздо 3.5 мм (або 2.5 мм штекера, якщо ви збираєтеся цей маршрут).
Підключити кроковий двигун в кольорових дротів згідно з a4988 схема плати і даташит кроковий по вашому. Для мене це було так:



Увага: пам'ятайте, що дроти подачі живлення на двигун, ймовірно, буде витягувати 1-2А в обраному напруга, тому переконайтеся, що використовуються дроти розраховані на це. Чіп a4988 і дошки навколо нього можуть нагріватися! Чіп a4988 і дошки навколо нього можуть нагріватися! Потенціометр, вбудований в борт забезпечує обмеження струму для захисту a4988 і мотор, тому переконайтеся, що ви встановите його належним чином перед використанням за допомогою мультиметра.
Налаштування Програми
Як тільки компоненти були зібрані, можна перейти до кодування. Завантажити zip в комплекті з цим підручником, або перевірити цей репозиторій github, розташований, якщо ви віддаєте перевагу. Я розповім, як я поклав його разом, так що ви можете зрозуміти Загальний потік програми і модулі працюють разом.
Крок 1: включає в себе основні визначення
Тільки включати необхідні для цього був РК письмовій бібліотека LiquidCrystal.ч. Це дає доступ до РК.ХХХХ() функції. Там через pow() в програмі, і я виявив, що в тому числі бібліотеки C++ математики.ч не треба, як деякі з його найбільш корисних функцій, включених в Arduino фондової середовищі, в тому числі через pow().
1 |
#include <LiquidCrystal.h> |
2 |
|
3 |
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //set LCD output pins |
4 |
|
5 |
//define stepper driver pins
|
6 |
const int stp = 11; //can't use pin 10 with the SS LCD as it's the backlight control. |
7 |
//if it goes low, backlight turns off!
|
8 |
const int dir = 12; |
9 |
|
10 |
//define trigger pin
|
11 |
const int trig = 13; |
12 |
|
13 |
//BUTTONS
|
14 |
//define button values
|
15 |
const int btnUp = 0; |
16 |
const int btnDn = 1; |
17 |
const int btnL = 2; |
18 |
const int btnR = 3; |
19 |
const int btnSel = 4; |
20 |
const int btnNone = 5; |
21 |
|
22 |
//define button-reading variables
|
23 |
int btnVal = 5; |
24 |
int adcIn = 0; |
Я поставив РК-виводу, драйвер крокового виводу і камери тригера виводу. Після того, як фактична апаратний інтерфейс налаштований, я додав змінні для подій натискання кнопок потім кнопку-значення функції, яку я адаптував від DFRobot Вікі на їх ідентичні РК клавіатура щит. Зверніть увагу, що SainSmart надає жодних документів.
Крок 2: Настройка() Цикл
Це супер скачайте стоковий фотографію Bahia. Ініціалізувати LCD та відповідних вихідних контактів, потім основний екран привітання, потім падіння на головному екрані меню 1 з обнулені значення.
1 |
void setup() { |
2 |
lcd.begin(16, 2); // initialise LCD lib full-screen |
3 |
lcd.setCursor(0,0); // set cursor position |
4 |
|
5 |
pinMode(stp, OUTPUT); //initialise stepper pins |
6 |
pinMode(dir, OUTPUT); |
7 |
|
8 |
pinMode(trig, OUTPUT); //initialise trigger pin |
9 |
digitalWrite(trig, LOW); //ensure trigger is turned off |
10 |
|
11 |
lcd.print("Welcome to"); //welcome screen |
12 |
lcd.setCursor(0,1); |
13 |
lcd.print("SliderCam v0.2!"); |
14 |
delay(1000); |
15 |
lcd.clear(); |
16 |
lcd.print(menuItemsTop[0]); |
17 |
delay(100); |
18 |
lcd.setCursor(0,1); |
19 |
for (int i = 0; i < 4; i++) { |
20 |
lcd.setCursor(i, 1); |
21 |
lcd.print(currentDistance[i]); |
22 |
}
|
23 |
lcd.setCursor(4,1); |
24 |
lcd.print("mm(max 1300)"); |
25 |
}
|
Крок 3: Кнопки Монітора
Перевага кодування тут-мудрий, що обладнання не потрібно нічого робити взагалі без участі користувача. Це означає, що найперше, що може бути вічним кнопку цикл опитування. Не називаючи readLcdButtons() функція знову і знову, поки її значення не змінюється негативно позначитися на продуктивності програми, і вам не потрібно турбуватися про вихід переривання контактів доступний.
1 |
void loop() { |
2 |
do { |
3 |
btnVal = readLcdButtons(); //continually read the buttons... |
4 |
}
|
5 |
while (btnVal==5); //...until something is pressed |
1 |
//declare button poll function
|
2 |
int readLcdButtons() { |
3 |
delay(90); //debounce delay, tuned experimentally. delay is fine as program shouldn't be doing anything else |
4 |
//at this point anyway
|
5 |
adcIn = analogRead(0); //read value from pin A0 |
6 |
|
7 |
/*threshold values confirmed by experimentation with button calibration sketch returning the following ADC read values:
|
8 |
right: 0
|
9 |
up: 143
|
10 |
down: 328
|
11 |
left: 504
|
12 |
select: 741
|
13 |
*/
|
14 |
|
15 |
if (adcIn > 1000) return btnNone; |
16 |
if (adcIn < 50) return btnR; |
17 |
if (adcIn < 250) return btnUp; |
18 |
if (adcIn < 450) return btnDn; |
19 |
if (adcIn < 650) return btnL; |
20 |
if (adcIn < 850) return btnSel; |
21 |
|
22 |
return btnNone; //if it can't detect anything, return no button pressed |
23 |
}
|
ReadLcdButtons()
має затримку 90мс для того, щоб брязкоту кнопок. Насправді, це не брязкоту, так як це не перездати вимірювання АЦП після певної кількості часу, а скоріше поголовно кнопки досить рідко рідко реєструвати більш ніж один клік.
Він досягає те ж саме, з практичної точки зору УБ. Це скоріше опитування кнопок кожен 90мс, а не постійно, тому використання затримки() це взагалі не вважається хорошою практикою для цілей debouncing, але він вирішив проблему (були доступні тільки в кожному кінці меню).
Крок 4: Оновіть Екран
Після того, як пристрій може реагувати на введення, там повинен бути спосіб для відображення цих реакцій.
Після того, як пристрій може реагувати на введення, там повинен бути спосіб для відображення цих реакцій. Робимо це так само просто, як очищення екрана, а потім відновлення на основі відомих поточних параметрів.
Це звучить складно, але на практиці робить життя набагато легше. Він видаляє велика кількість РК-команди з інших країн в програмі, і створює змінну-Тип-агностик зони, яка мінімально впливає на оновлення програми зовнішні по відношенню до неї.
Фактичний освіжаючий частини еволюціонували, щоб включати в себе чотири окремих етапи:
Скидання параметрів...
1 |
//PRINT NEW SCREEN VALUES
|
2 |
btnVal=btnNone; |
3 |
lcd.clear(); |
...друку у верхньому рядку...
1 |
lcd.setCursor(0, 0); |
2 |
lcd.print(menuItemsTop[currentMenuItem]); //print top level menu item |
...друку в нижньому рядку, які я поясню трохи пізніше...
1 |
lcd.setCursor(0,1); |
2 |
switch (currentMenuItem) { |
3 |
case 0: |
4 |
{
|
5 |
for (int i = 0; i < 4; i++) { |
6 |
lcd.setCursor(i, 1); |
7 |
lcd.print(currentDistance[i]); |
8 |
}
|
9 |
break; |
10 |
}
|
11 |
|
12 |
case 1: |
13 |
{
|
14 |
for (int i = 0; i < 6; i++) { |
15 |
lcd.setCursor(i, 1); |
16 |
lcd.print(currentDuration[i]); |
17 |
}
|
18 |
break; |
19 |
}
|
20 |
|
21 |
case 2: |
22 |
{
|
23 |
for (int i = 0; i < 4; i++) { |
24 |
lcd.setCursor(i, 1); |
25 |
lcd.print(currentSteps[i]); |
26 |
}
|
27 |
break; |
28 |
}
|
29 |
|
30 |
case 3: |
31 |
{
|
32 |
if (travelDir == 0) lcd.print("From Motor"); |
33 |
else lcd.print("To Motor"); |
34 |
break; |
35 |
}
|
36 |
|
37 |
case 4: |
38 |
{
|
39 |
lcd.print("Stop!"); |
40 |
break; |
41 |
}
|
42 |
} //end switch |
...і додати екран спеціальні команди поверх того, що вже надруковано.
1 |
if (currentMenuItem==0){ |
2 |
lcd.setCursor(4,1); |
3 |
lcd.print("mm(max 1300)"); //insert max carriage travel on slider used |
4 |
} |
5 |
if (currentMenuItem==1){ |
6 |
lcd.setCursor(6,1); |
7 |
lcd.print("s(3600/hr)"); |
8 |
} |
9 |
if (currentMenuLevel == 1) { |
10 |
lcd.setCursor(currentCursorPos, 1); |
11 |
lcd.blink(); |
12 |
} |
13 |
else lcd.noBlink(); |
Створення Меню: Головні Рубрики
Природно, що точної розділі оновлення екрану не пише сам, і ми повинні знати меню він пише на екрані, перш ніж він може бути завершений. Основні рубрики легко, так як вони фактично не змінюються в залежності від введення користувача. Це означає, що можна просто бути рядка масиву - технічно масив покажчиків на тип char, або масив масивів:
1 |
//MENU GUI
|
2 |
//define top-level menu item strings for numerical navigation
|
3 |
char* menuItemsTop[] = { |
4 |
" 01 Distance >", "< 02 Duration >", "< 03 Steps > ", "< 04 Direction >", "< 05 Go!"}; |
5 |
|
6 |
int currentMenuLevel = 0; //top menu or submenu |
7 |
int currentMenuItem = 0; //x-axis position of menu selection |
8 |
int currentCursorPos = 0; //current lcd cursor position |
9 |
int currentDistance[4] = { |
10 |
0, 0, 0, 0}; |
11 |
int currentDuration[6] = { |
12 |
0, 0, 0, 0, 0, 0}; |
13 |
int currentSteps[4] = { |
14 |
0, 0, 0, 1}; |
Це означає, що можна просто бути рядка масиву - технічно масив покажчиків на тип char, або масив масивів: Це означає, що цей масив menuItemsTop можна переміщатися шляхом простої зміни числа в квадратних дужках під час оновлення екрану. І так трапляється, оскільки всі нуль-індексований, щоб відстежувати тотожне з цілим currentMenuItem.
Маніпулюючи currentMenuItem
на кнопку заходах дозволяє нам одновимірних навігації, тому, коли ви бачите menuItemsTop[currentMenuItem
] очевидно, що даний розділ рубрики.
1 |
if (currentMenuLevel==0) { |
2 |
switch (btnVal){ |
3 |
case btnL: |
4 |
{
|
5 |
if (currentMenuItem == 0) break; //can't go left from here |
6 |
else currentMenuItem--; |
7 |
break; |
8 |
}
|
9 |
|
10 |
case btnR: |
11 |
{
|
12 |
if (currentMenuItem == 4) break; //can't go right from here |
13 |
else currentMenuItem++; |
14 |
break; |
15 |
}
|
16 |
|
17 |
case btnSel: |
18 |
{
|
19 |
currentMenuLevel++; |
20 |
if (currentCursorPos > 3 && (currentMenuItem == 0 || currentMenuItem == 2)) currentCursorPos = 3; //don't go off the end of the numbers for the 4-digit numbers |
21 |
if (currentCursorPos > 0 && (currentMenuItem > 2)) currentCursorPos = 0; // set blinking cursor to left for text-based options |
22 |
if (currentMenuItem == 4) { |
23 |
motion = 1; |
24 |
motionControl(); |
25 |
break; |
26 |
}
|
27 |
}
|
28 |
} //end of switch |
29 |
} //end of level 0 |
Так що ви можете рухатися вліво і вправо, і перейти в меню, або у разі йти! потім активоване контролю руху. Що це все, що потрібно тут.
Створення Меню: Підменю
Система підменю довелося попотіти, завдяки своїй внутрішній складності. Перші три записи, відстань, Тривалість і дії, технічно складаються з суб-суб-меню, кожен, дозволяє навігації, мульти-символьне значення, а також кожного окремо взятого персонажа.
Це покривається, що робить кожна запис підменю відключається рубриці системи в своєму власному праві. Хоча це був довгий шлях навколо, це простий і послідовний спосіб такого низького рівня навігації. Так як я дуже просто прорахував відстань підменю, а потім скопіювати її на інші підменю, ось подивися на цього.
1 |
else { // i.e. "else if currentMenuLevel = 1" |
2 |
if (currentMenuItem == 0) { //01 DISTANCE |
3 |
|
4 |
switch (btnVal) { |
5 |
case btnUp: |
6 |
{
|
7 |
currentChar = currentDistance[currentCursorPos]; |
8 |
adjustDigit(currentChar, 1); |
9 |
currentDistance[currentCursorPos] = currentChar; |
10 |
break; |
11 |
}
|
12 |
|
13 |
case btnDn: |
14 |
{
|
15 |
currentChar = currentDistance[currentCursorPos]; |
16 |
adjustDigit(currentChar, 0); |
17 |
currentDistance[currentCursorPos] = currentChar; |
18 |
break; |
19 |
}
|
20 |
|
21 |
case btnL: |
22 |
{
|
23 |
if (currentCursorPos == 0) break; //can't go left from here |
24 |
else currentCursorPos--; |
25 |
break; |
26 |
}
|
27 |
|
28 |
case btnR: |
29 |
{
|
30 |
if (currentCursorPos == 3) break; //can't go left from here |
31 |
else currentCursorPos++; |
32 |
break; |
33 |
}
|
34 |
|
35 |
case btnSel: |
36 |
{
|
37 |
parseArrayDistance(); |
38 |
currentMenuLevel--; |
39 |
}
|
40 |
} //end switch |
41 |
} //end DISTANCE |
Зліва і праворуч є по суті такими ж, як в меню верхнього рівня, просто рухаючись вперед і назад вздовж ряду в ту ж сторону, що число насправді буде набір цифр int масив та поточне місце розташування зберігається в int називається currentCursorPos що дозволяє блимати, як показано на екрані оновити модуль вище.
Друкуючи ці масиви вздовж нижньої частини РК-поспіль, що для петлі були для в розділі оновлення екрану; I від 0 до 3, РК-колони від 0 до 3, currentDistance[] від 0 до 3.
1 |
int adjustDigit(int x, int dir){ //digit adjust function |
2 |
if (dir == 0 && x > 0) x--; //subtract from digit on btnDn |
3 |
if (dir == 1 && x < 9) x++; // add to digit on btnUp |
4 |
lcd.setCursor(currentCursorPos, 1); |
5 |
lcd.print(x); |
6 |
currentChar = x; |
7 |
return currentChar; //return new digit |
8 |
}
|
Збільшення і зменшення числа досягається за рахунок зберігання поточного
цифру змінної currentChar, який потім передається в adjustDigit (функції
) поряд з логічне значення, яке вказує напрямок; щоб збільшити або зменшити двигуна.
Це просто налаштовує цифра за логічним значенням і зберігає результат, коли потік повертається в основний цикл, де currentChar значення зберігається назад в правильне положення оригінальний currentDistance[] масив і нова скоригована цифра друкується на екрані оновлення.
Парсинг Відображення Значень Масиву
Коли виберіть виберіть з одного числа масиву підменю, воно викликає відповідну функцію парсинга - в цьому випадку parseArrayDistance(). Вам треба розібрати блок, використовується для зручного відображення та редагування в ціле число корисних для реальних обчислень руху. Я вирішив зробити це зараз, а не на ходу! щоб зберегти УБ почуття жваво.
1 |
int adjustDigit(int x, int dir){ //digit adjust function |
2 |
if (dir == 0 && x > 0) x--; //subtract from digit on btnDn |
3 |
if (dir == 1 && x < 9) x++; // add to digit on btnUp |
4 |
lcd.setCursor(currentCursorPos, 1); |
5 |
lcd.print(x); |
6 |
currentChar = x; |
7 |
return currentChar; //return new digit |
8 |
}
|
Я придумав цю функцію з однієї корисної передає коментар я знайшов після вичерпання Гуглі шукаю стандартний набір-для-інт функції, порожню, і позбутися від безладу масиву в чарі-на-інт функції, які були неефективний спосіб. Здається, досить короткі і легкі, враховуючи, що це буквально на основі десяткової математики, але якщо ви знаєте кращий спосіб, я всі вуха.
Контроль руху та запуску камери
Всі значення встановлюються і натисніть Go! Що відбувається далі? Вам потрібно розрахувати, які саме цифри даний йому повинні зробити для того, щоб виконати завершальний рух. Ця частина є функціональною, але робота в прогресі, я вважаю, що там повинні бути більше варіантів різних видах руху.
1 |
int motionControl() { |
2 |
totalMotorSteps = currentDistanceInt * 5; //calculate total steps (0.2mm = 20-tooth gear on 2mm pitch belt; 40mm per rev, 200 steps per rev, ergo 1/5th mm per step) |
3 |
pulseDelay = (1000L * (currentDurationInt - (currentStepsInt * shutterDuration))) / totalMotorSteps; //how long to pause in ms between STP pulses to the motor driver |
4 |
intervalDistance = totalMotorSteps / currentStepsInt; |
Що відбувається у цій функції є достатньо зрозуміло з коментарів, я думаю. Я shutterDuration 2 секунди в програмному забезпеченні, в основному, продовжуєш відчувати досить швидке. Якщо ви знімаєте вночі, на низьких ISO, то це, можливо, буде потрібно більше схоже на 25-35 секунд в залежності від вашої точної витримки.
У pulseDelay множиться на 1000 В кінці, щоб перетворення секунд в мілісекунди, звичайно. L для перетворення постійного інт на Лонг більше мені помилятися в бік обережності, ніж строго необхідно. Оскільки це порівняно невелика замальовка, я не дуже турбувався про використання змінної пам'яті.
Ці розрахунки припускають, що сама петля вимагає незначної кількості часу в порівнянні з часом pulseDelay, який, як тільки я вийняв кнопка голосування з'являється, щоб бути правдою.
1 |
//once per overall run
|
2 |
if (travelDir == 0) digitalWrite(dir, LOW); |
3 |
else if (travelDir == 1) digitalWrite(dir, HIGH); |
4 |
//Serial.begin(9600);
|
5 |
//Serial.println(pulseDelay);
|
6 |
|
7 |
//step loop
|
8 |
do { |
9 |
digitalWrite(stp, HIGH); //fire motor driver step |
10 |
delay(pulseDelay); |
11 |
digitalWrite(stp, LOW); //reset driver |
12 |
//btnVal = readLcdButtons(); //check there's no stoppage - this takes too long and significantly slows motor; use reset for stop!
|
13 |
currentStep++; |
14 |
|
15 |
//at end of each step
|
16 |
if (currentStep % intervalDistance == 0) { //if current number of motor steps is divisible by the number of motor steps in a camera step, fire the camera |
17 |
digitalWrite(trig, HIGH); //trigger camera shutter |
18 |
delay(80); |
19 |
digitalWrite(trig, LOW); //reset trigger pin |
20 |
delay((shutterDuration * 1000)-80); //delay needs changing to timer so stop button can be polled |
21 |
}
|
22 |
|
23 |
}
|
24 |
while (currentStep < totalMotorSteps); |
25 |
|
26 |
} //end motion control |
Нарешті, зверніть увагу на значення currentSteps на 1. Нарешті, зверніть увагу на значення currentSteps на 1. Я не створений помилка-перевіряти функцію для цього, але простий
здоровий глузд говорить, кроку стане нескінченним, якщо currentStepsInt == 0, тому краще тримати його в одному безперервному русі,
якщо це необхідно. Я додав запис поліпшення для цього вже.
Запуск кінцевого продукту
Те, що працює на код, написаний більш або менш з нуля за два дні і виправлена більше двох, він працює як сон! Доказ знаходиться в пудинг. Це насправді вам варто інтервальна запис, і блок управління дійсно добре працювати в полі?
У моїх тестах, відповідь представляється гучне "так". Нижче знаходиться дві години, 650-рамки інтервальної зйомки, самий перший тест. Повзунок також пройшов 9-годинний тест 720 кадр бездоганно, але на жаль акумулятор камери не так добре після 2 годин ..., якого я не дізнався, до 8.5 годин, природно.
Якщо я встановив належним чином про час і кроків, рух може бути безперервним протягом Доллі повільно рухається у відео дій, хоча уривчасто закінчується необхідність редагування, або швидкість-нарощує.
Звук може бути проблемою, якщо ваш степпер дуже тихо, але для додавання вартості до самостійної запису, це варіант.
Поліпшення
Як і всі, можливі поліпшення. Я перерахував вгорі .файл Іно, правда без особливого догляду за доцільності, ні замовити будь-який вид важливість.
Деякі з них я вважав фіксації до виходу цього підручника з V0.2, але мені здається, що вони самі по собі є досвідом подивитися з точки зору морально демонтаж юзабіліті програми.
1 |
IMPROVEMENTS AND CONSIDERATIONS TOWARDS V1.0: |
2 |
1) Efficiency of submenu button response code for first three menu headers |
3 |
2) Use of bulb shutter time as an extra menu option, passed to shutterDuration int |
4 |
3) shutter duration should be timed pause, not delay() - can't poll stop button! |
5 |
4) Use EEPROM library functions to save quantities, can thus simplify the motion control section and use Reset as "stop" |
6 |
5) Remove switch from "Go" submenu, replace with more appropriate logic statement |
7 |
6) Would it be better to time camera steps rather than total travel? "duration" being more like 15 sec or 2 min than 30 min or 4hrs? |
8 |
7) Any const ints that would be better as #define or ints better as boolean? Hardly running against the limits of SRAM space at 8kB, though. |
9 |
8) Tweening/easing for acceleration curves, particularly for video use |
10 |
9) Error check for zero step size, or simply add one to intervalDistance if value is zero before calculations- other end of Distance is still 1 step |
11 |
10) Would sub-16ms delay()s be better as delayMicroseconds()? How much do interrupts throw off timing? |
12 |
11) Use of sleep on A4988 to reduce power consumption in the field? |
13 |
12) Error check for currentDurationInt <= currentStepsInt*shutterDuration, allowing no time for movement or even negative pulseDelay! |
14 |
*/
|
Це просто поліпшень, які я гадав досі, в прагненні керівництва до codebase з рудиментарною, але функціональна версія V0.2 в бік більш оптимізовані і більш здатним відпустити v1.0. Ви можете більше уваги. Не соромтеся залишати їх у коментарях нижче або на github.
Завертаючи
Якщо Ви виконали від початку до кінця, включаючи фотографії Туц+ частина побудувати, тепер ти гордий власник високої якості моторизований слайдер камера, яка може виробляти таймлапс зйомки і тонкі Доллі рухається. Якщо ви використовуєте код для якийсь інший проект, я б хотів побачити його.
У цьому уроці, я подивився на різні форми циклу на основі управління потоком, створюючи зачатки GUI і оновлення РК на основі введення користувача. Я теж подивився на одночасне управління кількома зовнішніми механічними пристроями через дошки проламати.
Ви бачили потік і легкість програмування модульний код, а також побачити ідеї як покращити код, який працює, але не оптимізований, як з UX і процесор з точки зору ефективності. Ці кошти повинні служити вам добре для різноманітності спілкування і взаємодії на основі проектів в майбутньому.
Будь ласка, залиште які-небудь питання або зауваження в коментарях нижче!