Технический форум по робототехнике.
RootAdmin » 01 сен 2015, 12:55
Для автоматического регулирования - самое оно. нам нужно некое количество оборотов шаговика на оборот экструдера. Частоту вращения будем подстраивать точно. Регулировка должна сводиться к заданию соотношения, коэффициента разницы скоростей экструдера и шаговика. Там и 0.1 Гц важно.
Кстати, сейчас чуть переделаю код.
Revenger » 01 сен 2015, 14:34
Понял. Молчу )) Просто регулировка кнопками теряет смысл, т.к. изменить скорость вращения быстро не получится.
Пошел считать зубья шестерёнки, а то забыл с поездками...
Добавлено спустя 1 час 26 минут 7 секунд:Зубов на шестерне/звёздочке - 31
Revenger » 02 сен 2015, 16:30
Докупил я смд резистор на оптодатчик, на 20кОм. Сказали, что в наличии только кратно 2кОм, т.е. 18, 20, 22 и т.д. (хотя странно, 4,7кОм то покупал там же)
Думаю 19,7 и 20 не большая разница?
RootAdmin » 02 сен 2015, 16:50
Будет работать, возможно повысится шанс посторонней засветки, но совсем незначительно. Разве что фонариком туда специально светить.
Не успевают сегодня доделать скетч, надеюсь на завтра.
Revenger » 02 сен 2015, 17:50
Светить не буду. Если что, сделаю крышечку ))
Не терпится уже попробовать, но что поделать, раз нет времени... дольше ждали ))
Пока изучаем матчасть ))
Revenger » 03 сен 2015, 00:17
Прикольно смд паять

- Вложения
-
![IMG_1549[1].JPG (2.59 МиБ) Просмотров: 1827 IMG_1549[1].JPG](./download/file.php?id=37936&t=1&style=9)
RootAdmin » 03 сен 2015, 12:33
Ага, особенно феном и пастой. Сами плывут-становятся.
Добавлено спустя 9 минут 13 секунд:
Я бы поставил сопротивление фотодиода между VCC и выводом. Чтоб штатный разъем использовать. Уровень - снимаем с точки соединения резистора и фотодиода.
Revenger » 03 сен 2015, 12:43
Так я вроде куда надо и поставил. Или путаюсь... вроде я так сразу и сделал и проверял напряжение.
Верхние три контакта это как раз провода на разъём.
RootAdmin » 03 сен 2015, 15:22
Да, три контакта разъема. На один подаем питание (VCC), второй - земля (GND). Третий - опять подаем питание на резистор? А снимать сигнал откуда? С точки соединения резистора и фотодиода еще одним проводом?
Revenger » 03 сен 2015, 17:01

Я не знаю
Паял по рекоммендации ранее, когда искали 4В и 0В.
Мнеб схему аль чертёж...
Добавлено спустя 56 минут 15 секунд:Правильно ли я понимаю, резистор 200Ом я перенесу поближе к ноге оптодатчика (ответной части, по дорожке короче той же как идёт), а резистор на 20кОм я просто разверну одной стороной на эту дорожку (по идее там же питание, и оно нужно на двух контактах оптодатчика?), а вторую оставлю на той, где он есть, устранив разрыв, что я сделал.
- Вложения
-

- Без имени-1.jpg (101.53 КиБ) Просмотров: 1742
RootAdmin » 03 сен 2015, 17:54
Да. Но это просто эстетика, наличие-отсутствие провода ни на что не влияет.
Главное - чтоб на ногу ардуины приходил сигнал с правильной точки (соединение резистора и фотодиода).
Revenger » 03 сен 2015, 18:32
Ну так и получается, что белый провод как раз и будет этой правильной точкой вроде.
Я сомневаюсь, т.к. порой наличие резистора или конденсатора в, казалось бы ненужных местах, оказывается очень даже нужными, а их влияние на схему мне не понять в полной мере (подтяжки всякие и т.п.) . ))
п.с. Вот, напаял и... даже работает
На фото даже номинал виден, а в реальности я не могу прочитать что там написано.
- Вложения
-

RootAdmin » 04 сен 2015, 14:06
Теперь верно-красиво. Аж смотреть приятно. Шестерня (зуб) помещается?
Revenger » 04 сен 2015, 17:49
Да, проходит четко. Правда на сколько % перекрывает не знаю, надо по импульсу смотреть, но тянуть всё со стола не хочется.. Хотя чего всё.. датчик и тестер с +5В )) Попробую "на ходу" держа в руках если получится. Да надо будет уже креплением заняться.
Добавлено спустя 3 часа 20 минут 34 секунды:Проверил (с замиранием в сердце )) ), четко впритирку проходит зуб. Ну не прямо впритирку конечно, но выставлять надо будет точно (еще бы звезда не гуляла

).
- Вложения
-

RootAdmin » 04 сен 2015, 19:01
Очередная версия.
- Код: Выделить всё • Развернуть
/*
Управление шаговиком (драйвер степ-дир) переменным резистором
теперь с кнопками! :)
А на этот раз - с экраном и резистивными кнопками.
Добавил измерение скорости вращения экструдера. Чуть подправил генерацию импульса на шаговик.
v 0.5 */
/*
Вывод Назначение
0 UART
1 UART
2 Внешнее прерывание от оптопары
3
4
5 Dir_pin
6 Step_pin
7 LCD RS
8 LCD RW
9 LCD E
10 LCD DB4
11 LCD DB5
12 LCD DB6
13 LCD DB7
A0 Резистор
A1 Кнопки
A2
A3
A4
A5
A6
A7
*/
//#define Razr 1 //признак разработчика. Если пользователь - комментируем или удаляем.
#include <LiquidCrystal.h> // Подключаем стандартную библиотеку LiquidCrystal
// Инициализируем объект-экран, передаём использованные
// для подключения контакты на Arduino в порядке:
#define lcd_RS_pin 7
#define lcd_RW_pin 8
#define lcd_E_pin 9
#define lcd_DB4_pin 10
#define lcd_DB5_pin 11
#define lcd_DB6_pin 12
#define lcd_DB7_pin 13
// RS, RW, E, DB4, DB5, DB6, DB7
LiquidCrystal lcd(lcd_RS_pin, lcd_RW_pin, lcd_E_pin, lcd_DB4_pin, lcd_DB5_pin, lcd_DB6_pin, lcd_DB7_pin);
#define Step_pin 6 //вывод Arduino для ноги STEP контроллера (выход)
#define Dir_pin 5 //вывод Arduino для ноги DIR контроллера (выход)
#define Resistor_pin A0 //вывод Arduino резистора 0-5вольт (аналоговый вход)
//Оптодатчик:
#define OptoSensor_pin 2 //вывод Arduino для оптодатчика (вход)
#define ToothSumm 4 //сколько усреднять зубьев
volatile unsigned long OptoSensorTicks=0;//Переменная для хранения тиков таймера на 1 вызов (время между зубьями)
volatile byte OptoToothCounter =0; //Указатель на текущтй зуб в массиве
volatile unsigned int OptoToothTimeArray [ToothSumm]; //массив с таймингами зубьев
//********** Кнопки:
#define btnRIGHT 1 //Определяем кнопки, это просто внутренние номера, НЕ ноги-выводы
#define btnUP 2
#define btnDOWN 3
#define btnLEFT 4
#define btnSELECT 5
#define btnNONE 0
//**********
#define btnDEFtime 30 //Значение для антидребезга - клавиша удерживаемая столько времени в миллисекундах считается нажатой.
#define btnPAUSEtime 400 //Значение в миллисекундах паузы между повторами
int lcd_key = btnNONE; //Для хранения полученного значеник кнопки
byte keyTemp = btnNONE; //Переменная для хранения временного состояния кнопок
byte keyCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
unsigned long BtnTime; //Хранит время начала нажатия кнопок
byte btnCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
byte btnTemp=btnNONE; //Для хранения номера ранее нажатой кнопки
#if defined(Razr) //Мне для отладки
#define ButtonPin A7 //Сюда подключены кнопки
#else
#define ButtonPin A1 //Сюда подключены кнопки
#endif
//************
byte ControlMode = 0; //Переменная определяет режим управления. 0 - резистор. 1 - кнопки.
//Переменная для значения таймера
volatile unsigned char FullTimer0;
//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256;//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256Count; //внутренный счетчик таймера
//значение минимальной частоты
#define LowFreq 1
//значение МАКСИмальной частоты
#define HighFreq 10000
//Переменная для шага чаcтоты на едниницу изменения АЦП
float FreqStep;
int OutFreq = LowFreq; //Переменная для хранения установленной частоты
//Переменная для текущего значения резистора
int sensorValue = 0;
//Переменная для Старого значения резистора
int OLDsensorValue = 0;
void setup() {
pinMode(Step_pin,OUTPUT); // Конфигурим вывод Step_pin как выход
pinMode(Dir_pin,OUTPUT); // Конфигурим вывод Dir_pin как выход
pinMode(Resistor_pin,INPUT); // Конфигурим вывод Dir_pin как вход
pinMode(OptoSensor_pin,INPUT); // Конфигурим вывод OptoSensor_pin как вход
attachInterrupt(0, OptoSensor, CHANGE); // привязываем 0-е прерывание к функции OptoSensor(). На изменение состояния. Да, из-за разницы между шириной самого зуба и межзубного расстояния - бкдкт различия, усредним.
lcd.begin(16,2); //Инициализируем экран
//Установим на выходах 0
digitalWrite(Step_pin, LOW);
digitalWrite(Dir_pin, LOW);
// Посчитаем "шаг" изменения частоты на единицу изменения резистора
FreqStep=(float)(HighFreq-LowFreq)/1024;
//Запускает последовательный порт
Serial.begin(9600);
//Сообщение о запуске программы
Serial.println("Program started");
// Serial.print("FreqStep=");
// Serial.println(FreqStep);
//Запускает таймер и получает загружаемое значение таймера.
//Параметр - желаемая частота в герцах.
FullTimer0=SetupTimer2(50);
//Установки Таймер2: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон в районе 1 кгц
//так что сейчас мы просто жестко запрограммируем это.
TCCR2A = 0;
TCCR2B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer2
TIMSK2 = 1<<TOIE2;
//Установки Таймер1: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон
//так что сейчас мы просто жестко запрограммируем это.
TCCR1A = 0;
TCCR1B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer0 (для обнуления скорости)
TIMSK1 = 1<<TOIE1;
//Выводит загружаемое значение таймера
Serial.print("Timer2 Load:");
Serial.println(FullTimer0,HEX);
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print("Stepper control"); //выводим на него строку
lcd.setCursor(0, 1); //устанавливаем курсор
lcd.print("R B "); //выводим на него строку
lcd.setCursor(0, 1); //устанавливаем курсор
lcd.cursor(); //Включим курсор
lcd.blink(); //Пусть мигает
delay(10);
}
void loop() {
lcd_key=read_LCD_buttons(); //прочитаем нажатую кнопку
if (lcd_key) //Нажата какая-то кнопка
{
Serial.print("Button=");
Serial.println(lcd_key,DEC);
if (btnRIGHT==lcd_key) //нажата кнопка ВПРАВО
{
lcd.setCursor(6, 1);
ControlMode = 1;
}
if (btnLEFT==lcd_key) //нажата кнопка ВЛЕВО
{
lcd.setCursor(0, 1);
ControlMode = 0;
}
}
if (ControlMode) //Если режим "кнопки"
{
if (btnUP==lcd_key) //Если нажата кнопка "Больше"
#if defined(Razr) //Мне для отладки
{OutFreq+=1000;}
#else
{OutFreq+=1;}
#endif
if (btnDOWN==lcd_key) //Если нажата кнопка "Меньше"
#if defined(Razr) //Мне для отладки
{OutFreq-=1000;}
#else
{OutFreq-=1;}
#endif
if (lcd_key) //Если вообще что-то нажато
{
SetupTimer2(OutFreq);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(FullTimer0);
lcd.setCursor(4, 0);
lcd.print(FullTimer256);
lcd.setCursor(7, 1);
lcd.print(" "); //чистим вывод
lcd.setCursor(7, 1);
lcd.print(OutFreq); //выводим Частоту
lcd.setCursor(6, 1);
}
}
else //Если режим резистор (светодиод выключен)
{
//Тут будем читать занчение
sensorValue=analogRead(Resistor_pin);
//Сравним значение со старым, если отличается - пересчитаем установку таймера
if (sensorValue!= OLDsensorValue)
{ //Serial.println("ReCall"); //debug
OLDsensorValue=sensorValue;
OutFreq = LowFreq+FreqStep*sensorValue; //Вычислим новое значение частоты
lcd.setCursor(1, 1);
lcd.print(" "); //Чистим вывод
lcd.setCursor(1, 1);
lcd.print(OutFreq); //выводим Частоту
lcd.setCursor(0, 1);
SetupTimer2(OutFreq);
}
}
//выведем скорость
OptoSensorTicks=0;
for (int i=0; i<ToothSumm; i++) {OptoSensorTicks+=OptoToothTimeArray[i];}
OptoSensorTicks*=35/ToothSumm; //разделим тики , получаем тиков на оборот
lcd.setCursor(8, 0);
lcd.print(" ");
lcd.setCursor(8, 0);
lcd.print(OptoSensorTicks);
/*
Serial.print("sensor=");
Serial.println(sensorValue,DEC);
Serial.print("FullTimerCount");
Serial.println(FullTimerCount);
Serial.print("FullTimer");
Serial.println(FullTimer,DEC);
Serial.print("timer=");
Serial.println(FullTimer0,DEC);
Serial.print("ButtPressed=");
Serial.println(ButtPressed,DEC);
Serial.print("OutFreq=");
Serial.println(OutFreq,DEC);
Serial.println("***");
Serial.println("");
Serial.println("***");
Serial.println(OptoSensorTicks);
delay (200);
*/
}
//Timer1 указатель вектора прерывания по переполнению
ISR(TIMER1_OVF_vect)
{
OptoToothTimeArray[OptoToothCounter]=0; //присваиваем элементу массива 0
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
//Timer2 указатель вектора прерывания по переполнению
ISR(TIMER2_OVF_vect)
{
if (FullTimer256Count>1)
{FullTimer256Count--;}
else
{if (FullTimer256Count==1) //предпоследний цикл
{
TCNT2+=FullTimer0;
FullTimer256Count=0;
}
{if (FullTimer256Count==0) // Срабатывание
{
//Переключение IO-вывода в HIGH
digitalWrite(Step_pin,HIGH);
FullTimer256Count=FullTimer256;
//Переключение IO-вывода в другое состояние.
// digitalWrite(Step_pin,!digitalRead(Step_pin));
//Перезагрузка таймера и коррекция по задержке
if (FullTimer256)
{TCNT2=0;} //Если холостые циклы есть - максимальное значение
else
{TCNT2+=FullTimer0;}
//Переключение IO-вывода в LOW
digitalWrite(Step_pin,LOW);
}
}
}
}
#define TIMER_CLOCK_FREQ 250000.0
//15625 for /1024
//2MHz for /8 prescale from 16MHz
//Установка Таймера2.
//Конфигурирует 8-битный Таймер2 ATMega168 для выработки прерывания
//с заданной частотой.
//Возвращает начальное значение таймера, которое должно быть загружено в TCNT2
//внутри вашей процедуры ISR.
//Смотри пример использования ниже.
unsigned char SetupTimer2(float timeoutFrequency){
//Подсчет начального значения таймера
//Слегка усложним, добавив холостые просчеты
long ticks = TIMER_CLOCK_FREQ/timeoutFrequency; // тиков счетчика для получения заданной частоты
// #if defined(Razr)
// lcd.setCursor(9, 0);
// lcd.print(ticks);
// #endif
FullTimer256=ticks/256; //Вычисляем количество ПОЛНЫХ 256 циклов таймера
ticks-=FullTimer256*256;
FullTimer0=(byte)(257.0-(ticks+0.5)); //Вычисляем количество доплнительных тиков таймера
//257 на самом деле должно быть 256, но я получил лучшие результаты с 257.
//загружает таймер для первого цикла
if (FullTimer256)
{TCNT2=0;} //Если холостые циклы есть - максимальное значение
else
{TCNT2=FullTimer0;}
}
// *****************************
//Чтение кнопок с антидребезгом
// read the buttons
int read_LCD_buttons()
{
int adc_key_in = analogRead(ButtonPin); // Получаем напряжение с АЦП
byte btnTempTemp = btnNONE; //Переменная для хранения свежесчитанного внутри функции
//digitalWrite (LED_pin,0); //debug
//lcd.setCursor(5, 0); //debug
//lcd.print(adc_key_in); //debug
//delay (400); //debug
//Тут используем millis() для отслеживания нажатия кнопки
// Запоминиаем в переменной BtnTime ВРЕМЯ НАЧАЛА нажатия
// Запоминаем в переменной btnTemp нажатия
// Дефиним время антидребезга #define
if (adc_key_in > 950) //Ничего не нажато
{
//BtnTime=0; //Скидываем время нажатия
btnCONTpress=0;
return btnNONE; // We make ths the 1st option for speed reasons since it will be the most likely result
}
else //что-то нажато
{
if (adc_key_in < 790) { btnTempTemp=btnSELECT; } //Определяем в переменную ТЕКУЩУЮ нажатую кнопку.
if (adc_key_in < 555) { btnTempTemp=btnLEFT; }
if (adc_key_in < 380) { btnTempTemp=btnDOWN; }
if (adc_key_in < 195) { btnTempTemp=btnUP; }
if (adc_key_in < 50) { btnTempTemp=btnRIGHT; }
//А тут проверим, совпадает ли с btnTemp (была ли нажата ранее)
/* lcd.setCursor(0, 0); //debug
lcd.print(btnTempTemp); //debug
lcd.setCursor(2, 0); //debug
lcd.print(btnTemp); //debug
lcd.setCursor(1, 1); //debug
lcd.print(millis()); //debug
lcd.setCursor(12, 1); //debug
digitalWrite (LED_pin,1); //debug
delay (100);
lcd.print(" "); //debug
lcd.setCursor(12, 1); //debug
lcd.print(adc_key_in); //debug
*/
if (btnTempTemp==btnTemp) //Кнопка уже БЫЛА нажата
{
if (btnCONTpress) //Повторные установки клавиши
{
if ((millis()-BtnTime) > btnPAUSEtime)
{
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
else //Первая установка клавиши
{
if ((millis()-BtnTime) > btnDEFtime)
{
btnCONTpress=1;
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
}
else //Раньше было другое состояние
{
// digitalWrite (LED_pin,1); //debug
// delay (100);
btnCONTpress=0;
BtnTime=millis(); //Устанавливаем ТЕКУЩЕЕ время в переменную BtnTime
btnTemp=btnTempTemp; //устанавливаем кнопку во временную переменную.
}
}
return btnNONE; // Если ничего не сработало, то ничего не возвращаем
}
//***********************************
void OptoSensor() // функция обработки прерывания. Меняет глобальные прееменные
{//Сработал - значит считаем тики. F njxytt - echtlyztv pf
OptoToothTimeArray[OptoToothCounter]=TCNT1; //присваиваем элементу массива текущее значение таймера
TCNT1 = 0; //сбрасываем таймер
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
Вывел частоту вращения в верхнюю строку справа, частота сейчас выводится в тиках таймера на оборот.
Поменял алгоритм формирования частоты шаговику, должен вертеться вдвое быстрей. То есть выдаю сейчас по короткому импульсу на герц.
Нужно проверить - работает ли оптопара, что примерно показывает "частотомер" - буду пилить настройку коэффициента соотношения скоростей.
Добавлено спустя 1 минуту 10 секунд:Да даже не проходил бы - оптопару можно и пополам разрезать. Может так и сделать.