Добрый день.
UNO управляет процессом намотки на катушки: основной шаговый мотор крутит бобину не допуская провисания провода,
а второй перемещает укладчик витков.
При наполнении катушки - укладчик смещается на следующую катушку.
Оба мотора работают в прерываниях разных таймеров для обеспечения разных скоростей и отсутствия лагов от обмена Modbus.
Пробовал без таймера основной мотор "спотыкается" во время обмена данными Modbus.
Проблема в том, что регулярно система виснет: то один мотор остановится, то второй, то оба, может и loop зависнуть перестав мигать светодиодом на ровном месте в абсолютно случайное время.
Пожалуйста, накиньте направление куда двигаться?
Две переменных из второго прерывания объявил как volatile
Может вообще все переменные сделать volatile?
UNO управляет процессом намотки на катушки: основной шаговый мотор крутит бобину не допуская провисания провода,
а второй перемещает укладчик витков.
При наполнении катушки - укладчик смещается на следующую катушку.
Оба мотора работают в прерываниях разных таймеров для обеспечения разных скоростей и отсутствия лагов от обмена Modbus.
Пробовал без таймера основной мотор "спотыкается" во время обмена данными Modbus.
Проблема в том, что регулярно система виснет: то один мотор остановится, то второй, то оба, может и loop зависнуть перестав мигать светодиодом на ровном месте в абсолютно случайное время.
Пожалуйста, накиньте направление куда двигаться?
C++:
#define MainStEnb 10 //Основной ШД
#define MainStDir 9
#define MainStStep 8
#define MoveStEnb 13 //Укладчик ШД
#define MoveStDir 12
#define MoveStStep 11
#define ledPin 3
#define ledRXTXPin 2
#define AnalogSignal A1// датчик провисания(угол)
#define ButtonPin A0 //кнопка "Домой"
#define LeftStop A2 // концевой выключатель для калибровки ноля
#include <ModbusRtu.h>
#include <PID_v1.h>
#include <GyverTimers.h>
const int KP = 26; // коэффициент пропорциональности ПИД, иногда меняется от глубины намотки текущей катушки
double Setpoint, Input, Output;
PID regulator(&Input, &Output, &Setpoint, KP, 1, 0, REVERSE);
const float StepsForMM = 200.0, RollWidth = 50.1; // ширина наматываемой части
const float ShiftWidthLeft = 1.2; //отступ слева от концевого выключателя
const float RollSide = 12.7; //суммарная толщина бортиков катушек
const float PeredatochnoeChislo = 3.103 ; //передаточное число между шестернями привода
const float FilamentWidth = RollWidth/24 ; // ширина занимаемая одним витком
const unsigned int MainSpeedMax = 4000; // макс скорость
const unsigned int MainSpeedMin = 0; //минимальная скокрость работы - 0 - стоп
const int PIDInterval = 100; //интервал обработки датчика провисания в мс
volatile bool s1 = 0;
volatile bool s2 = 0;
volatile unsigned long Steps = 0; //шаги онсновного привода
const int AngleConst = 245; //угол в аналогрид(0-1023) нечто среднее между 210(верх) и 300 (нижнее положение ролика)
byte RollNum = 1; //номер катушки
unsigned int Speed=0;
unsigned int MoveStSpeed = 2000; //скорость частота вращения мотора укладчика
unsigned int Spins = 0; //обороты
long Target = 0;//цель в шагах ползуна
long MoveStCurrentPosition = 0; //текущая координата
long MoveStTarget = 0; // цель для ползуна
bool Direction = 1; // направление хода укладчика один это двигаться направо
bool NowGoingHome = 0; //сейчас еду домой
byte OutOfRoll = 0; // укладчик находится вне диапазона намотки, нужно для увеличения скокрости укладчика относительно намотки
byte LeftStopLock = 0; //доехали до левого концевика
byte NextRollButt = 0; //защелка от повторного нажатия
long AnalogReadTimer, MainStSpeedUpdateTimer=0; //таймер
long ReverseSwitchTimer=0; //таймер сработки выключателя назад
byte ReverseSwitch =0; // состояние выключателя домой
int AvgSpeed = 0; //средние скокрост
int AvgAnalogRead = 0; //средние значения с датчика
int DirectionCh =0; // колво смен аправл
bool ledState = 0;
unsigned long LEDTimer, LEDRxTxTimer = 0;
unsigned int modbus_array[2] = {0, 1}; //Готовим массив данных "разрешно работать 0/1" и "номер катушки"
Modbus bus(4, Serial, 4); // this is slave 4, Serial 0, and RS-485 (4 pin for enable)
void setup() {
pinMode(MainStEnb, OUTPUT); // Инициализация осноного мотора
pinMode(MainStDir, OUTPUT);
pinMode(MainStStep, OUTPUT);
pinMode(MoveStEnb, OUTPUT); // Инициализация мотора укладчика
pinMode(MoveStDir, OUTPUT);
pinMode(MoveStStep, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(ledRXTXPin, OUTPUT);
pinMode(LeftStop, INPUT); //концевик слева
digitalWrite(LeftStop, HIGH);
pinMode(ButtonPin, INPUT); //кнопка Домой
digitalWrite(ButtonPin, HIGH);
Timer1.setFrequency(Speed); //частота таймера
Timer1.enableISR(CHANNEL_B); // Подключить прерывание таймера 1, канал B
Timer2.setFrequency(MoveStSpeed); //частота таймера
Timer2.enableISR(CHANNEL_B); // Подключить прерывание таймера 2, канал B
//при генерации меандра реальная частота будет в два раза меньше заданной из-за особенности работы самого таймера.
// Инициализация и параметры ПИД
Setpoint = AngleConst;
regulator.SetMode(AUTOMATIC);
regulator.SetOutputLimits(MainSpeedMin, MainSpeedMax);
regulator.SetSampleTime(PIDInterval);
Serial.begin(19200);
bus.start();
Serial.println("Start");
}
ISR(TIMER1_B) { //прерывание по таймеру для осн двигателя
s1 = not(s1);
digitalWrite(MainStStep, s1);
Steps++;
}
ISR(TIMER2_B) { //прерывание по таймеру для двигателя укладчика
if (MoveStCurrentPosition<MoveStTarget) {digitalWrite(MoveStDir, 0); MoveStCurrentPosition++;}
if (MoveStCurrentPosition>MoveStTarget) {digitalWrite(MoveStDir, 1); MoveStCurrentPosition--;}
if (MoveStCurrentPosition!=MoveStTarget) {
s2 = not(s2);
digitalWrite(MoveStStep, s2);
}
}
void loop() {
bus.poll(modbus_array, 2); //Принимаем данные о номере катушки и рарешении на работу по Modbus
regulator.Compute(); // Вычисляем ПИД
if (OutOfRoll && (abs(MoveStCurrentPosition - (RollNum-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft)<10) ) { // достгли левого края новой катушки
Target = (RollNum-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft+ StepsForMM*FilamentWidth;
OutOfRoll=0;
Direction = 1; //направо
DirectionCh = 0;
regulator.SetTunings(KP, 1, 0);
Serial.println("I am in roll!");
Timer2.setFrequency(600);
}
if (!digitalRead(ButtonPin)){ //нажали кнопку Домой
delay(50);
if (!digitalRead(ButtonPin)) {
MoveStTarget = MoveStCurrentPosition; //остановка
Timer2.setFrequency(4000);
MoveStTarget = -1000000;
Serial.println("Go home");
NowGoingHome = 1;
}
}
if(!digitalRead(LeftStop) && (NowGoingHome)) { // сработал левый концевик
NowGoingHome = 0;
Serial.println("Iam home, go to start point");
MoveStCurrentPosition = 0;
MoveStTarget = StepsForMM*ShiftWidthLeft; // После калибровки отправляем ползун чуть правее в начало первой катушки
RollNum=1; Direction = 1; OutOfRoll=0;
DirectionCh = 0;
regulator.SetTunings(KP, 1, 0);
Timer2.setFrequency(600);
}
if (millis() - AnalogReadTimer > 50) { // контролируем скорость с датчика угла провисания
AnalogReadTimer = millis();
AvgAnalogRead = 0.8*AvgAnalogRead + 0.2*analogRead(AnalogSignal); //бегущее среднее для датчика
}
if ((millis() - MainStSpeedUpdateTimer > PIDInterval) && (AvgAnalogRead > 160) ) { // отправка скорости на мотор
MainStSpeedUpdateTimer = millis();
Input = AvgAnalogRead; //ПИД вход с датчика
Speed = int(Output); //ПИД результат
Timer1.setFrequency(Speed); //обновляем скорость
}
if (modbus_array[0]==0) {Timer1.pause();} // Разрешение на работу от мастера
if ((AvgAnalogRead > 160) && (modbus_array[0]) && (!NowGoingHome)) { //включена работа
if (!OutOfRoll) { //таскаем туда сюда, если не переход на след катушку
long LeftSide = (RollNum-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft; // вычисляем и меняем тип данных на целый
long RightSide = LeftSide+StepsForMM*RollWidth; // вычисляем и меняем тип данных на целый
if (int(Steps/1600/PeredatochnoeChislo)>Spins) { // каждый оборот сдвинуться на FilamentWidth
Spins = int(Steps/1600/PeredatochnoeChislo);
if (Direction) {Target = Target + StepsForMM*FilamentWidth;} else
{Target = Target - StepsForMM*FilamentWidth;}
if (Target < LeftSide) {
Target = Target + 2*StepsForMM*FilamentWidth;
Direction = !Direction; //меняем напрвление
DirectionCh++;
}
if (Target > RightSide) {
Target = Target - 2*StepsForMM*FilamentWidth;
Direction = !Direction; //меняем напрвление
DirectionCh++;
}
MoveStTarget = Target;
}
if (DirectionCh>5) {regulator.SetTunings(5, 1, 0); Serial.print("Kp: 5");} //После первых пяти слое намотки уменьшаем KP ПИД для более плавной работы
}
}else {Timer1.pause();}
if (modbus_array[1] != RollNum) { // поступил сигнал "следующая катушка"
RollNum=modbus_array[1];
OutOfRoll=1; //вне катушки, нужно быстренько ехать к новой
Timer2.setFrequency(4000); // увеличиваем скорость ползуна
MoveStTarget = ((RollNum-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft + StepsForMM*FilamentWidth); //едь сюда к левой стенке следующей катушки
Serial.print("Roll ");
Serial.println(RollNum);
}
if(millis() - LEDTimer > 500) { //мигаем
LEDTimer = millis();
ledState = !ledState;
digitalWrite(ledRXTXPin, ledState);
}
}
Может вообще все переменные сделать volatile?
C++:
volatile long MoveStCurrentPosition = 0;
volatile long MoveStTarget = 0;
Изменено: