2 шаговых двигателя и зависания.

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Добрый день.
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
Может вообще все переменные сделать volatile?
C++:
volatile long MoveStCurrentPosition = 0;
volatile long MoveStTarget = 0;
 
Изменено:

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
volatile должны быть те переменные, которые меняются в прерывании, и которые используются вне прерывания.
понял. сделал все что в прерывании есть.
я так понимаю что если не биться за оптимизацию памяти, то от volatile хуже не будет?
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
Хуже чем что? Чем не работает правильно?
Доступ к памяти будет организован иначе
Так виснет контроллер, иногда один из моторов виснет иногда перезапускается.
Если объявлять volatile Только то что изменяется в прерывании и участвует в основном теле программы надо сделать так:
C++:
bool s1 = 0;
bool s2 = 0;
volatile unsigned long Steps = 0; //шаги основного привода
volatile long MoveStCurrentPosition = 0;
volatile long MoveStTarget = 0;
так как s1 и s2 не участвуют во внешней программе, а живут только в прерываниях
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
Виснуть контроллер может и по другим причинам.
Если работает 1 из моторов тоже виснет ?
моторы работают всегда в паре.
но зависнуть может и один (например укладчика) а мотающий продолжит поддерживать скорость накручивая на катушки витки в одном и том же месте, где встал укладчик. Чаще бывает или полное зависание или перезагрузка МК.
 

Boroda22

★✩✩✩✩✩✩
23 Фев 2022
251
42
избежать утечек памяти — никогда не выделять ничего динамически.
Нет, нужно просто понимать что делаешь, понимать что такое время жизни объекта, знать для чего нужен деструктор.
У меня все переменные заданы статически...
Это как? являются экземплярами класса ?

Освежил в памяти по поводу volatile, так это походу то же самое, что изменять переменную по ссылке, а не по значению, ну и оптимизация "умного" компилятора. Скорее всего проблема в архитектуре кода, отсюда зависания и непредсказуемое поведение. Упростите код в главном цикле, тогда и ошибку будет проще найти.
 

poty

