Использование энкодера в качестве нелинейного регулятора.
Добрый день,
Автоматизирую сверлильно присадочный станок.
Сделана электронная линейка 3000мм -рабочи ход. Ход каретки
измеряется оптическим энкодером (передача трос на шкивах на
двигателе возможны пропуски шагов или прокруты) . Каретка
управляется шаговым двигателем, эта часть работает.
Не сделано: ввод заданного значения на дисплей
изначально планировал клавиатуру, но не хватает на все
выводов контролера.
Из Вашего урока №55 про мех. энкодер родилась идея
использовать энкодер для задания величины на дисплее
перемещения каретки от 0 до 3000мм с шагом 1мм. (по аналогии
управления перемещения шпинделя сверлильного станка, быстрее
крутим - быстрее меняется число на дисплее).
Можно ли увидеть программу управления шпинделем сверл.станка
полностью с
"...Анализировал признаки timeRight и timeLeft. При ненулевом
значении признаков шаговый двигатель перемещения шпинделя
делал количество шагов в зависимости от значения активного
признака. Зависимость задал в массиве."
Использование энкодера в качестве нелинейного регулятора.
Re: Использование энкодера в качестве нелинейного регулятора.
Здравствуйте!
Заказчик программы для управления сверлильным станком разрешил выложить скетч.
Заказчик программы для управления сверлильным станком разрешил выложить скетч.
Код: Выделить всё
#include <TimerOne.h>
#include <Encod_er.h>
#include <StepDirDriverL.h>
#include <Button.h>
#include <EEPROM.h>
#include <LiquidCrystalRus.h>
#include <avr/wdt.h>
#define PIN_DRILLER_ON 9 // включение двигателя сверла _-_
#define PIN_LIGHT 11 // подсветка _-_
#define PIN_PWM_DRILL 3 // ШИМ двигателя сверла
#define TIME_POWER_SAVE 40 // время перехода в режим энергосбережения (* 0,25 сек, 63 сек макс.)
#define TIME_POWER_OFF 120 // // время перехода в режим выключения двигателя (* 0,25 сек, 63 сек макс.)
#define SPINDLE_VEL 4 // скорость движения ШПИНДЕЛЯ (Tкомм.фаз = SPINDLE_VEL * 0,25 мс)
#define SCALE_SPINDLE 0.1 // массштаб перевода шагов в перемещение шпинделя (сколько в шаге мм)
#define MAX_SPINDLE 1000 // максимальное расстояние перемещения ШПИНДЕЛЯ в шагах
#define MIN_VEL_DRILL 64 // минимальный ШИМ двигателя сверла (0...255)
#define TIME_FAST_MENU 31 // время для выбора быстрого меню (* 64 мс)
#define TIME_FLASH_SYNHR 2000 // время мигания сообщения СИНХРОНИЗАЦИЯ (* 0,25 мс)
#define ACKN_SPINDLE_UP 40 // число подтверждений датчика ШПИНДЕЛЬ ВВЕРХУ (* 0,25 мс)
#define ACKN_PEDAL 80 // число подтверждений кнопки ПЕДАЛЬ (* 0,25 мс)
#define ACKN_ENCODER 80 // число подтверждений кнопки ЭНКОДЕР (* 0,25 мс)
// адреса EEPROM
#define EEPROM_POS_SP_BEFORE 5 // положение шпиндлера перед деталью
#define EEPROM_POS_SP_DETAIL 10 // положение шпиндлера на деталь
#define EEPROM_POS_DEPTH_DRILL 15 // глубина сверловки
#define EEPROM_MATERIAL_NUMBER 20 // номер материала
#define EEPROM_BRIGHT 22 // яркость подсветки
#define EEPROM_USER_DRILL_VEL 24 // пользовательская скорость сверла
#define EEPROM_USER_SPINDLE_VEL 26 // пользовательская скорость шпинделя
Encod_er encoder(2, 8, 4); // энкодер
StepDirDriverL spindleMotor(5, 4, 6); // двигатель шпинделя
Button sensSpindleUp(12, ACKN_SPINDLE_UP); // датчик ШПИНДЕЛЬ ВВЕРХУ
Button buttonPedal(7, ACKN_PEDAL); // кнопка ПЕДАЛЬ
Button buttonEncoder(10, ACKN_ENCODER); // кнопка ЭНКОДЕР
LiquidCrystalRus disp(13, 15, 16, 17, 18, 19); // дисплей
// МАССИВ МЕНЮ ВЫБОР МАТЕРИАЛА
struct mMenu {
char materialName[16]; // название материала
byte materialVelDrill; // скорость сверловки (0...255)
byte materialSpindleVel; // скорость опускания шпинделя (0...255)
};
struct mMenu materialMenu[20] = {
{ "1 tekstolit", 20, 10 },
{ "2 tekstolit", 30, 11 },
{ "3 tekstolit", 40, 12 },
{ "4 tekstolit", 50, 13 },
{ "5 tekstolit", 60, 14 },
{ "6 tekstolit", 80, 15 },
{ "7 tekstolit", 100, 16 },
{ "8 tekstolit", 150, 17 },
{ "9 tekstolit", 200, 18 },
{ "10 tekstolit", 255, 19 },
{ "11 tekstolit", 255, 20 },
{ "12 tekstolit", 255, 21 },
{ "13 tekstolit", 255, 22 },
{ "14 tekstolit", 255, 30 },
{ "15 tekstolit", 255, 50 },
{ "16 tekstolit", 255, 10 },
{ "17 tekstolit", 255, 10 },
{ "18 tekstolit", 255, 10 },
{ "19 tekstolit", 255, 10 },
{ "pol_zovatel_skiy", 255, 10 }
};
// МАССИВ ПЕРЕМЕЩЕНИЯ ШПИНДЕЛЯ ЭНКОДЕРОМ
struct mE {
byte timeEncoder; // порог времени энкодера
byte dividerMoto; // скорость двигателя (делитель)
long stepsMoto; // число шагов
};
/*
struct mE movEncoder[14] = {
{5, 4, 30},
{10, 4, 25},
{20, 5, 20},
{30, 5, 15},
{40, 5, 12},
{50, 5, 8},
{60, 5, 6},
{70, 6, 5},
{80, 6, 4},
{90, 7, 3},
{105, 8, 2},
{155, 9, 1},
{255, 10, 1},
{255, 10, 1}
};
*/
struct mE movEncoder[14] = {
{5, 4, 300},
{10, 4, 250},
{20, 5, 200},
{30, 5, 150},
{40, 5, 120},
{50, 5, 80},
{60, 5, 60},
{70, 6, 50},
{80, 6, 40},
{90, 7, 30},
{105, 8, 20},
{155, 9, 10},
{255, 10, 5},
{255, 10, 5}
};
long posSpindle= 0; // текущее положение ШПИНДЕЛЯ
long posSpindleBefore; // положение ШПИНДЕЛЯ перед деталью
long posSpindleDetail; // положение ШПИНДЕЛЯ на деталь
long depthDrill; // глубина сверловки
byte materialNumber=0; // номер материала
byte bright=255; // яркость подсветки
byte mode=0; // режим
unsigned int timer1=0; // таймер 1 (общего назначения, 0,25 мс)
boolean firstCycle; // признак первый проход
boolean errorEeprom=false; // признак ошибки EEPROM
byte x;
unsigned int divTimerPS; // делитель таймера энергосберегающего режима
byte timerPowerSave=0; // таймер энергосберегающего режима (* 0,25 сек)
void setup() {
//Serial.begin(9600); // инициализируем порт, скорость 9600
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
spindleMotor.setMode(0, false); // шаговый режим, без фиксации при остановке
spindleMotor.setDivider(5); // делитель частоты
disp.begin(16, 2); // инициализируем дисплей 2 строки по 16 символов
disp.print("SYNHRONIZASIY"); // сообщение СИНХРОНИЗАЦИЯ
pinMode(PIN_DRILLER_ON, OUTPUT); // двигатель сверла
digitalWrite(PIN_DRILLER_ON, LOW);
// чтение и проверка данных EEPROM
errorEeprom=false;
if(readLongFromEeprom(EEPROM_POS_SP_BEFORE, & posSpindleBefore) == false) {posSpindleBefore=0; errorEeprom=true;}
if(readLongFromEeprom(EEPROM_POS_SP_DETAIL, & posSpindleDetail) == false) {posSpindleDetail=0; errorEeprom=true;}
if(readLongFromEeprom(EEPROM_POS_DEPTH_DRILL, & depthDrill) == false) {depthDrill=0; errorEeprom=true;}
if(readByteFromEeprom(EEPROM_MATERIAL_NUMBER, & materialNumber) == false) {materialNumber= 0; }
if(readByteFromEeprom(EEPROM_BRIGHT, & bright) == false) {bright= 255; }
x= materialMenu[19].materialVelDrill;
if(readByteFromEeprom(EEPROM_USER_DRILL_VEL, & materialMenu[19].materialVelDrill) == false) {materialMenu[19].materialVelDrill= x; }
x= materialMenu[19].materialSpindleVel;
if(readByteFromEeprom(EEPROM_USER_SPINDLE_VEL, & materialMenu[19].materialSpindleVel) == false) {materialMenu[19].materialSpindleVel= x; }
analogWrite(PIN_LIGHT, bright); // подсветка
analogWrite(PIN_PWM_DRILL, 0); // ШИМ двигателя сверла
wdt_enable(WDTO_15MS); // разрешение работы сторожевого таймера с тайм-аутом 15 мс
}
void loop() {
//- 0 ---------- пауза для установки начального состояния кнопок, датчиков
if(mode == 0) {
if(timer1 > 200) mode= 1; // переход
}
//-- 1 --------- движение шпинделя вниз, до тех пор пока не сойдет с датчика ШПИНДЕЛЬ ВВЕРХУ
else if(mode == 1) {
if(sensSpindleUp.flagPress == true) {
// движение шпинделя вниз
spindleMotor.setDivider(SPINDLE_VEL); // скорость ШПИНДЕЛЯ
spindleMotor.step(-10); // движение вниз
}
else { mode= 2; timer1=0; } // переход
}
//-- 2 --------- движение шпинделя вверх, до тех пор пока не сработает датчик ШПИНДЕЛЬ ВВЕРХУ
else if(mode == 2) {
// мигающее сообщение СИНХРОНИЗАЦИЯ
if(timer1 == 0) disp.print("SYNHRONIZASIY");
if(timer1 == TIME_FLASH_SYNHR) disp.clear();
if(timer1 == (TIME_FLASH_SYNHR * 2)) timer1= 0;
if(sensSpindleUp.flagPress != true) {
// движение шпинделя вверх
spindleMotor.setDivider(SPINDLE_VEL); // скорость ШПИНДЕЛЯ
spindleMotor.step(10); // движение вверх
}
else {
spindleMotor.step(0); // остановка ШПИНДЕЛЯ
posSpindle= 0; // положение ШПИНДЕЛЯ
buttonEncoder.flagClick= false;
if(errorEeprom == true) {
// ошибка EEPROM
// сообщение ОШИБКА EEPROM
// ТОЛЬКО МЕНЮ
disp.clear();
disp.print("OSIBKA EEPROM");
disp.setCursor(0, 1);
disp.print("TOLKO MENU");
}
else {
// сообщение СВЕРЛО К ДЕТАЛИ
// ВЕРХ-> 135.29 мм
disp.clear();
disp.print("SVERLO K DETALI");
disp.setCursor(0, 1);
disp.print("VERH-> ");
disp.print(posSpindleBefore * SCALE_SPINDLE);
disp.print(" mm");
}
encoder.timeRight= 0;
encoder.timeLeft= 0;
mode= 3; // переход
}
timerPowerSave= 0;
}
//-- 3 --------- окончание синхронизации, ожидание первого нажатия педали
else if(mode == 3) {
if(errorEeprom == false) {
if(buttonPedal.flagPress == true) {
spindleMotor.setDivider(SPINDLE_VEL); // скорость ШПИНДЕЛЯ
spindleMotor.step(posSpindle - posSpindleBefore);
encoder.timeRight= 0;
encoder.timeLeft= 0;
timerPowerSave= 0;
mode= 4; // переход на первое опускание до детали
}
}
if(buttonEncoder.flagClick == true) {
buttonEncoder.flagClick= false;
firstCycle=true;
timer1= 0;
timerPowerSave= 0;
mode=7; // переход на меню
}
if( (encoder.timeRight != 0) || (encoder.timeLeft != 0) ) {
// двинули энкодер
// позиция шпинделя
encoder.timeRight= 0;
encoder.timeLeft= 0;
buttonPedal.flagClick= false;
firstCycle= true;
timerPowerSave= 0;
mode= 5; // переход на установку энкодером
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 4 --------- первое опускание шпинделя до позиции перед деталью
else if(mode == 4) {
if( (encoder.timeRight != 0) || (encoder.timeLeft != 0) ) {
// двинули энкодер
// позиция шпинделя
posSpindle= posSpindleBefore + spindleMotor.readSteps(); // изменен знак step
spindleMotor.step(0); // остановка
encoder.timeRight= 0;
encoder.timeLeft= 0;
buttonPedal.flagClick= false;
firstCycle= true;
timerPowerSave= 0;
mode= 5; // переход на установку энкодером
}
else if( spindleMotor.readSteps() == 0){
// остановка по достижению позиции
posSpindle= posSpindleBefore;
buttonPedal.flagClick= false;
buttonEncoder.flagClick= false;
firstCycle= true;
timerPowerSave= 0;
mode= 14; // переход на МОЖНО СВЕРЛИТЬ
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 5 --------- установка положения шпинделя энкодером
else if(mode == 5) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение УСТ. ШПИНДЕЛЯ
// 234.18 мм
disp.clear();
disp.print("UST. SPINDELY");
disp.setCursor(0, 1);
disp.print(posSpindle * SCALE_SPINDLE);
disp.print(" mm");
}
if( ustSpindleEnc() == true) { // двинули энкодер
posSpindleBefore= posSpindle;
timerPowerSave= 0;
mode= 6; // переход
}
if(buttonPedal.flagClick == true) {
buttonPedal.flagClick= false;
buttonEncoder.flagClick= false;
firstCycle= true;
timerPowerSave= 0;
mode= 14; // переход на сверловку
}
if(buttonEncoder.flagClick == true) {
buttonEncoder.flagClick= false;
firstCycle=true;
timer1= 0;
timerPowerSave= 0;
mode=7; // переход на меню
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 6 --------- отработка перемещения шпинделя
else if(mode == 6) {
if( spindleMotor.readSteps() == 0){
firstCycle= true;
mode= 5; // переход
}
timerPowerSave= 0;
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-------------- БЫСТРОЕ МЕНЮ ------------------
//-- 7 --------- выбор типа меню
else if(mode == 7) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ПОКА
// сообщение БЫСТРОЕ МЕНЮ
disp.clear();
disp.print("POKA");
disp.setCursor(0, 1);
disp.print("BYSTROE MENU");
}
if( (timer1 >> 8) == TIME_FAST_MENU ) {
// сообщение РАСШИРЕННОЕ
// сообщение МЕНЮ
disp.clear();
disp.print("RASHIRENNOE");
disp.setCursor(0, 1);
disp.print("MENU");
}
if( buttonEncoder.flagPress == false ) {
buttonEncoder.flagClick= false;
encoder.timeRight= 0;
encoder.timeLeft= 0;
firstCycle=true;
if( (timer1 >> 8) < TIME_FAST_MENU ) mode=8; // переход на быстрое меню
else mode=18; // переход на расширенное меню
}
timerPowerSave= 0;
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 8 --------- установка положения шпинделя перед деталью
else if(mode == 8) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение УСТ. ШПИНДЕЛЯ
// -> | 234.8 мм
disp.clear();
disp.print("UST. SPINDELY");
disp.setCursor(0, 1);
disp.print("-> | ");
disp.print(posSpindle * SCALE_SPINDLE);
disp.print(" mm");
}
if( ustSpindleEnc() == true) { // двинули энкодер
posSpindleBefore= posSpindle;
timerPowerSave= 0;
mode= 9; // переход
}
// проверка перехода дальше по меню
if(buttonEncoder.flagClick == true) {
// запись posSpindleBefore в EEPROM
long _posSpindleBefore;
if((readLongFromEeprom(EEPROM_POS_SP_BEFORE, & _posSpindleBefore) == false) || (posSpindleBefore != _posSpindleBefore)) {
writeLongToEeprom(EEPROM_POS_SP_BEFORE, & posSpindleBefore);
}
buttonEncoder.flagClick= false;
firstCycle=true;
timerPowerSave= 0;
mode=10; // переход на установку шпинделя на деталь
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 9 --------- отработка перемещения шпинделя
else if(mode == 9) {
if( spindleMotor.readSteps() == 0){
firstCycle= true;
mode= 8; // переход
}
timerPowerSave= 0;
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 10 --------- установка положения шпинделя на деталь
else if(mode == 10) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение УСТ. ШПИНДЕЛЯ
// ->| 234.8 мм
disp.clear();
disp.print("UST. SPINDELY");
disp.setCursor(0, 1);
disp.print("->| ");
disp.print(posSpindle * SCALE_SPINDLE);
disp.print(" mm");
}
if( ustSpindleEnc() == true) { // двинули энкодер
posSpindleDetail= posSpindle;
timerPowerSave= 0;
mode= 11; // переход
}
// проверка перехода дальше по меню
if(buttonEncoder.flagClick == true) {
// запись posSpindleDetail в EEPROM
long _posSpindleDetail;
if((readLongFromEeprom(EEPROM_POS_SP_DETAIL, & _posSpindleDetail) == false) || (posSpindleDetail != _posSpindleDetail)) {
writeLongToEeprom(EEPROM_POS_SP_DETAIL, & posSpindleDetail);
}
buttonEncoder.flagClick= false;
firstCycle=true;
timerPowerSave= 0;
mode=12; // переход на выбор глубины
}
analogWrite(PIN_PWM_DRILL, 0);
digitalWrite(PIN_DRILLER_ON, LOW);
}
//-- 11 --------- отработка перемещения шпинделя
else if(mode == 11) {
if( spindleMotor.readSteps() == 0){
firstCycle= true;
timerPowerSave= 0;
mode= 10; // переход
}
analogWrite(PIN_PWM_DRILL, 0);
digitalWrite(PIN_DRILLER_ON, LOW);
}
//-- 12 -------- выбор глубины сверловки
else if(mode == 12) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение УСТ. ГЛУБИНЫ
// 234.8 мм
disp.clear();
disp.print("UST. GLUBINY");
disp.setCursor(0, 1);
disp.print("-|-> ");
disp.print(depthDrill * SCALE_SPINDLE);
disp.print(" mm");
}
// проверка энкодера
if(encoder.timeRight != 0) {
for(int i=0; i<14; i++) {
if(encoder.timeRight <= movEncoder[i].timeEncoder) {
depthDrill += movEncoder[i].stepsMoto;
encoder.timeRight= 0;
encoder.timeLeft= 0;
firstCycle= true;
timerPowerSave= 0;
break;
}
}
}
else if(encoder.timeLeft != 0) {
for(int i=0; i<14; i++) {
if(encoder.timeLeft <= movEncoder[i].timeEncoder) {
depthDrill -= movEncoder[i].stepsMoto;
if(depthDrill < 0) depthDrill=0;
encoder.timeRight= 0;
encoder.timeLeft= 0;
firstCycle= true;
timerPowerSave= 0;
break;
}
}
}
// проверка перехода дальше по меню
if(buttonEncoder.flagClick == true) {
// запись depthDrill в EEPROM
long _depthDrill;
if((readLongFromEeprom(EEPROM_POS_DEPTH_DRILL, & _depthDrill) == false) || (depthDrill != _depthDrill)) {
writeLongToEeprom(EEPROM_POS_DEPTH_DRILL, & depthDrill);
}
buttonEncoder.flagClick= false;
buttonPedal.flagClick= false;
firstCycle=true;
timerPowerSave= 0;
mode=15; // переход на сверловку
}
analogWrite(PIN_PWM_DRILL, 0);
digitalWrite(PIN_DRILLER_ON, LOW);
}
//----------------------- СВЕРЛОВКА --------------------
//-- 14 --------- ожидание нажатия педали (рабочего)
else if(mode == 14) {
if(firstCycle == true) { // первый вход
firstCycle= false;
if( posSpindleBefore > posSpindleDetail ) {
// сообщение ПАРАМЕТРЫ ЗАДАНЫ
// сообщение НЕПРАВИЛЬНО
disp.clear();
disp.print("PARAMETRY ZADANY");
disp.setCursor(0, 1);
disp.print("NEPRAVILNO");
}
else {
// сообщение МОЖНО СВЕРЛИТЬ
disp.clear();
disp.print("MOGNO SVERLIT");
disp.setCursor(0, 1);
disp.print(posSpindle * SCALE_SPINDLE);
disp.print(" ");
disp.print(depthDrill * SCALE_SPINDLE);
disp.print(" mm");
}
}
if(buttonPedal.flagClick == true) {
spindleMotor.setDivider(materialMenu[materialNumber].materialSpindleVel); // скорость ШПИНДЕЛЯ
spindleMotor.step( posSpindle - (posSpindleDetail + depthDrill));
posSpindle= posSpindleDetail + depthDrill;
buttonPedal.flagClick= false;
firstCycle=true;
timerPowerSave= 0;
mode= 15; // переход
}
if(buttonEncoder.flagClick == true) {
buttonEncoder.flagClick= false;
firstCycle=true;
timer1= 0;
timerPowerSave= 0;
mode=7; // переход на меню
}
// корректировка энкодером
if( ustSpindleEnc() == true) { // двинули энкодер
posSpindleBefore= posSpindle;
timerPowerSave= 0;
mode= 17; // переход
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_SAVE) { analogWrite(PIN_PWM_DRILL, materialMenu[materialNumber].materialVelDrill); digitalWrite(PIN_DRILLER_ON, HIGH); }
else if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 15 --------- сверловка
else if(mode == 15) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ИДЕТ СВЕРЛОВКА
disp.clear();
disp.print("IDET SVERLOVKA");
}
if( spindleMotor.readSteps() == 0){
spindleMotor.setDivider(SPINDLE_VEL); // скорость ШПИНДЕЛЯ
spindleMotor.step( posSpindle - posSpindleBefore);
buttonEncoder.flagClick= false;
firstCycle=true;
mode= 16; // переход
}
if(buttonPedal.flagClick == true) {
//прекращение операции (аварийный стоп)
buttonPedal.flagClick= false;
spindleMotor.setDivider(SPINDLE_VEL); // скорость ШПИНДЕЛЯ
spindleMotor.step( posSpindle - posSpindleBefore + spindleMotor.readSteps() +2);
buttonEncoder.flagClick= false;
firstCycle=true;
mode= 16; // переход
}
timerPowerSave= 0;
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_SAVE) { analogWrite(PIN_PWM_DRILL, materialMenu[materialNumber].materialVelDrill); digitalWrite(PIN_DRILLER_ON, HIGH); }
else if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 16 --------- подъем шпинделя
else if(mode == 16) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ПОДЪЕМ ШПИНДЕЛЯ
disp.clear();
disp.print("POD_EM SPINDELY");
}
if( spindleMotor.readSteps() == 0){
posSpindle= posSpindleBefore;
buttonPedal.flagClick= false;
buttonEncoder.flagClick= false;
firstCycle=true;
mode= 14; // переход на ожидание нажатия педали
}
timerPowerSave= 0;
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_SAVE) { analogWrite(PIN_PWM_DRILL, materialMenu[materialNumber].materialVelDrill); digitalWrite(PIN_DRILLER_ON, HIGH); }
else if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 17 --------- отработка перемещения шпинделя
else if(mode == 17) {
if( spindleMotor.readSteps() == 0){
firstCycle= true;
timerPowerSave= 0;
mode= 14; // переход на сверловку
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_SAVE) { analogWrite(PIN_PWM_DRILL, materialMenu[materialNumber].materialVelDrill); digitalWrite(PIN_DRILLER_ON, HIGH); }
else if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//---------------------- расширенное меню ----------------------
//-- 18 --------- ЗАМЕНА СВЕРЛА
else if(mode == 18) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ЗАМЕНА СВЕРЛА
disp.clear();
disp.print("ZAMENA SVERLA");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 19; // переход на остановку
}
if( encoder.timeRight != 0 ) {
resAllFlags();
mode= 20; // переход на меню ВЫБОР МАТЕРИАЛА
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
mode= 22; // переход на меню ВЫХОД
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 19 --------- остановка двигателя
else if(mode == 19) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение МОЖНО МЕНЯТЬ
// СВЕРЛО
disp.clear();
disp.print("MOZNO MENYT_");
disp.setCursor(0, 1);
disp.print("SVERLO");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 18; // переход на меню ЗАМЕНА СВЕРЛА
}
analogWrite(PIN_PWM_DRILL, 0);
digitalWrite(PIN_DRILLER_ON, LOW);
}
//-- 20 --------- ВЫБОР МАТЕРИАЛА
else if(mode == 20) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ВЫБОР МАТЕРИАЛА
disp.clear();
disp.print("VYBOR MATERIALA");
disp.setCursor(0, 1);
//disp.print( materialMenu[materialNumber].materialName );
textToDisp();
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 23; // переход на материалы
}
if( encoder.timeRight != 0 ) {
resAllFlags();
mode= 25; // переход на меню ПОЛЬЗ. УСТАНОВКИ
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
mode= 18; // переход на меню ЗАМЕНА СВЕРЛА
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 21 --------- ОСВЕЩЕНИЕ
else if(mode == 21) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ЯРКОСТЬ ОСВЕЩЕНИЯ
disp.clear();
disp.print("YRKOST_");
disp.setCursor(0, 1);
disp.print("OSVEZENYA ");
disp.print( (float)bright *100. / 255.,0);
disp.print(" %");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 24; // переход на установку яркости
}
if( encoder.timeRight != 0 ) {
resAllFlags();
mode= 22; // переход на меню ВЫХОД
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
mode= 25; // переход на меню ПОЛЬЗ. УСТАНОВКИ
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 22 --------- ВЫХОД
else if(mode == 22) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ВЫХОД
disp.clear();
disp.print("VYHOD");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 14; // переход на сверловку
}
if( encoder.timeRight != 0 ) {
resAllFlags();
mode= 18; // переход на меню ЗАМЕНА СВЕРЛА
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
mode= 21; // переход на меню ОСВЕЩЕНИЕ
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 23 --------- МАТЕРИАЛЫ
else if(mode == 23) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение МАТЕРИАЛ
disp.clear();
//disp.print( materialMenu[materialNumber].materialName );
textToDisp();
disp.setCursor(0, 1);
disp.print("D= ");
disp.print( (float)materialMenu[materialNumber].materialVelDrill *100. / 255.,0);
disp.print(" % S= ");
disp.print( materialMenu[materialNumber].materialSpindleVel );
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 20; // переход на ВЫБОР МАТЕРИАЛА
// запись materialNumber в EEPROM
byte _materialNumber;
if((readByteFromEeprom(EEPROM_MATERIAL_NUMBER, & _materialNumber) == false) || (materialNumber != _materialNumber)) {
writeByteToEeprom(EEPROM_MATERIAL_NUMBER, & materialNumber);
}
}
if( encoder.timeRight != 0 ) {
resAllFlags();
materialNumber++;
if(materialNumber >= 20) materialNumber= 0;
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
materialNumber--;
if(materialNumber == 255) materialNumber= 19;
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 24 --------- установка яркости
else if(mode == 24) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение ЯРКОСТЬ
disp.clear();
disp.print("YRKOST_");
disp.setCursor(0, 1);
disp.print( (float)bright *100. / 255.,1);
disp.print(" %");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 21; // переход на ОСВЕЩЕНИЕ
// запись materialNumber в EEPROM
if((readByteFromEeprom(EEPROM_BRIGHT, & x) == false) || (bright != x)) {
writeByteToEeprom(EEPROM_BRIGHT, & bright);
}
}
if( encoder.timeRight != 0 ) {
resAllFlags();
bright++;
if(bright == 0) bright= 255;
analogWrite(PIN_LIGHT, bright); // подсветка
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
bright--;
if(bright == 255) materialNumber= 0;
analogWrite(PIN_LIGHT, bright); // подсветка
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 25 --------- УСТАНОВКА ПОЛЬЗ. МАТЕРИАЛА
else if(mode == 25) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение УСТАНОВКА ПОЛЬЗ.
// МАТЕРИАЛА
disp.clear();
disp.print("USTANOVKA POL_Z.");
disp.setCursor(0, 1);
disp.print("MATERIALA");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 26; // переход на выбор скорости сверла
}
if( encoder.timeRight != 0 ) {
resAllFlags();
mode= 21; // переход на меню ОСВЕЩЕНИЕ
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
mode= 20; // переход на меню ВЫБОР МАТЕРИАЛА
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 26 --------- выбор скорости сверла
else if(mode == 26) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение СКОРОСТЬ СВЕРЛА
disp.clear();
disp.print("SKOROST_ SVERLA");
disp.setCursor(0, 1);
disp.print("D= ");
disp.print( (float) materialMenu[19].materialVelDrill * 100. / 255.,1);
disp.print(" %");
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 27; // переход на выбор скорости шпинделя
// запись materialNumber в EEPROM
if((readByteFromEeprom(EEPROM_USER_DRILL_VEL, & x) == false) || (materialMenu[19].materialVelDrill != x)) {
writeByteToEeprom(EEPROM_USER_DRILL_VEL, & materialMenu[19].materialVelDrill);
}
}
if( encoder.timeRight != 0 ) {
resAllFlags();
materialMenu[19].materialVelDrill++;
if(materialMenu[19].materialVelDrill == 0) materialMenu[19].materialVelDrill= 255;
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
materialMenu[19].materialVelDrill--;
if(materialMenu[19].materialVelDrill == 255) materialMenu[19].materialVelDrill= 0;
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
//-- 27 --------- выбор скорости шпинделя
else if(mode == 27) {
if(firstCycle == true) { // первый вход
firstCycle= false;
// сообщение СКОРОСТЬ ШПИНД.
disp.clear();
disp.print("SKOROST_ SPIND.");
disp.setCursor(0, 1);
disp.print("S= ");
disp.print( materialMenu[19].materialSpindleVel );
}
if(buttonEncoder.flagClick == true) {
resAllFlags();
mode= 25; // переход на УСТАНОВКА ПОЛЬЗ. МАТЕРИАЛА
// запись materialNumber в EEPROM
if((readByteFromEeprom(EEPROM_USER_SPINDLE_VEL, & x) == false) || (materialMenu[19].materialSpindleVel != x)) {
writeByteToEeprom(EEPROM_USER_SPINDLE_VEL, & materialMenu[19].materialSpindleVel);
}
}
if( encoder.timeRight != 0 ) {
resAllFlags();
materialMenu[19].materialSpindleVel++;
if(materialMenu[19].materialSpindleVel == 0) materialMenu[19].materialSpindleVel= 255;
}
if( encoder.timeLeft != 0 ) {
resAllFlags();
materialMenu[19].materialSpindleVel--;
if(materialMenu[19].materialSpindleVel == 255) materialMenu[19].materialSpindleVel= 0;
}
// управление двигателем сверла
if(timerPowerSave < TIME_POWER_OFF) { analogWrite(PIN_PWM_DRILL, MIN_VEL_DRILL); digitalWrite(PIN_DRILLER_ON, HIGH); }
else { analogWrite(PIN_PWM_DRILL, 0); digitalWrite(PIN_DRILLER_ON, LOW); }
}
else { while(true) {} }
}
//----------------------------------------------------------------------------------------
// обработчик прерывания 250 мкс
void timerInterrupt() {
wdt_reset();
encoder.scanState(); // сканирование энкодера
spindleMotor.control(); // управвление двигателем
sensSpindleUp.filterAvarage(); // сканирование датчика СУППОРТ ВВЕРХУ
buttonPedal.filterAvarage(); // сканирование кнопки ПЕДАЛЬ
buttonEncoder.filterAvarage(); // сканирование кнопки ЭНКОДЕР
timer1++;
// таймер режима энергосбережения
divTimerPS++;
if(divTimerPS >= 1000) { // 0,25 сек
divTimerPS= 0;
timerPowerSave++;
if(timerPowerSave == 0) timerPowerSave= 255;
}
}
//--------------------------------- сброс всех флагов
void resAllFlags() {
buttonPedal.flagClick= false;
buttonEncoder.flagClick= false;
encoder.timeRight= 0;
encoder.timeLeft= 0;
timerPowerSave= 0;
firstCycle=true;
}
// -------------------------------- запись данного типа long в EEPROM с контрольной суммой
void writeLongToEeprom(int adress, long *value) {
EEPROM.write(adress, *((byte*)value));
EEPROM.write(adress+1, *(((byte*)value)+1));
EEPROM.write(adress+2, *(((byte*)value)+2));
EEPROM.write(adress+3, *(((byte*)value)+3));
EEPROM.write(adress+4, (*((byte*)value) + *(((byte*)value)+1) + *(((byte*)value)+2) + *(((byte*)value)+3)) ^ 0xe5);
}
//------------------------------- чтение данного типа long из EEPROM с проверкой контрольной суммы
// при успешной операции возвращает true
boolean readLongFromEeprom(int adress, long *value) {
*((byte*)value) = EEPROM.read(adress);
*(((byte*)value)+1) = EEPROM.read(adress+1);
*(((byte*)value)+2) = EEPROM.read(adress+2);
*(((byte*)value)+3) = EEPROM.read(adress+3);
if ( (byte)((*((byte*)value) + *(((byte*)value)+1) + *(((byte*)value)+2) + *(((byte*)value)+3)) ^ 0xe5) == EEPROM.read(adress+4) ) return true;
return false;
}
// -------------------------------- запись данного типа byte в EEPROM с контрольной суммой
void writeByteToEeprom(int adress, byte *value) {
EEPROM.write(adress, *value);
EEPROM.write(adress + 1, (*value) ^ 0xe5 );
}
//------------------------------- чтение данного типа byte из EEPROM с проверкой контрольной суммы
// при успешной операции возвращает true
boolean readByteFromEeprom(int adress, byte *value) {
*value = EEPROM.read(adress);
if( ((*value) ^ 0xe5) == EEPROM.read(adress + 1)) return true;
return false;
}
//-------------------------------- установка положения шпиндлера энкодером
boolean ustSpindleEnc() {
long x;
// проверка энкодера
if(encoder.timeRight != 0) {
for(int i=0; i<14; i++) {
if(encoder.timeRight <= movEncoder[i].timeEncoder) {
spindleMotor.setDivider(movEncoder[i].dividerMoto); // скорость ШПИНДЕЛЯ
// ограничение снизу
x= posSpindle + movEncoder[i].stepsMoto;
if( x > MAX_SPINDLE ) {
spindleMotor.step( posSpindle - MAX_SPINDLE );
posSpindle= MAX_SPINDLE;
}
else {
spindleMotor.step(- movEncoder[i].stepsMoto);
posSpindle= x;
}
encoder.timeRight= 0;
encoder.timeLeft= 0;
return(true);
}
}
}
else if(encoder.timeLeft != 0) {
for(int i=0; i<14; i++) {
if(encoder.timeLeft <= movEncoder[i].timeEncoder) {
spindleMotor.setDivider(movEncoder[i].dividerMoto); // скорость ШПИНДЕЛЯ
// ограничение сверху
x= posSpindle - movEncoder[i].stepsMoto;
if( x < 0 ) {
spindleMotor.step(posSpindle);
posSpindle= 0;
}
else {
spindleMotor.step(movEncoder[i].stepsMoto);
posSpindle= x;
}
encoder.timeRight= 0;
encoder.timeLeft= 0;
return(true);
}
}
}
return(false);
}
//----------------------------------------- вывод данных для дурацких индикаторов
void textToDisp() {
switch(materialNumber) {
case 0:
disp.print("1 tekstolit"); break;
case 1:
disp.print("2 tekstolit"); break;
case 2:
disp.print("3 tekstolit"); break;
case 3:
disp.print("4 tekstolit"); break;
case 4:
disp.print("5 tekstolit"); break;
case 5:
disp.print("6 tekstolit"); break;
case 6:
disp.print("7 tekstolit"); break;
case 7:
disp.print("8 tekstolit"); break;
case 8:
disp.print("9 tekstolit"); break;
case 9:
disp.print("10 tekstolit"); break;
case 10:
disp.print("11 tekstolit"); break;
case 11:
disp.print("12 tekstolit"); break;
case 12:
disp.print("13 tekstolit"); break;
case 13:
disp.print("14 tekstolit"); break;
case 14:
disp.print("15 tekstolit"); break;
case 15:
disp.print("16 tekstolit"); break;
case 16:
disp.print("17 tekstolit"); break;
case 17:
disp.print("18 tekstolit"); break;
case 18:
disp.print("19 tekstolit"); break;
case 19:
disp.print("pol_zovatel_skiy"); break;
}
}
Re: Использование энкодера в качестве нелинейного регулятора.
Спасибо огромное!
Разбираюсь, много интересного и нового...
Разбираюсь, много интересного и нового...
Re: Использование энкодера в качестве нелинейного регулятора.
Здравствуйте!
Если человек, который заказал мне программу доделает сверлильный станок и вышлет мне фотографии, то я отдельной темой опишу устройство, схему, алгоритм работы. Сейчас он ждет двигатель с Алиэкспресс. Заказал двигатель, ему через 2 месяца вернули деньги. Опять ждет новый двигатель.
Если человек, который заказал мне программу доделает сверлильный станок и вышлет мне фотографии, то я отдельной темой опишу устройство, схему, алгоритм работы. Сейчас он ждет двигатель с Алиэкспресс. Заказал двигатель, ему через 2 месяца вернули деньги. Опять ждет новый двигатель.
Re: Использование энкодера в качестве нелинейного регулятора.
Добрый день!
Очень интересно было бы посмотреть!
Если у нас все получиться, выложу наше "ноу хау"
Очень интересно было бы посмотреть!
Если у нас все получиться, выложу наше "ноу хау"
Re: Использование энкодера в качестве нелинейного регулятора.
Доброго времени суток.
Получилось реализовать станок ? Было бы очень интересно разобрать как это получилось, прям добавить серию уроков.
Получилось реализовать станок ? Было бы очень интересно разобрать как это получилось, прям добавить серию уроков.
Re: Использование энкодера в качестве нелинейного регулятора.
Здравствуйте!
Вроде двигатель с АлиЭкспресс ему пришел, но пока молчит.
Программу в принципе он полностью проверил. У него не было только двигателя сверловки.
Вроде двигатель с АлиЭкспресс ему пришел, но пока молчит.
Программу в принципе он полностью проверил. У него не было только двигателя сверловки.
Вернуться в «Программирование Ардуино»
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей