Здравствуйте!
Представляю два варианта самодельного электро привода для автоматической фокусировки на базе Arduino UNO и Digispark
Первый вариант привода, собран на базе одной платы Arduino UNO, он более простой, но имеет меньшую скорость настройки фокуса.
В данном проекте используется:
плата Arduino Uno
Датчик расстояния VL53L0X
Драйвер шагового двигателя DRW8825
Сопротивления с номиналом в пределах от 500 до 1000 ом
Макетная плата
Соединительные провода
И источники питания
Один источник питания для платы Arduino UNO, он не должен быть импульсным, и напряжение должно быть в пределах от 3.7 до 5 вольт, а второй источник питания для драйвера шагового двигателя, подойдет блок питания на пару ампер с напряжением от 9 до 35 вольт.
Прежде чем все собирать, необходимо загрузить скетч на плату Arduino UNO. О том как настроить скорость вращения шагового двигателя, подробно рассказывается в видео, которое найдете в конце этой статьи. Кроме настройки скорости вращения, можно еще изменять микро шаг шагового двигателя, об этом смотрите даташит того драйвера, который вы будете использовать в этом проекте.
//Начало скетча первого варианта
const int step_Pin = 5; //контакт для подключения к контакту Step
const int dir_Pin = 6; //контакт для подключения к контакту Dir
const int enable_Pin = 7; //контакт для подключения к контакту Enable
int error_Plus = 0; //поправка цели на прибавление
int error_Minus = 0; //поправка цели на убавление
int tsel = 100; //переменная для хранения значения расстояния которое является целью для шагового двигателя
int speed_1 = 50; //частота импульсов для 1 скости (для сигнала Step)
int speed_2 = 70; //частота импульсов для 2 скости (для сигнала Step)
int speed_3 = 100; //частота импульсов для 3 скости (для сигнала Step)
//Библиотеки для работы с VL53L0X.
//Это стандартные библиотеки, которые можно найти в менеджере библиотек, по запросу "VL53L0X"
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;
//----------------- Здесь все что касается функции scan_distans(); -------------------
//массив для функции scan_distans(); нужен для хранения 50 значений расстояния
int arr_mm [50];
// переменные для функции scan_distans();
int black_mm = 0; //переменная для хранения первичного значения расстояния
int count = 0; //переменная которая является счетчиком для изменения записываемой ячейки массива
int mm = 0; //переменная для хранения усредненного значение расстояния
void scan_distans(){ //функция для получения усредненного значения
black_mm = sensor.readRangeContinuousMillimeters();//получаем первичные данные с датчика расстояния и помещаем их в переменную black_mm
arr_mm [count] = black_mm; //здесь происходит запись первичных данных в массив arr_mm
//в этой очень длинной строке складываются все значения массива arr_mm, и результат делится на количество ячеек массива, таким образом получаем среднее значение на основе последних 50 значений
mm = (arr_mm [0] + arr_mm [1] + arr_mm [2] + arr_mm [3] + arr_mm [4] + arr_mm [5] + arr_mm [6] + arr_mm [7] + arr_mm [8] + arr_mm [9] + arr_mm [10] + arr_mm [11] + arr_mm [12] + arr_mm [13] + arr_mm [14] + arr_mm [15] + arr_mm [16] + arr_mm [17] + arr_mm [18] + arr_mm [19] + arr_mm [20] + arr_mm [21] + arr_mm [22] + arr_mm [23] + arr_mm [24] + arr_mm [25] + arr_mm [26] + arr_mm [27] + arr_mm [28] + arr_mm [29] + arr_mm [30] + arr_mm [31] + arr_mm [32] + arr_mm [33] + arr_mm [34] + arr_mm [35] + arr_mm [36] + arr_mm [37] + arr_mm [38] + arr_mm [39] + arr_mm [40] + arr_mm [41] + arr_mm [42] + arr_mm [43] + arr_mm [44] + arr_mm [45] + arr_mm [46] + arr_mm [47] + arr_mm [48] + arr_mm [49])/50;
count++; if (count>49){count=0;}//здесь происходит прибавление к переменной count, и если на стала больше 49, то переменной count снова присваивается значение ноль
}
//----------------- Конец всего что касается функции scan_distans(); -------------------
void setup()
{
Wire.begin(); //установка соединения с датчиком расстояния
sensor.setTimeout(100); //пауза
if (!sensor.init()){ //если связь с датчиком расстояния не установилась, то попадаем в бесконечный цикл
while (1) {}
}
sensor.startContinuous();
while(count < 50){ //цикл для получения первых 50 значений расстояния и помещения их в массив
black_mm = sensor.readRangeContinuousMillimeters();//получаем первичные данные с датчика расстояния и помещаем их в переменную black_mm
arr_mm [count] = black_mm; //здесь происходит запись первичных данных в массив arr_mm
//в этой очень длинной строке складываются все значения массива arr_mm и результат делится на количество ячеек массива, таким образом получаем среднее значение на основе последних 50 значений
mm = (arr_mm [0] + arr_mm [1] + arr_mm [2] + arr_mm [3] + arr_mm [4] + arr_mm [5] + arr_mm [6] + arr_mm [7] + arr_mm [8] + arr_mm [9] + arr_mm [10] + arr_mm [11] + arr_mm [12] + arr_mm [13] + arr_mm [14] + arr_mm [15] + arr_mm [16] + arr_mm [17] + arr_mm [18] + arr_mm [19] + arr_mm [20] + arr_mm [21] + arr_mm [22] + arr_mm [23] + arr_mm [24] + arr_mm [25] + arr_mm [26] + arr_mm [27] + arr_mm [28] + arr_mm [29] + arr_mm [30] + arr_mm [31] + arr_mm [32] + arr_mm [33] + arr_mm [34] + arr_mm [35] + arr_mm [36] + arr_mm [37] + arr_mm [38] + arr_mm [39] + arr_mm [40] + arr_mm [41] + arr_mm [42] + arr_mm [43] + arr_mm [44] + arr_mm [45] + arr_mm [46] + arr_mm [47] + arr_mm [48] + arr_mm [49])/50;
count++; //прибавляем единицу к переменной count
}
count = 0; //присваиваем ноль переменной count
//назначаем контакты как выходы, и задаем им состояния LOW или HIGH
pinMode(step_Pin, OUTPUT); digitalWrite(step_Pin, LOW);
pinMode(dir_Pin, OUTPUT); digitalWrite(dir_Pin, LOW);
pinMode(enable_Pin, OUTPUT); digitalWrite(enable_Pin, HIGH);
//для крнтпкта enable_Pin следует указать состояние HIGH, так как при LOW драйвер шагового двигателя будет активен
tsel = tsel + error_Plus - error_Minus; //выражение для поправки цели
}
void loop()
{
scan_distans(); //1 раз сканируем расстояние до объекта и получаем новое усредненное значение
if(mm == tsel){ //если расстояние равно цели то выполняем следующее...
noTone(step_Pin);
digitalWrite(enable_Pin, HIGH); //подаем высокий уровень на контакт Step чтобы отключить драйвер шагового двигателя
}else{digitalWrite(enable_Pin, LOW);} //иначе включаем драйвер шагового двигателя и выполняем один из следующих блоков
if(mm - 1 > tsel){ //если расстояние больше цели - единица, то выполняем следующее...
digitalWrite(dir_Pin, LOW); //задаем направление вращения против часовой
//далее при помощи функции tone задаем частоту импульсов в зависимости от расстояния до объекта
if(mm - 11 >= tsel) {tone(step_Pin, speed_3);} //если объект отклонился более чем на 10 мм. то сделать частоту 150 Гц для сигнала Step
if(mm - 3 >= tsel && mm - 10 <= tsel){tone(step_Pin, speed_2);}//если расстояние в пределах от 3 мм. до 10 мм. то сделать частоту 80 Гц
if(mm - 1 >= tsel && mm - 2 <= tsel){tone(step_Pin, speed_1);} //если расстояние в пределах от 1 мм. до 2 мм. то сделать частоту 50 Гц
}
if(mm + 1 < tsel){ //если расстояние меньше цели + единица, то выполняем следующее...
digitalWrite(dir_Pin, HIGH); //задаем направление вращения по часовой
//далее при помощи функции tone задаем частоту импульсов в зависимости от расстояния до объекта
if(mm + 11 <= tsel) {tone(step_Pin, speed_3);} //если объект отклонился более чем на 10 мм то сделать частоту 150 Гц для сигнала Step
if(mm + 3 <= tsel && mm + 10 >= tsel){tone(step_Pin, speed_2);}//если расстояние в пределах от 3 мм. до 10 мм. то сделать частоту 80 Гц
if(mm + 1 <= tsel && mm + 2 >= tsel){tone(step_Pin, speed_1);} //если расстояние в пределах от 1 мм. до 2 мм. то сделать частоту 50 Гц
}
}
//Конец скетча первого варианта
После загрузки скетча на плату Arduino UNO, соберите все как показано на этой схеме
После сборки убедитесь что все верно, и можно подключать питание.
Второй вариант, состоит уже из платы Arduino Uno и платы Digispark.
Данный вариант отличается от предыдущего варианта, более высокой производительностью, в связи с тем, что формированием сигнала Step теперь занимается плата Digispark.
В этом случае скорость вращения шагового двигателя, ограничивается лишь параметрами самого шагового двигателя.
Такая связка представляет, подобие двух ядерного процессора, и позволяет максимально быстро получать значения расстояния, и в тоже время крутить шаговый двигатель с максимально допустимой скоростью.
И в этой версии используется два скетча, которые вместе являются копией предыдущего варианта, с той лишь разницей, что между платами организована простейшая связь, по двум проводам.
Перед сборкой необходимо загрузить этот скетч в плату Arduino Uno.
//Начало скетча второго варианта для платы Arduino Uno
const int dir_Pin = 6; //контакт для подключения к пину Dir
const int enable_Pin = 7; //контакт для подключения к пину Enable
const int kanal_A = 8; //контакт для подключения канала А (для связи с платой Digispark)
const int kanal_B = 9; //контакт для подключения канала В (для связи с платой Digispark)
int error_Plus = 22; //поправка цели на прибавление
int error_Minus = 0; //поправка цели на убавление
int tsel = 100; //переменная для хранения значения расстояния которое является целью для шагового двигателя
//Библиотеки для работы с VL53L0X.
//Это стандартные библиотеки, которые можно найти в менеджере библиотек, по запросу "VL53L0X"
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;
//----------------- Здесь все что касается функции scan_distans(); -------------------
//массив для функции scan_distans(); нужен для хранения 30 значений расстояния
int arr_mm [30];
// переменные для функции scan_distans();
int black_mm = 0; //переменная для хранения первичного значения расстояния
int count = 0; //переменная которая является счетчиком для изменения записываемой ячейки массива
int mm = 0; //переменная для хранения усредненного значение расстояния
void scan_distans(){ //функция для получения усредненного значения
black_mm = sensor.readRangeContinuousMillimeters();//получаем первичные данные с датчика расстояния и помещаем их в переменную black_mm
arr_mm [count] = black_mm; //здесь происходит запись первичных данных в массив arr_mm
//в этой очень длинной строке складываются все значения массива arr_mm, и результат делится на количество ячеек массива, таким образом получаем среднее значение на основе последних 30 значений
mm = (arr_mm [0] + arr_mm [1] + arr_mm [2] + arr_mm [3] + arr_mm [4] + arr_mm [5] + arr_mm [6] + arr_mm [7] + arr_mm [8] + arr_mm [9] + arr_mm [10] + arr_mm [11] + arr_mm [12] + arr_mm [13] + arr_mm [14] + arr_mm [15] + arr_mm [16] + arr_mm [17] + arr_mm [18] + arr_mm [19] + arr_mm [20] + arr_mm [21] + arr_mm [22] + arr_mm [23] + arr_mm [24] + arr_mm [25] + arr_mm [26] + arr_mm [27] + arr_mm [28] + arr_mm [29])/30;
count++; if (count>29){count=0;}//здесь происходит прибавление к переменной count, и если на стала больше 49, то переменной count снова присваивается значение ноль.
}
//----------------- Конец всего что касается функции scan_distans(); -------------------
void setup()
{
Wire.begin(); //установка соединения с датчиком расстояния
sensor.setTimeout(100); //пауза
if (!sensor.init()){ //если связь с датчиком расстояния не установилась, то попадаем в бесконечный цикл
while (1) {}
}
sensor.startContinuous();
while(count < 30){ //цикл для получения первых 30 значений расстояния и помещения их в массив
black_mm = sensor.readRangeContinuousMillimeters();//получаем первичные данные с датчика расстояния и помещаем их в переменную black_mm
arr_mm [count] = black_mm; //здесь происходит запись первичных данных в массив arr_mm
//в этой очень длинной строке, складываются все значения массива arr_mm и результат делится на количество ячеек массива, таким образом получаем среднее значение на основе последних 30 значений
mm = (arr_mm [0] + arr_mm [1] + arr_mm [2] + arr_mm [3] + arr_mm [4] + arr_mm [5] + arr_mm [6] + arr_mm [7] + arr_mm [8] + arr_mm [9] + arr_mm [10] + arr_mm [11] + arr_mm [12] + arr_mm [13] + arr_mm [14] + arr_mm [15] + arr_mm [16] + arr_mm [17] + arr_mm [18] + arr_mm [19] + arr_mm [20] + arr_mm [21] + arr_mm [22] + arr_mm [23] + arr_mm [24] + arr_mm [25] + arr_mm [26] + arr_mm [27] + arr_mm [28] + arr_mm [29])/30;
count++; //прибавляем единицу к переменной count
}
count = 0; //присваиваем ноль переменной count
//назначаем контакты как входы или как выходы, и задаем им состояния LOW или HIGH
pinMode(dir_Pin, OUTPUT); digitalWrite(dir_Pin, LOW);
pinMode(enable_Pin, OUTPUT); digitalWrite(enable_Pin, HIGH);
//для контпкта enable_Pin следует указать состояние HIGH, так как при LOW драйвер шагового двигателя будет активен
pinMode(kanal_A, OUTPUT); //канал A для связи с платой Digispark
digitalWrite(kanal_A, LOW); //задаем низкий уровень, чтобы предотвратить вращение шагового двигателя если это не требуется
pinMode(kanal_B, OUTPUT); //канал B для связи с платой Digispark
digitalWrite(kanal_B, LOW); //задаем низкий уровень, чтобы предотвратить вращение шагового двигателя если это не требуется
tsel = tsel + error_Plus - error_Minus; //выражение для поправки цели
}
void loop()
{
scan_distans(); //1 раз сканируем расстояние до объекта и получаем новое усредненное значение
if(mm == tsel){ //если расстояние равно цели то выполняем следующее...
digitalWrite(enable_Pin, HIGH); //подаем высокий уровень на контакт Step чтобы отключить драйвер шагового двигателя
digitalWrite(kanal_A, LOW);
digitalWrite(kanal_B, LOW);
}else{digitalWrite(enable_Pin, LOW);} //иначе включаем драйвер шагового двигателя и выполняем один из следующих блоков
if(mm - 1 > tsel){ //если расстояние больше цели - единица, то выполняем следующее...
digitalWrite(dir_Pin, LOW); //задаем направление вращения против часовой
//далее при помощи функции tone задаем частоту импульсов в зависимости от расстояния до объекта
if(mm - 1 >= tsel && mm - 2 <= tsel){ digitalWrite(kanal_A, HIGH); digitalWrite(kanal_B, LOW);}
if(mm - 3 >= tsel && mm - 13 <= tsel){ digitalWrite(kanal_A, LOW); digitalWrite(kanal_B, HIGH);}
if(mm - 14 >= tsel) { digitalWrite(kanal_A, HIGH); digitalWrite(kanal_B, HIGH);}
}
if(mm + 1 < tsel){ //если расстояние меньше цели + единица, то выполняем следующее...
digitalWrite(dir_Pin, HIGH); //задаем направление вращения по часовой
//далее при помощи функции tone задаем частоту импульсов в зависимости от расстояния до объекта
if(mm + 1 <= tsel && mm + 2 >= tsel){ digitalWrite(kanal_A, HIGH); digitalWrite(kanal_B, LOW);}
if(mm + 3 <= tsel && mm + 13 >= tsel){ digitalWrite(kanal_A, LOW); digitalWrite(kanal_B, HIGH);}
if(mm + 14 <= tsel) { digitalWrite(kanal_A, HIGH); digitalWrite(kanal_B, HIGH);}
}
}
//Конец скетча второго варианта для платы Arduino Uno
А этот скетч, а это скетч необходимо загрузить в плату Digispark.
В этом варианте проекта, скорости вращения шагового двигателя настраиваются в этом скетче, а не в скетче для платы Arduino Uno!
//Начало скетча второго варианта для платы Digispark
const int step_Pin = 1; //контакт для подключения к контакту Step
const int kanal_A = 0; //контакт для подключения канала А
const int kanal_B = 2; //контакт для подключения канала В
//В зависимость от используемого шагового двигателя, может понадобится настроить задержки в следующих трех строках!
int speed_1 = 8000; //задержка для 1 скости (для сигнала Step)
int speed_2 = 4000; //задержка для 2 скости (для сигнала Step)
int speed_3 = 1000; //задержка для 3 скости (для сигнала Step)
void setup(){
//назначаем контпкты как входы или как выходы, и задаем состояния LOW выходу step_Pin
pinMode(step_Pin, OUTPUT);
pinMode(kanal_A, INPUT_PULLUP); //канал A для связи с платой Arduino Uno
pinMode(kanal_B, INPUT_PULLUP); //канал B для связи с платой Arduino Uno
}
void loop(){
if(digitalRead(kanal_A) == HIGH && digitalRead(kanal_B) == HIGH){ //если kanal_A = HIGH и kanal_B = HIGH
delayMicroseconds(speed_3);
digitalWrite(step_Pin, HIGH);
delayMicroseconds(speed_3);
digitalWrite(step_Pin, LOW);
return;}
if(digitalRead(kanal_A) == LOW && digitalRead(kanal_B) == HIGH){//если kanal_A = LOW и kanal_B = HIGH
delayMicroseconds(speed_2);
digitalWrite(step_Pin, HIGH);
delayMicroseconds(speed_2);
digitalWrite(step_Pin, LOW);
return;}
if(digitalRead(kanal_A) == HIGH && digitalRead(kanal_B) == LOW){//если kanal_A = HIGH и kanal_B = LOW
delayMicroseconds(speed_1);
digitalWrite(step_Pin, HIGH);
delayMicroseconds(speed_1);
digitalWrite(step_Pin, LOW);
return;}
if(digitalRead(kanal_A) == LOW && digitalRead(kanal_B) == LOW){ //если kanal_A = LOW и kanal_B = LOW
digitalWrite(step_Pin, LOW);}
}
//Конец скетча второго варианта для платы Digispark
После загрузки скетчей в плату Arduino Uno, и в плату Digispark, можно собирать все как показано на этой схеме
После сборки убедитесь что все верно, и можно подключать питание.