★★★★★★✩
19 Фев 2020
3,261
948
Если запись в переменную происходит не за один цикл (все переменные больше int в данном случае) вне обработчика прерывания, то есть прямой смысл запрещать на это время прерывания.
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
Если запись в переменную происходит не за один цикл (все переменные больше int в данном случае) вне обработчика прерывания, то есть прямой смысл запрещать на это время прерывания.
Большую часть loop спрятал от прерываний
C++:
void loop() {
bus.poll(modbus_array, 2);    //Принимаем данные о номере катушки и рарешении на работу по Modbus

noInterrupts();
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 ((millis() - MainStSpeedUpdateTimer > PIDInterval) && (AvgAnalogRead > 160) ) { //    отправка скорости на мотор
                                            MainStSpeedUpdateTimer = millis();
                                            Input = AvgAnalogRead; //ПИД вход с датчика
                                            Speed = int(Output); //ПИД результат
                                            Timer1.setFrequency(Speed); //обновляем скорость
                                            }

if ((AvgAnalogRead > 160) && (modbus_array[0]) && (!NowGoingHome)) { //включена работа
                            if (!OutOfRoll) { //таскаем туда сюда, если не переход на след катушку
                                LeftSide = int((RollNum-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft); // вычисляем и меняем тип данных на целый
                                RightSide  = int(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); } //После первых пяти слое намотки уменьшаем KP ПИД для более плавной работы
                                                                }
                          }else {Timer1.pause();}

if (millis() - AnalogReadTimer > 50)   { //    контролируем скорость с датчика угла провисания                     
                                        AnalogReadTimer = millis();
                                        AvgAnalogRead = 0.8*AvgAnalogRead + 0.2*analogRead(AnalogSignal); //бегущее среднее для датчика
                                        }

    
if ((modbus_array[1] != RollNum)&&(modbus_array[1]<11)) { // поступил сигнал "следующая катушка"
                                RollNum=modbus_array[1];
                                OutOfRoll=1; //вне катушки, нужно быстренько ехать к новой
                                Timer2.setFrequency(4000); // увеличиваем скорость укладчика
                                MoveStTarget = ((RollNum-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft + StepsForMM*FilamentWidth); //едь сюда к левой стенке следующей катушки
                                                          
                                }
interrupts();

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 (modbus_array[0]==0) {Timer1.pause();} // Разрешение на работу от мастера

if(millis() - LEDTimer > 500) {   //мигаем
                              noInterrupts();
                              LEDTimer = millis();
                              ledState = !ledState;
                              digitalWrite(ledRXTXPin, ledState);
                              interrupts();
                              }
}
 

poty

★★★★★★✩
19 Фев 2020
3,261
948
Эмммм... Прерывания нужно запрещать на минимальный интервал, выполняющий свою задачу, иначе можно сделать только хуже. То есть для тех переменных, которые "считываются" в прерывании и больше int, это нужно делать перед присвоением им значения. Все остальные вычисления делать с включенными прерываниями. Поясняю: у Вас куча вычислений с плавающей точкой, занимающих довольно значительное время. Я предпочитаю в микроконтроллерах в принципе уходить от плавающей точки и чисел long, их использование часто вызвано неоправданными ожиданиями к точности. Но если уж используете, то явно не в режиме с выключенными прерываниями. На практике интервал вычислений может легко превысить пару периодов прерываний и, значит, будет потеря одного или нескольких прерываний (флаг каждого конкретного прерывания один).
 
  • Лойс +1
Реакции: Старик Похабыч

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
Эмммм... Прерывания нужно запрещать на минимальный интервал, выполняющий свою задачу, иначе можно сделать только хуже. То есть для тех переменных, которые "считываются" в прерывании и больше int, это нужно делать перед присвоением им значения. Все остальные вычисления делать с включенными прерываниями. Поясняю: у Вас куча вычислений с плавающей точкой, занимающих довольно значительное время. Я предпочитаю в микроконтроллерах в принципе уходить от плавающей точки и чисел long, их использование часто вызвано неоправданными ожиданиями к точности. Но если уж используете, то явно не в режиме с выключенными прерываниями. На практике интервал вычислений может легко превысить пару периодов прерываний и, значит, будет потеря одного или нескольких прерываний (флаг каждого конкретного прерывания один).
Спасибо. Я вас понял. Отсутствие пропуска шагов на основном двигателе на максимальной скорости можно считать, что часть без прерываний успевает отработать?
Иначе только изменяемые в прерывании переменные комментировать
C++:
noInterrupts();
interrupts();
 

poty

★★★★★★✩
19 Фев 2020
3,261
948
С практической точки зрения - Ваша мысль правильная. Однако никогда не стоит недооценивать случайностей.
Собственно, мои слова были сказаны для возможных вариантов избавления от зависаний. Я бы ещё посмотрел на качество питания и защиту от помех и просадок.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
По поводу расчетов. К примеру на 124 тика одним мотором надо сделать 23 тика другим мотором. 124/23 , т.е. каждые 5,39 тиков. Если округлить, то получится 5, итого 24.8, тика, или 24 , если опять же округлять. Поэтому тут кажется логичным сделать переменные типа float. Но если увеличить число тиков в 10 раз , т.е. на 1240 тиков сделать 230, но мотором дергать только каждый 10-ый тик , то будет те же 5.39, но учитывая 10-ку дергать вторым мотором надо будет каждый 53-ий тик.1240/53=23,4 , что гораздо ближе к нужном. Соотв. если сделать эти расчеты до начала намотки, то дальнейшая обработка сведется к минимуму:в нужный момент поднять пин, в следующий опустить, единственное, что опускание время до смены пина с высокого на низкий уровень должно быть такое, что бы драйвер отработал.
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
С практической точки зрения - Ваша мысль правильная. Однако никогда не стоит недооценивать случайностей.
Собственно, мои слова были сказаны для возможных вариантов избавления от зависаний. Я бы ещё посмотрел на качество питания и защиту от помех и просадок.
Спасибо.
Убрал float где можно, перенес функцию расчета координат катушек в setup чтобы выполнить раз и забить в массив.
Питание 5 в от блок, на нем работают 3 контроллера - выделывается только этот.
Керамические конденсаторы распаяны, ферритовые кольца на всех проводах питания и датчиков.

C++:
long LeftSide[11];
long RightSide[11];

void setup() {
    for (int i=1; i <= 10; i++){ //расчитываем параметры катушек
     LeftSide[i] = ((i-1)*StepsForMM*(RollWidth+RollSide) + StepsForMM*ShiftWidthLeft);
     RightSide[i]  = LeftSide[i]+StepsForMM*RollWidth;
     Serial.print("i: "); Serial.print(i); Serial.print(" ");
     Serial.print(LeftSide[i]); Serial.print("<< >>"); Serial.println(RightSide[i]);
   }
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
По поводу расчетов. К примеру на 124 тика одним мотором надо сделать 23 тика другим мотором. 124/23 , т.е. каждые 5,39 тиков. Если округлить, то получится 5, итого 24.8, тика, или 24 , если опять же округлять. Поэтому тут кажется логичным сделать переменные типа float. Но если увеличить число тиков в 10 раз , т.е. на 1240 тиков сделать 230, но мотором дергать только каждый 10-ый тик , то будет те же 5.39, но учитывая 10-ку дергать вторым мотором надо будет каждый 53-ий тик.1240/53=23,4 , что гораздо ближе к нужном. Соотв. если сделать эти расчеты до начала намотки, то дальнейшая обработка сведется к минимуму:в нужный момент поднять пин, в следующий опустить, единственное, что опускание время до смены пина с высокого на низкий уровень должно быть такое, что бы драйвер отработал.

Я правильно вас понял, что вы хотите подпихнуть двигатель укладчика к основному, и вызывать его с некоторой пропорциональностью от первого?
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
Да, а разве это не так работает ? я пор пропорцию
В базовой части намотки именно так. Большой крутит, маленький смещает на виток туда сюда от края до края.
Но катушек на одной оси несколько, при заполнении одной, укладчик включает макс скорость и бежит в сторону следующей катушки.
В этот момент ему нужна частота
Timer2.setFrequency(4000); Гц
А большой двигатель так и продолжает поддерживать скорость чтобы не было провисания.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
В любом случае есть этапы работы.
1) Намотка
2) Смещение
и т.д.
Как работает 3д принтер ? он же не перегоняет 3д модель в пластик сразу, а делает для модели G-код, который уже говорит что делать принтеру. Значит и для намотки можно сделать предварительный расчет тиков, даже подобрать пропорцию приличнее и т.д. Ну лично я бы так делал.
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
98
Master считает метраж,
Но ведь основной параметр любой катушки это витки,а не метраж. Хотя это не совсем к делу относится. Но всё же.
Хотабыч правильно пишет,про увод расчитываемых чисел в целочисленные значения путём их умножения перед вычислениями.
Хотелось бы конкретней узнать:
1)Сколько шагов мотора на оборот катушки?
2) сколько шагов на мм направляющей механики?
3) какие катушки мотаются в основном? Диаметр провода,кол-во витков.Кол-во слоёв.
4) минимальная и желаемая скорость намотки
Это чтобы ясней представлять требования к вычислительным мощностям.