Линейная интерполяция
- Войдите на сайт для отправки комментариев
Пнд, 18/01/2016 - 14:52
Доброго времени суток.
Прошу помочь в решении проблемы. У меня система из 2-х шаговых двигателей(ШД) и CNC Shield c драйверами. Смог сделать так. В COM-порт посылаю номер мотора и количество шагов. Он откручивает. Теперь надо сделать линейную интерполяцию (типа движение по диагонали). Т.о. работают два мотора одновременно. подскажите как сделать!
P.S. Видел в интернете hex файлы для прошивки 3 осей и одного лазера, которые работают с G - кодами для ЧПУ, но это не подходит.
надо сделать линейную интерполяцию (типа движение по диагонали).
Т.о. работают два мотора одновременно. подскажите как сделать!
Да. Правильно. По прямой. Один проезжает по X сколько-то шагов, другой по Y. При этом поподая в нужную точку. По теореме Пифагора? Это каким образом?
Да. Правильно. По прямой. Один проезжает по X сколько-то шагов, другой по Y. При этом поподая в нужную точку. По теореме Пифагора? Это каким образом?
Ну, Вы объясните что нужно. Про Пифагора я имел в виду, если Вы знаете две стороны треугольника, а надо посчитать третью. Но, теперь, мне кажется. что Вам нужно не это. А что - я никак не пойму. Ну, поехали по одной оси 5 см., а по друго 8, а что Вам надо-то? У Вас проблема с одновременностью работы моторов или с чем?
Мне нужно, чтобы работал 2 ШД работали, которые двигают платформу, как в ЧПУ станке т.е. дновременно ехали. Один столько, другой столько и попадали в нужную мне точку. Я пишу в COM порт этим движкам координаты в шагах. И они одновременн едут, продвигая мою подвижку по платформу. http://upload.akusherstvo.ru/image925489.jpg
Ну, Вы говорите, что по одной оси они у Вас ездят. Так? По любой ездят? И по и X и по Y - но тольео не одновременно. Правильно я понял? Так может хоть код покажете. как оно сейчас сделано?
Сейчас так: я в COM порт посылаю номер мотора и количество шагов и он делает. Потом выбираю другой и делаю тоже самое. А мне нужно, то , что я описал выше. Как я понял, интерполяция делается в ЧПУ станках так. Ты задал конечную точку, а он движет то одним мотором, то другим поочередно, сответственн приходя в нужную нам точку. http://postprocessor.su/linear_moves.html
Я Вам писал
может хоть код покажете, как оно сейчас сделано?
Вы же вместо кода
Сейчас так: я в COM порт посылаю номер мотора и количество шагов и он делает. Потом выбираю другой и делаю тоже самое.
Вы издеваетесь? Не хотите показывать код (боитесь, что я украду) - дело хозяйское, только тогда и разбирайтесь сами.
/* массивы перемен */ int motorNumb; // номер мотора char CurChar; // текущий символ для установки флага мотора или шага char Com_Step = 0; // флаг установки шага char Com_Motor = 0; // флаг выбора мотора int dirPin1 = 5; // pin для направления int dirPin2 = 6; int stepPin1 = 2; // pin для шагов int stepPin2 = 3; int openmotorPin = 8; // pin для запуска мотора int val_btn1=0; // значение кнопки int val_btn2=0; int btnPin1 = 15; // pin для кнопки int btnPin2 = 14; int speedmotor = 2000; // задаем скорость мотора int stepsvar = 0; // значение шагов, которое задаем мотору int flag_zero=1; //флаг установки нулей int flag1_motor=1; int flag2_motor=1; /* Функция установки pin и открытия com-порт */ void setup() { // задаем, что этот pin на выход pinMode(dirPin1, OUTPUT); pinMode(dirPin2, OUTPUT); pinMode(stepPin1, OUTPUT); pinMode(stepPin2, OUTPUT); pinMode(openmotorPin, OUTPUT); pinMode(btnPin1,INPUT_PULLUP); pinMode(btnPin2,INPUT_PULLUP); // открываем com-порт со скоростью передачи 9600 Serial.begin(9600); } /* функция, отвечающая за вращение мотора №1 */ void step1(boolean dir,int steps) { digitalWrite(dirPin1,dir); for(int i=0;i<steps;i++) { // если на pin кнопки что-то пришло, то выходим из цикла принудительно val_btn1= digitalRead(btnPin1); if(val_btn1==LOW) {digitalWrite(stepPin1, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin1, LOW); delayMicroseconds(speedmotor); flag1_motor=1;} if((val_btn1==HIGH)&&(flag1_motor==1)) {flag1_motor=0; break; } if((val_btn1==HIGH)&&(flag1_motor==0)) {digitalWrite(stepPin1, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin1, LOW); delayMicroseconds(speedmotor);} } } /* функция, отвечающая за вращение мотора №2 */ void step2(boolean dir,int steps) { digitalWrite(dirPin2,dir); for(int i=0;i<steps;i++) { val_btn2= digitalRead(btnPin2); if(val_btn2==LOW) {digitalWrite(stepPin2, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin2, LOW); delayMicroseconds(speedmotor); flag2_motor=1;} if((val_btn2==HIGH)&&(flag2_motor==1)) {flag2_motor=0; break; } if((val_btn2==HIGH)&&(flag2_motor==0)) {digitalWrite(stepPin2, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin2, LOW); delayMicroseconds(speedmotor);} } } /*При введение символа 'M' или 'S' устанавливается флаг мотора или флаг шага*/ if ((Serial.available() > 0)&&(Com_Step == 0)&& (Com_Motor == 0)) { //читаем байт из порта CurChar = Serial.read(); //если это символ S то устанавливаем флаг начала установки шага if (CurChar == 'S') { Com_Step = 1; Serial.println("Select Steps"); } else { //если это символ M то устанавливаем флаг выбора мотора if (CurChar == 'M') { Com_Motor = 1; Serial.println("Selection motor"); } } } /* Устанавливаем какой мотор будет работать */ //если в порту есть хоть один символ и установлен флаг выбора мотора if ((Serial.available() > 0)&&(Com_Motor == 1)) { // сбрасываем флаг Com_Motor = 0; Serial.print("Motor: "); motorNumb = Serial.parseInt(); Serial.println(motorNumb); } /* Устанавливаем сколько шагов должен сделать мотор */ //если в порту есть хоть один символ и установлен флаг установки шага// if ((Serial.available() > 0)&&(Com_Step == 1)) { // сбрасываем флаг установки шага Com_Step = 0; Serial.print("Steps: "); stepsvar=Serial.parseInt(); Serial.println(stepsvar); //в зависимости от того какой номер мотора //назначен выполняется определенный case switch (motorNumb) { case 1: if (stepsvar > 0) { step1(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step1(false,stepsvar); } break; case 2: if (stepsvar > 0) { step2(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step2(false,stepsvar); } break; } } }Да нет я его искал. Вот сейчас и кидаю. Слишком много скетчей у меня.
А где функция loop()? Давайте-ка работающий скетч, прямо копи-пастом из IDE.
/* массивы перемен */ int motorNumb; // номер мотора char CurChar; // текущий символ для установки флага мотора или шага char Com_Step = 0; // флаг установки шага char Com_Motor = 0; // флаг выбора мотора int dirPin1 = 5; // pin для направления int dirPin2 = 6; int stepPin1 = 2; // pin для шагов int stepPin2 = 3; int openmotorPin = 8; // pin для запуска мотора int val_btn1=0; // значение кнопки int val_btn2=0; int btnPin1 = 15; // pin для кнопки int btnPin2 = 14; int speedmotor = 2000; // задаем скорость мотора int stepsvar = 0; // значение шагов, которое задаем мотору int flag_zero=1; //флаг установки нулей int flag1_motor=1; int flag2_motor=1; /* Функция установки pin и открытия com-порт */ void setup() { // задаем, что этот pin на выход pinMode(dirPin1, OUTPUT); pinMode(dirPin2, OUTPUT); pinMode(stepPin1, OUTPUT); pinMode(stepPin2, OUTPUT); pinMode(openmotorPin, OUTPUT); pinMode(btnPin1,INPUT_PULLUP); pinMode(btnPin2,INPUT_PULLUP); // открываем com-порт со скоростью передачи 9600 Serial.begin(9600); } /* функция, отвечающая за вращение мотора №1 */ void step1(boolean dir,int steps) { digitalWrite(dirPin1,dir); for(int i=0;i<steps;i++) { // если на pin кнопки что-то пришло, то выходим из цикла принудительно val_btn1= digitalRead(btnPin1); if(val_btn1==LOW) {digitalWrite(stepPin1, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin1, LOW); delayMicroseconds(speedmotor); flag1_motor=1;} if((val_btn1==HIGH)&&(flag1_motor==1)) {flag1_motor=0; break; } if((val_btn1==HIGH)&&(flag1_motor==0)) {digitalWrite(stepPin1, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin1, LOW); delayMicroseconds(speedmotor);} } } /* функция, отвечающая за вращение мотора №2 */ void step2(boolean dir,int steps) { digitalWrite(dirPin2,dir); for(int i=0;i<steps;i++) { val_btn2= digitalRead(btnPin2); if(val_btn2==LOW) {digitalWrite(stepPin2, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin2, LOW); delayMicroseconds(speedmotor); flag2_motor=1;} if((val_btn2==HIGH)&&(flag2_motor==1)) flag2_motor=0; break; } if((val_btn2==HIGH)&&(flag2_motor==0)) {digitalWrite(stepPin2, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin2, LOW); delayMicroseconds(speedmotor);} } } /* Функция работает по кругу(зациклена) */ void loop () { /*При введение символа 'M' или 'S' устанавливается флаг мотора или флаг шага*/ if ((Serial.available() > 0)&&(Com_Step == 0)&& (Com_Motor == 0)) { //читаем байт из порта CurChar = Serial.read(); //если это символ S то устанавливаем флаг начала установки шага if (CurChar == 'S') { Com_Step = 1; Serial.println("Select Steps"); } else { //если это символ M то устанавливаем флаг выбора мотора if (CurChar == 'M') { Com_Motor = 1; Serial.println("Selection motor"); } } } /* Устанавливаем какой мотор будет работать */ //если в порту есть хоть один символ и установлен флаг выбора мотора if ((Serial.available() > 0)&&(Com_Motor == 1)) { // сбрасываем флаг Com_Motor = 0; Serial.print("Motor: "); motorNumb = Serial.parseInt(); Serial.println(motorNumb); } /* Устанавливаем сколько шагов должен сделать мотор */ //если в порту есть хоть один символ и установлен флаг установки шага// if ((Serial.available() > 0)&&(Com_Step == 1)) { // сбрасываем флаг установки шага Com_Step = 0; Serial.print("Steps: "); stepsvar=Serial.parseInt(); Serial.println(stepsvar); //в зависимости от того какой номер мотора //назначен выполняется определенный case switch (motorNumb) { case 1: if (stepsvar > 0) { step1(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step1(false,stepsvar); } break; case 2: if (stepsvar > 0) { step2(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step2(false,stepsvar); } break; } }Ну, понятно.
У Вас структура программы заточена по то, что пока мотор не отработает нужные шаги, программа не воспринимает никаких других команд. Чтобы иметь возможность гонять их параллельно, надо менять структуру программы - т.е. переписывать её.
Вы готовы на это? В принципе Вы ничего не выиграете - конечная скорость прибытия в нужную точку будет такой же. Просто ехать будет "вправо-вверх" как сейчас, а по диалоналям.
Если готовы, могу дать некую отправную точку, как переписать. Где-то через час-другой освобожусь и могу показать.
Только, по мне, так смысла в этом не вижу.
Я был бы рад, если бы помогли! Я тоже так думаю, но мне это нужно под проект, поэтому, если подскажите - будет здорово!
Ну, вот попробуйте вот такой скетч.
Сразу должен сказать:
1. я пока не понял что Вы хотели сделать с кнопками - у меня никаких кнопок нет, если надо - добавим, но мне надо понимать что они делают.
2. Команды я подавал из монитора порта не по одному числу, а сразу командой. Формат команд:
N S <символ новой строки>
где
N - номер мотора (1 или 2). Если 0 - то команда относится к обоим моторам сразу.
S - количество шагов. Если положительное, то (как было у Вас dir будет HIGH, иначе - LOW. Если S равно нулю, то команда немедленно останавливает мотор.
Значит так, по мере поступления команды мотор(ы) начинают движение. Если во время движения поступает новая команда - мотор забывает старую и выполняет указанное количество шагов из той точки в которой в данный момент находится. В случае если поступила команда на 0 шагов - мотор останавливается немедленно.
Я не испытывал на моторах - у меня их нет, я просто наблюдал за выводом в сериал. Управление моторами мне испытать не на чем. Само по себе управление я просто переписал у Вас - проверьте, не ляпнул ли чего, если ляпнул - поправим.
Вот скетч:
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } class Motor { public: Motor(const int8_t dirPin, const int8_t stepPin, const char * motorName) { m_dirPin = dirPin; m_stepPin = stepPin; pinMode(m_dirPin, OUTPUT); pinMode(m_stepPin, OUTPUT); m_stepsToDo = 0; m_direction = LOW; m_Name = (char *) motorName; } void doOneStep(void) { if (! m_stepsToDo) return; m_stepsToDo--; digitalWrite(m_dirPin, m_direction); digitalWrite(m_stepPin, HIGH); delayMicroseconds(speedMotor); digitalWrite(m_stepPin, LOW); delayMicroseconds(speedMotor); Serial << m_Name << ": doing step. " << m_stepsToDo << " steps left. Direction=" << m_direction << "\n"; } inline void SetSteps (const int steps) { m_stepsToDo = (m_direction = (steps > 0)) ? steps : -steps; } private: static int speedMotor; int8_t m_dirPin, m_stepPin, m_direction; int m_stepsToDo; char * m_Name; }; char *sm1 = "X motor", *sm2 = "Y motor"; int Motor::speedMotor = 2000; Motor motors[2] = { Motor(5, 2, sm1), Motor(6, 3, sm2) }; void setup() { Serial.begin(115200); } const bool readCommand(int &steps, int &motor) { static char commandBuffer[16] = {0}; static int8_t ptr = 0; static const int8_t BufferSize = sizeof(commandBuffer)/sizeof(commandBuffer[1]) - 1; char symbol = 0; while (Serial.available() && ptr < BufferSize) { symbol = Serial.read(); if (symbol == '\n') break; commandBuffer[ptr++] = symbol; } if (ptr == BufferSize) { ptr = 0; motor = -1; Serial << "Input buffer OVERFLOW\n"; return true; } if (symbol != '\n') return false; commandBuffer[ptr] = 0; Serial << "Command read: \"" << commandBuffer << "\"\n"; sscanf(commandBuffer, "%d %d", &motor, &steps); ptr = 0; return true; } void loop () { motors[0].doOneStep(); motors[1].doOneStep(); int steps, motor; if (! readCommand(steps, motor)) return; if (motor < 0 || motor > 2) { Serial << "Command not recognized\n"; } else if (motor == 0) { motors[0].SetSteps(steps); motors[1].SetSteps(steps); } else { motors[motor-1].SetSteps(steps); } }а вот протокол исполнения (то, что в Сериале напечаталось, я только комментарии добавил для Вас)
Ктстати, останавливать можно и по одному, разумеется.
Как видите.я завёл "тип дланных" Motor и определил две переменные этого типа. Чтобы отличать их друг от друга при печати, я добавил им имена. Никакой другой нагрузки имена не несут и их из окончательной версии можно выбросить.
Между числами в команде обязан быть хотя бы один пробел (или табуляция). Можно больше, но суммарная длина буфера команды - 16 символов. Если превысить, скетч ругнётся.
Вроде, всё. Код краткий и простой, но если есть вопросы - задавайте. Только испытайте сначала, не надо спрашивать "а что будет, если ..." На такие вопросы лучший ответ - попробовать.
До интерполяции не дотягивает.
Было красным, стало синим. Интерполяция зеленым. Почему бы не включать моторы одновременно - будет движение по диагонали.
Почему бы не включать моторы одновременно - будет движение по диагонали.
Я так понял задачу. Если нужно как-то по-другому, пусть ТС скажет.
Да, по диагонали. Под углом 45 градусов.
Чтобы изменить угол нужно хотя-бы по одной оси изменить скорость.
Да, по диагонали. Под углом 45 градусов.
Чтобы изменить угол нужно хотя-бы по одной оси изменить скорость.
В данном скетче нельзя - она static. Но если ТС скажет, что это ему нужно - поменяем.
А почему от G-кодов отказались? Ну или AccelStepper использовать.
Спасибо за скетч! Как вы правильно сказали нужно прверить всё. И сам скетч разберу и вам отпишусь. А кнопки - концевки, которыми я создаю ноль-пункт. Могу выслать как это у меня получилось.
Про интерполяцию мне было сказано, как писал выше Andy(зелёная линия, хотя и движение по синей линии может подойти).
Как в arduino использовать G - коды без лишних программ, типа grbl я не знаю! А ещё обязательно использование COM-порта, и мне кажется проще посылать шаги мотору, чем G- код. Хотя может я не прав.
С помощью библиотеки AccelStepper вы предлагаете использовать различные скорости моторов? Если - да, то данный вариант не очень подходит.
А что они (эти два ШД) делают то? Если стандартные и проверенные приемы управления ШД не подходят?
И еще, я посмотрел вашу программу, длительность периода между шагами у вас 2 миллисекунды. Предположим, что у вас стандартный мотор с шагом 1.8 градуса, т.е. 200 шагов на оборот. Вы упоминаете о шилде с драйверами, на драйверах всегда есть функция деления шага, зачем нужен микрошаг понаписано много. Я не знаю что у вас установлено на драйверах. ну допустим деления нет , т.е. 1:1. Следовательно ШД у вас вращается 2.5 оборота в секунду. А где разгон и торможение в вашей программе ? Я думаю вы пытались увеличить частоту вращения уменьшением переменной speedmotor и на каком значении происходит срыв? AccelStepper о котором я упомянул тоже имеет минусы. но разгоняет и тормозит он корректно. Насчет G-кодов согласен, с ними связываться надо при сборке 3D принтера или HomeCNC станка.
Да у ШД 200 шагов на оборот. Делений нет, пока не требуются, но на шилде они естественно есть. Срыв честно говоря не помню, надо проверить(я выставил её стандартно и всё). Разгонно-тормозную характеристику делать буду позже. Мне сейчас нужно разобраться с интерполяцией.
Да у ШД 200 шагов на оборот. Делений нет, пока не требуются, но на шилде они естественно есть. Срыв честно говоря не помню, надо проверить(я выставил её стандартно и всё). Разгонно-тормозную характеристику делать буду позже. Мне сейчас нужно разобраться с интерполяцией.
Я вчера ошибся у вас длительность сигнала Step 2 миллисекунды (обычно на порядок меньше), а период 4 миллисекунды,т.е. скорость вращения 1.25 об/сек. Вы так и не сказали, что делаете из движков, но судя по всему координатный стол, тогда в программировании вы кружным путем пошли. Если нет, то еще раз
Мне нужно, чтобы работал 2 ШД работали, которые двигают платформу, как в ЧПУ станке т.е. дновременно ехали. Один столько, другой столько и попадали в нужную мне точку. Я пишу в COM порт этим движкам координаты в шагах. И они одновременн едут, продвигая мою подвижку по платформу. http://upload.akusherstvo.ru/image925489.jpg
Для этой картинки операция интерполяции вырождается в одно деление 4/2=2. т.е. чтобы двум движкам прийти в эту точку одновременно, надо чтобы ШД Х сделал в два раза больше шагов чем ШД У и со скоростью в два раза большей чем у ШД У. Все!
Не буду цитировать ЕвгенияП, но он вам абсолютно верно пишет об одновременности работы движков, и программу он вам хорошую написал, если вы делаете манипулятор перередвижения для фигур на шахматной доске, только конем придется ходить в два приема.
ЕвгенийП, здравствуйте.
Изучил программу и опробовал её. Моторами не крутит и в COM порт ничего не выдаёт, кроме Input buffer OVERFLOWCommand not recognized если подать одно и тоже ( типа 1 700 несколько раз). Подумал из-за несовпадения скрости COM порта у вас 112500 и у меня 9600. Изменил - ничего не случилось. А вот подумал , что у вас не прописан 8 пин, который управляет разрешением мотора - двигаться или не двигаться(enable). Прписал его в
void setup() { Serial.begin(9600); pinMode(8, OUTPUT); }Тоже не помогло. Вот и не в чём тут дело. И кидаю код с кнопками и 3-им мотором.
/* массивы перемен */ int motorNumb; // номер мотора char CurChar; // текущий символ для установки флага мотора или шага char Com_Step = 0; // флаг установки шага char Com_Motor = 0; // флаг выбора мотора int dirPin1 = 5; // pin для направления int dirPin2 = 6; int dirPin3 = 13; int stepPin1 = 2; // pin для шагов int stepPin2 = 3; int stepPin3 = 12; int openmotorPin = 8; // pin для запуска мотора int val_btn1=0; // значение кнопки int val_btn2=0; boolean val_btn3=0; int btnPin1 = 15; // pin для кнопки int btnPin2 = 14; int btnPin3 = 9; int speedmotor = 2000; // задаем скорость мотора int stepsvar = 0; // значение шагов, которое задаем мотору int flag_zero=1; //флаг установки нулей int flag1_motor=1; int flag2_motor=1; int flag3_motor=1; int steps_shagovik1=1200; // весь диапазон шагового мотора int steps_shagovik2=800; int steps_shtok=360; // весь диапазон штокового мотора int solenoidPin = 10; // pin для соленоида /* Функция установки pin и открытия com-порт */ void setup() { // задаем, что этот pin на выход pinMode(dirPin1, OUTPUT); pinMode(dirPin2, OUTPUT); pinMode(dirPin3, OUTPUT); pinMode(stepPin1, OUTPUT); pinMode(stepPin2, OUTPUT); pinMode(stepPin3, OUTPUT); pinMode(openmotorPin, OUTPUT); pinMode(btnPin1,INPUT_PULLUP); pinMode(btnPin2,INPUT_PULLUP); pinMode(btnPin3,INPUT_PULLUP); pinMode(solenoidPin, OUTPUT); // открываем com-порт со скоростью передачи 9600 Serial.begin(9600); } /* функция, отвечающая за вращение мотора №1 */ void step1(boolean dir,int steps) { digitalWrite(dirPin1,dir); for(int i=0;i<steps;i++) { // если на pin кнопки что-то пришло, то выходим из цикла принудительно val_btn1= digitalRead(btnPin1); if(val_btn1==LOW) {digitalWrite(stepPin1, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin1, LOW); delayMicroseconds(speedmotor); flag1_motor=1;} if((val_btn1==HIGH)&&(flag1_motor==1)) {flag1_motor=0; break; } if((val_btn1==HIGH)&&(flag1_motor==0)) {digitalWrite(stepPin1, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin1, LOW); delayMicroseconds(speedmotor);} } } /* функция, отвечающая за вращение мотора №2 */ void step2(boolean dir,int steps) { digitalWrite(dirPin2,dir); for(int i=0;i<steps;i++) { val_btn2= digitalRead(btnPin2); if(val_btn2==LOW) {digitalWrite(solenoidPin,LOW); digitalWrite(stepPin2, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin2, LOW); delayMicroseconds(speedmotor); digitalWrite(solenoidPin,HIGH); flag2_motor=1;} if((val_btn2==HIGH)&&(flag2_motor==1)) {digitalWrite(solenoidPin,HIGH); flag2_motor=0; break; } if((val_btn2==HIGH)&&(flag2_motor==0)) {digitalWrite(solenoidPin,LOW); digitalWrite(stepPin2, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin2, LOW); delayMicroseconds(speedmotor);} } } /* функция, отвечающая за вращение мотора №3 */ void step3(boolean dir,long steps){ digitalWrite(dirPin3,dir); for(int i=0;i<steps;i++){ val_btn3= digitalRead(btnPin3); if(val_btn3==HIGH) {digitalWrite(stepPin3, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin3, LOW); delayMicroseconds(speedmotor); flag3_motor=1;} if((val_btn3==LOW)&&(flag3_motor==1)) {flag3_motor=0; break; }if((val_btn3==LOW)&&(flag3_motor==0)) {digitalWrite(stepPin3, HIGH); delayMicroseconds(speedmotor); digitalWrite(stepPin3, LOW); delayMicroseconds(speedmotor);} } } /* Функция работает по кругу(зациклена) */ void loop () { /* Установка нулей для моторов */ while(flag_zero==1) { digitalWrite(solenoidPin,HIGH); // Установка нулей для шагового мотора №1 // Мотор доходит до кнопки (в качестве шагов весь диапазон) step1(true,steps_shagovik1); //Считываем значение кнопки val_btn1=digitalRead(btnPin1); if (val_btn1==HIGH) { delay(1000); Serial.println("Push button 1"); //Мотор отходит на середину диапазона step1(false,(steps_shagovik1/2)); Serial.println("Function step1"); } delay(1000); //Установка нулей для шагового мотора №2 step2(false,steps_shagovik2); val_btn2=digitalRead(btnPin2); if (val_btn2==HIGH) { delay(1000); Serial.println("Push button 2"); step2(true,(steps_shagovik2/2)); } delay(1000); // Установка нулей для штокового мотора step3(true,steps_shtok); //Считываем значение кнопки val_btn3=digitalRead(btnPin3); if (val_btn3==LOW) { delay(1000); Serial.println("Push button 3"); step3(false,(steps_shtok/2)); } flag_zero=0; } /*При введение символа 'M' или 'S' устанавливается флаг мотора или флаг шага*/ if ((Serial.available() > 0)&&(Com_Step == 0)&& (Com_Motor == 0)) { //читаем байт из порта CurChar = Serial.read(); //если это символ S то устанавливаем флаг начала установки шага if (CurChar == 'S') { Com_Step = 1; Serial.println("Select Steps"); } else { //если это символ M то устанавливаем флаг выбора мотора if (CurChar == 'M') { Com_Motor = 1; Serial.println("Selection motor"); } } } /* Устанавливаем какой мотор будет работать */ //если в порту есть хоть один символ и установлен флаг выбора мотора if ((Serial.available() > 0)&&(Com_Motor == 1)) { // сбрасываем флаг Com_Motor = 0; Serial.print("Motor: "); motorNumb = Serial.parseInt(); Serial.println(motorNumb); } /* Устанавливаем сколько шагов должен сделать мотор */ //если в порту есть хоть один символ и установлен флаг установки шага// if ((Serial.available() > 0)&&(Com_Step == 1)) { // сбрасываем флаг установки шага Com_Step = 0; Serial.print("Steps: "); stepsvar=Serial.parseInt(); Serial.println(stepsvar); //в зависимости от того какой номер мотора //назначен выполняется определенный case switch (motorNumb) { case 1: digitalWrite(solenoidPin, HIGH); if (stepsvar > 0) { step1(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step1(false,stepsvar); } digitalWrite(solenoidPin, LOW); break; case 2: if (stepsvar > 0) { step2(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step2(false,stepsvar); } break; case 3: if (stepsvar > 0) { step3(true,stepsvar); } else if (stepsvar < 0) { stepsvar=-1*stepsvar; step3(false,stepsvar); } break; } } }ЕвгенийП, здравствуйте.
Изучил программу и опробовал её. Моторами не крутит и в COM порт ничего не выдаёт, кроме Input buffer OVERFLOWCommand not recognized если подать одно и тоже ( типа 1 700 несколько раз). Подумал из-за несовпадения скрости COM порта у вас 112500 и у меня 9600. Изменил - ничего не случилось. А вот подумал , что у вас не прописан 8 пин, который управляет разрешением мотора - двигаться или не двигаться(enable).
Так, нет, так не пойдёт. Если Вы хотите довести всё до ума и заставить её ездить по диагоналям и как-то там ещё, я готов Вам помогать, но давайте идти шаг за шагом и не мешать в одну кучу всех мух и котлеты.
Будь мы вместе за компьютером, мы бы дожали это за пару часов, но так придётся потратить неделю, но мы дожмём. Для этого Вы должны 1) чётко делать что я говорю, и 2) давать мне точно ту информацию, которуя я прошу.
Поехали. Про пин пока забудьте и про моторы тоже. Отключите их. Подключим позже. Пока же:
1. Возьмите мой скетч из поста №14.
2. в мониторе установите ту же скорость, что и у меня в коде
3. В выпадающем списке, что находится рядом с выбором скорости в мониторе установите "новая строка"
После этого перезапустите скетч и вводите (по одной!!!) команды
1 3
2 -4
0 3
Команды вводите по одной. После каждой команды давите Ентер.
В результате Вы должны получить примерно ту же печать, что и у меня в посте №14. Если получите то же. что и у меня, напишите мне об этом. Если получите что-то другое, то дайте мне следующее:
1. Копипасту того, что напечатано в мониторе
2. скриншот монитора. чтобы я видел настройки скорости и новой строки.
Это самое главное - это логика работы всей программы. Когда дожмём это, перейдём к движкам. Дожмём их, перейдём к диагонали. Дожмём её, подумаем над разными скоростями. давайте по порядку.
Жду информации.
Да. Всё получилось как у вас.
Я попробовал с моторами. Они крутятся. Поробовал команду 0 500 оба крутит. Единственное они оба 500 крутят. А если надо записать ) 500 200. Хотя я спешу наверное. И я не очень понял вы пишете на C++? Просто я не все строчки понимаю. Например 1-ую.
Я попробовал с моторами. Они крутятся. Поробовал команду 0 500 оба крутит. Единственное они оба 500 крутят. А если надо записать ) 500 200. Хотя я спешу наверное. И я не очень понял вы пишете на C++? Просто я не все строчки понимаю. Например 1-ую.
Отлично. Теперь, плавно переходим к "500 200".
Вам нужна единая команда типа 0 200 500? Не проблема. Сделаем.
Пока же её нет, делаем так:
1. вводим команду 1 500 <enter>
2. НЕ ДОЖИДАЯСЬ пока мотор остановится вводим 2 200 <enter>
Должны крутиться оба. Если 500 мало (не успеваете вторую команду ввести, а первый движок уже стал, введите в первой команде больше, 1000 там - сколько надо). Они должны крутиться оба но не совсем вместе. Должно быть так: один дёрнется, потом другой, потом снова первый и т.д.
Если это работает, перейдём одновременному кручению.
Пожалуйста
1) опишите что у Вас получилось и
2) Вы там добавляли какой-то пин. Выложите текущий скетч полностью, чтобы у нас одинаковые были.
Всё так и есть, запускаем сначал один 1 1500, птм второй 2 1500 и они ходят дёргано - шаг за шагом.
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } class Motor { public: Motor(const int8_t dirPin, const int8_t stepPin, const char * motorName) { m_dirPin = dirPin; m_stepPin = stepPin; pinMode(m_dirPin, OUTPUT); pinMode(m_stepPin, OUTPUT); m_stepsToDo = 0; m_direction = LOW; m_Name = (char *) motorName; } void doOneStep(void) { if (! m_stepsToDo) return; m_stepsToDo--; digitalWrite(m_dirPin, m_direction); digitalWrite(m_stepPin, HIGH); delayMicroseconds(speedMotor); digitalWrite(m_stepPin, LOW); delayMicroseconds(speedMotor); Serial << m_Name << ": doing step. " << m_stepsToDo << " steps left. Direction=" << m_direction << "\n"; } inline void SetSteps (const int steps) { m_stepsToDo = (m_direction = (steps > 0)) ? steps : -steps; } private: static int speedMotor; int8_t m_dirPin, m_stepPin, m_direction; int m_stepsToDo; char * m_Name; }; char *sm1 = "X motor", *sm2 = "Y motor"; int Motor::speedMotor = 2000; Motor motors[2] = { Motor(5, 2, sm1), Motor(6, 3, sm2) }; void setup() { Serial.begin(115200); pinMode(8, OUTPUT); } const bool readCommand(int &steps, int &motor) { static char commandBuffer[16] = {0}; static int8_t ptr = 0; static const int8_t BufferSize = sizeof(commandBuffer)/sizeof(commandBuffer[1]) - 1; char symbol = 0; while (Serial.available() && ptr < BufferSize) { symbol = Serial.read(); if (symbol == '\n') break; commandBuffer[ptr++] = symbol; } if (ptr == BufferSize) { ptr = 0; motor = -1; Serial << "Input buffer OVERFLOW\n"; return true; } if (symbol != '\n') return false; commandBuffer[ptr] = 0; Serial << "Command read: \"" << commandBuffer << "\"\n"; sscanf(commandBuffer, "%d %d", &motor, &steps); ptr = 0; return true; } void loop () { motors[0].doOneStep(); motors[1].doOneStep(); int steps, motor; if (! readCommand(steps, motor)) return; if (motor < 0 || motor > 2) { Serial << "Command not recognized\n"; } else if (motor == 0) { motors[0].SetSteps(steps); motors[1].SetSteps(steps); } else { motors[motor-1].SetSteps(steps); } }2 everlast
Вам поможет алгоритм Брезенхема:
https://ru.wikipedia.org/wiki/Алгоритм_Брезенхэма
причем он работает без умножения и деления (для быстроты)
sva1509 Спасибо! Посмотрю!
Всё так и есть, запускаем сначал один 1 1500, птм второй 2 1500 и они ходят дёргано - шаг за шагом.
Всё здорово. Сегодня чуть попозже попробуем ходить н дёргано.
А пока, знаете, я в прошлый раз забыл - комадна для двух двигателей у нас ведь есть, только там нельзя разные дистанции задать. Попробуйте 0 1500 - должны также дёргано по диагонали ехать. Скажите мне работает ли.
Дерганность сегодня победим, надеюсь, чуть позже. Только скажите мне пожалуйста две вещи:
1. Имею ли я право занимать таймер(ы). Они у Вас для чего-то ещё используются? Или я могу занимать оба? Или один?
2. Нужно ли Вам будет делать задежку (которая сейчас 2000мкс) разной для разных двигателей или она всегда будет одинаковой для обоих?
У меня диапозон движения не такой большой, поэтому писал 0 500 и едут они диагонали. Дёрганость на самой платформе(когда едут два движка) не видно.
1. Я не пользовался таймерами и пока не знаю как ими работать;
2. Вы имеете ввиду вот это?Скорость моторов? Я пока не знаю.
Вот что я думаю по поводу скорости моторов.Получается так, если я задаю 0 500 он движется по диагонали, и оба мотора приходят в одну точку. А когда будет по прямугольнику, то один закончит движение раньше другого 0 500 100. Получается, чтобы они пришли одновременно в одну точку по диагонали прямоугольника нужно варьировать скорость или использовать https://ru.wikipedia.org/wiki/Алгоритм_Брезенхэма ?!
Ну и еще. Я не очень понимаю на каком языке вы написали? Мне просто надо прописать ноль-пункты для моторов и кнопки...Всё то, что описано в моём коде! Я пока не знаю как сделать с вашей переделанной программой!
Мне просто надо прописать ноль-пункты для моторов и кнопки...Всё то, что описано в моём коде! Я пока не знаю как сделать с вашей переделанной программой!
Доберёмся. Всё будет. Давайте дожмём, чтобы всё хорошо ездило.
Хорошо.
ЕвгенийП Нашёл ещё один интересный скетч, как раз для ЧПУ станка. Что думаете?
int motorPins[3][2] = {{2,5},{3,6},{12, 13}}; int count; int count2[3] = {0,0,0}; int val = 0; int rot=0; int incomingByte = 0; int sign=1; long delayTime; //Процедура настройки прошивки void setup() { pinMode(8, OUTPUT); int i; Serial.begin(115200); //Эта скорость должна совпадать со скоростью, установленной в программе for (i=0; i<3; i++) { for (count = 0; count < 2; count++) { pinMode(motorPins[i][count], OUTPUT); //установка режима работы цифровых pin'ов Ардуино } } delayTime=2000; } //Поворот двигателя с номерм sm на один шаг вперёд void moveForward(int sm) { digitalWrite(motorPins[sm][1], HIGH); //Задаём направление digitalWrite(motorPins[sm][0], HIGH); digitalWrite(motorPins[sm][0], LOW); } //Поворот двигателя с номерм sm на один шаг назад void moveBackward(int sm) { digitalWrite(motorPins[sm][1], LOW); digitalWrite(motorPins[sm][0], HIGH); digitalWrite(motorPins[sm][0], LOW); } //Задержка в микосекундах void delayMicros(long wt){ unsigned long mls; unsigned int mks; mls=(unsigned long)(wt / 1000); mks=(unsigned int)(wt % 1000); if (mls>0) delay(mls); if (mks>0) delayMicroseconds(mks); } //Одновременный поворот двигателей 0, 1, 2 на x, y, z шагов соответственно void MoveSM(long x, long y, long z) { long c[3], c2[3]; double c1[3], d[3]; long m, i; boolean flg; c[0] = x; c[1] = y; c[2] = z; m = 1; for (i=0; i<3; i++) { if (m < abs(c[i])) m = abs(c[i]); } for (i=0; i<3; i++) { c1[i] = 0; d[i] = 1.0 * c[i] / m; c2[i] = 0; } flg = false; for (i=0; i<3; i++) { if (abs(c1[i]) < abs(c[i])) flg=true; } while (flg) { flg=false; for (i=0; i<3; i++) { if (abs(c1[i]) < abs(c[i])) c1[i] += d[i]; if (abs(c1[i]) - abs(c2[i]) >= 0.5) { if (c[i]>0) { c2[i]++; moveForward(i); } else { c2[i]--; moveBackward(i); } } if (abs(c1[i]) < abs(c[i])) flg=true; } delayMicros(delayTime); } } //Основной цикл void loop() { if (Serial.available() > 0) { //Пришла команда long c[4]={0,0,0,0}; int i; sign=1; i=0; incomingByte = Serial.read(); while (incomingByte!=';') { //Читаем входящую строку, признак конца строки знак "точка с запятой" if (c[i]==0) { if (incomingByte=='-') sign=-1; } if (incomingByte==',') { c[i]*=sign; sign=1; i++; } else if (incomingByte>='0' && incomingByte<='9') { c[i]=c[i]*10+incomingByte-'0'; } while (Serial.available() == 0) { delayMicroseconds(1); //Ждём очередной символ, если не пришел } incomingByte = Serial.read(); } c[i]*=sign; if (c[3]>0) delayTime=c[3]; MoveSM(c[0],c[1],c[2]); //Вращаем двигатели на заданное число шагов Serial.println("OK"); //Отправляем компьютеру сообщение "OK", значит можно высылать новую команду } else delayMicroseconds(1); //Если ничего не пришло, ждём 1 микросекуду. }Ага, вот посмотрите. Они в строках 26-28 дёргают двигатесь на шаг.
Вы же в аналогичной ситуации делаете задержку - строки 19-21 нашего скетча.
Разница в том, что у них задержки (наша строка 20) нет. Вместо этого они делают единую задержку после "многократных дёргов" обоих двигателей в строке 92.
Вы можете объяснить для чего эта задержка? Она нам сильно нужна? Или можно без неё, но просто большее количество раз дёргать? Честно говоря, я как раз над ней думал, она сильно мешает и ради неё придётся "ногой до уха доставать". Если она Вам нужна. чтобы знать сколько именно проехал мотор, то может это сделать по-другому?
Попробуйте убрать (закомментировать) задержку в строке 20 и скажите, как получается. Должно быть более плавное движение по дигонали, а не рыскание то по одной оси, то по другой. Получается?
Закоментировал эту строку в нашем скетче. Стало дергаться сильно. А если раскоментировать, то нет.
Тогда попробуйте вот так и скажите что получится.
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } class Motor { public: Motor(const int8_t dirPin, const int8_t stepPin, const char * motorName) { m_dirPin = dirPin; m_stepPin = stepPin; pinMode(m_dirPin, OUTPUT); pinMode(m_stepPin, OUTPUT); m_stepsToDo = 0; m_direction = LOW; m_Name = (char *) motorName; } void doOneStep(void) { if (! m_stepsToDo) return; m_stepsToDo--; digitalWrite(m_dirPin, m_direction); digitalWrite(m_stepPin, HIGH); } void finishOneStep(void) { digitalWrite(m_stepPin, LOW); } inline void SetSteps (const int steps) { m_stepsToDo = (m_direction = (steps > 0)) ? steps : -steps; } private: static int speedMotor; int8_t m_dirPin, m_stepPin, m_direction; int m_stepsToDo; char * m_Name; }; char *sm1 = "X motor", *sm2 = "Y motor"; int Motor::speedMotor = 2000; Motor motors[2] = { Motor(5, 2, sm1), Motor(6, 3, sm2) }; void setup() { Serial.begin(115200); pinMode(8, OUTPUT); } const bool readCommand(int &steps, int &motor) { static char commandBuffer[16] = {0}; static int8_t ptr = 0; static const int8_t BufferSize = sizeof(commandBuffer)/sizeof(commandBuffer[1]) - 1; char symbol = 0; while (Serial.available() && ptr < BufferSize) { symbol = Serial.read(); if (symbol == '\n') break; commandBuffer[ptr++] = symbol; } if (ptr == BufferSize) { ptr = 0; motor = -1; Serial << "Input buffer OVERFLOW\n"; return true; } if (symbol != '\n') return false; commandBuffer[ptr] = 0; Serial << "Command read: \"" << commandBuffer << "\"\n"; sscanf(commandBuffer, "%d %d", &motor, &steps); ptr = 0; return true; } void loop () { motors[0].doOneStep(); motors[1].doOneStep(); delayMicroseconds(2000); motors[0].finishOneStep(); motors[1].finishOneStep(); delayMicroseconds(2000); int steps, motor; if (! readCommand(steps, motor)) return; if (motor < 0 || motor > 2) { Serial << "Command not recognized\n"; } else if (motor == 0) { motors[0].SetSteps(steps); motors[1].SetSteps(steps); } else { motors[motor-1].SetSteps(steps); } }Да, явно лучше.Не чувствуются шаги.
Так, теперь скажите нам пора переходить к кнопкам или мы ещё будем движение улучшать.
К кнопкам переходим тогда, когда движение нам нравится и больше мы его менять не хотим. Поэспериментируйте и скажите. Если хотим, что чего хотим добиться.
До интерполяции не дотягивает.
Было красным, стало синим. Интерполяция зеленым. Почему бы не включать моторы одновременно - будет движение по диагонали.
Получается мне нужно как на рисунке зелёным. А сейчас получается что красным или синим. Еще получается нужно команду 0 200 500, чтобы платфрма ехала по прямоугольнику, а то 0 500 или 0 200 получается по квадрату, а нужно попадать в любую точку XY плоскости. Как я понял, к примеру, мы задаём 0 3 500, по X он едет 3, а по Y 500 т.е. он делает так: X-мотор проезжает 1 шаг , Y-мотор 165 шагов, и так три раз. И видимо остальные шаги по Y(165*3=495, 500-495=5) т.е. 5 шагов он доделывает сам.
А сейчас получается так если я задам 0 3 500, то получится так: по X сделает сразу 3 шага, а по Y будет крутить 500.
ЕвгениюП, с удовольствием читаю ваши этюды, хотя это требует усилий. Я хотел бы обратить внимание, что шаговый двигатель не просто "штучка" в которую через пины забиваются "единички" и "нули". Это сложное устройство, теорию ШД я вам не предлагаю читать, но думаю, что в силу вашей профессии вы ознакомитесь с материлом на http://avrdoc.narod.ru/index/0-7. А может и Everlast почитает.
Получается мне нужно как на рисунке зелёным. А сейчас получается что красным или синим.
Знаете, я тут сильно напрягся, даже попытался раздобыть движки для пробы. Дело в том, я ожидал что сейчас они будут ехать по диагонали. Пусть рывками, но по диагонали. Если это не так, то, боюсь, я что заочно мне это не отладить, а движков у меня нет. Извините, похоже я переоценил возможности заочной отладки. Простите.
ЕвгенийП
Ничего страшного. Вы мне и так очень сильно помогли! А по поводу движения. Они движуться. Только, как я писал, при 0 500 или 0 2000 и т.д.(они движуться по квадрату). А у меня должна быть возможность попасть в любую точку плоскости XY c тем движением моторов, как описано мною выше.
Спасибо за то, что откликнулись и помогли мне в решении данной проблемы!