Я пытаюсь управлять двумя шаговыми двигателями с помощью последовательного ввода. Мой код работает, однако мне приходится несколько раз нажимать новую команду направления
Я использую два шаговых двигателя 28BYJ-48 с двумя драйверами, которые идут в комплекте. (Я не знаю их названия.)
Вот мой код:
/*
* Код для одновременного управления двумя шаговыми двигателями с использованием вызовов функций библиотеки шаговых двигателей
* Этот код имеет функции, которые делают вызовы для запуска одного шага от каждого из двух двигателей за раз.
* поэтому каждый двигатель по очереди делает шаг, в результате чего они оба работают вместе
* переменная 'lastCall' обеспечивает непрерывный ввод, чтобы поддерживать работу степперов, если нет последовательного ввода
* Написано Габриэлем Адамсом — март 2023 г. —
*/
#include <Stepper.h>
//определения для каждой команды, которая будет получена через последовательный порт
#define COMMAND_LEFT 'a'
#define COMMAND_RIGHT 'd'
#define COMMAND_FORWARD 'w'
#define COMMAND_BACK 's'
#define COMMAND_STOP ' '
//Количество шагов на внутренний оборот двигателя
const float STEPS_PER_REV = 32;
//Величина понижения передачи
const float GEAR_RED = 64;
//Количество шагов на один оборот выходного редуктора
const float STEPS_PER_OUT_REV = STEPS_PER_REV * GEAR_RED;
//введите здесь количество шагов на оборот для ваших двигателей
int stepsInRev = STEPS_PER_OUT_REV ;
// это устанавливает значение для циклов for и, следовательно, устанавливает количество шагов в каждом вызове
int num_of_steps = 1;
// установка выводов для каждого драйвера Motor1 ~ IN1, IN2, IN3, IN4; двигатель2 ~ IN1, IN2, IN3, IN4
Stepper myStepper1(STEPS_PER_OUT_REV, 4, 6, 5, 7);
Stepper myStepper2(STEPS_PER_OUT_REV, 8, 10, 9, 11);
// переменная для хранения последнего обращения к последовательному порту
char lastCall = ' ';
// Я прототипировал здесь все функции, но по какой-то причине Arduino IDE это не понравилось
//поэтому они закодированы, пока я не выясню, почему
//аннулировать forwardStep();
//отменить обратный шаг();
// недействительный левый шаг();
// недействительный правый шаг();
//аннулировать allStop();
//двигать моторы вперед
void forwardStep(int steps){
Serial.println("forward");
// шаг вперед на один шаг
myStepper1.step(1);
myStepper2.step(1);
delay(10);
}
// чтобы переместить моторы назад
void backwardStep(int steps){
Serial.println("backward");
// шаг на один шаг назад
myStepper1.step(-1);
myStepper2.step(-1);
delay(10);
}
// для перемещения двигателей в противоположных направлениях (слева)
void leftStep(int steps){
Serial.println("left");
// шаг на один шаг влево
myStepper1.step(1);
myStepper2.step(-1);
delay(10);
}
// для перемещения двигателей в противоположных направлениях (справа)
void rightStep(int steps){
Serial.println("right");
// шаг на один шаг вправо
myStepper1.step(-1);
myStepper2.step(1);
delay(10);
}
// чтобы отключить драйверы моторов и остановить моторы
void allStop(){
Serial.println("stop");
// шаговики останавливаются
PORTD = B00000000; //устанавливает все контакты с 0 по 7 в состояние LOW, чтобы выключить stepper1
PORTB = B00000000; //устанавливает все контакты с 8 по 13 в состояние LOW, чтобы выключить stepper2
}
void setup() {
Serial.begin(9600);//запускаем последовательный порт bluetooth - отправка и получение на скорости 9600 бод
// устанавливаем скорость 60 об/мин:
myStepper1.setSpeed(700);
myStepper2.setSpeed(700);
}
void loop() {
//проверить, есть ли последовательная связь, и если да, прочитать данные
if(Serial.available()) {
char data = (char)Serial.read();
// переключиться на установку символа через последовательный порт на команду
switch(data) {
case COMMAND_FORWARD:
forwardStep(num_of_steps);
break;
case COMMAND_BACK:
backwardStep(num_of_steps);
break;
case COMMAND_LEFT:
leftStep(num_of_steps);
break;
case COMMAND_RIGHT:
rightStep(num_of_steps);
break;
case COMMAND_STOP:
allStop();
break;
}
// установить переменную 'lastCall' на последний вызов из serial
lastCall = data;
}
char data = lastCall;
Loop(lastCall);
Serial.read();
}
void Loop(char x){
switch(lastCall) {
case COMMAND_FORWARD:
forwardStep(num_of_steps);
break;
case COMMAND_BACK:
backwardStep(num_of_steps);
break;
case COMMAND_LEFT:
leftStep(num_of_steps);
break;
case COMMAND_RIGHT:
rightStep(num_of_steps);
break;
case COMMAND_STOP:
allStop();
break;
}
return lastCall;
(char)Serial.read();
}
@Gabriel Adams, 👍0
Обсуждение1 ответ
Проблема в том, что вы читаете из последовательного буфера без использования данных. В вашем коде есть три места, где вы используете Serial.read();:
- Вы используете in в блоке с серийным кодом и соответствующим образом устанавливаете
lastCall. Это нормально. - Затем вы используете его в конце
void loop(), но ничему не присваиваете значение. - И вы используете его в конце своей собственной функции
Loop(), снова не присваивая значение чему-либо.
Краткое объяснение того, как работает Последовательный: Uno имеет аппаратное обеспечение для обработки последовательной связи в фоновом режиме через прерывания. Данные поступают на Uno и автоматически (в фоновом режиме) помещаются во внутренний буфер объекта Serial. Вызов Serial.read() удаляет самый старый байт из буфера (чтобы вы получали байты в порядке поступления) и возвращает его. Если нет доступных новых данных, он вернет -1.
Поэтому, когда вы просто используете Serial.read(), не присваивая значение чему-либо, вы фактически выбрасываете байты данных из последовательного буфера.
Я думал, что команда Serial.read() обеспечит более быстрое чтение последовательного ввода.
Чтения данных из буфера недостаточно. На самом деле нужно что-то с этим делать. В противном случае вы просто читаете, не реагируя. Поэтому удалите два вызова Serial.read(), оставив только один в блоке if(Serial.available()).
почему в данный момент он не изменит сразу направление, когда я даю новую команду, как мне использовать команду Serial.read() для быстрого перехода к новому циклу?
Вы должны удалить все вызовы delay(). В настоящее время ваш код тратит больше всего времени на эти задержки, ничего не делая. Вместо этого вы можете использовать неблокирующий стиль кодирования из примера BlinkWithoutDelay, который поставляется с Arduino IDE. Он использует millis() в качестве хранителя времени, выполняя код (мигание светодиода в примере; выполнение шага в вашем коде) только тогда, когда пришло время это сделать. В Интернете есть много руководств по этому поводу.
Если вы хотите, вы можете пойти еще дальше и переключиться на библиотеку AccelStepper, которая имеет больше возможностей, чем стандартная библиотека Stepper. Он позволяет вам установить скорость и ускорение, а затем вы просто запускаете двигатель, достаточно часто выполняя метод run(). Тогда нет необходимости в собственном времени шагов, потому что библиотека справляется с этим. Хотя это будет более серьезное изменение в вашем коде.
- Управление направлением шагового двигателя с помощью кнопок.
- Шаговый двигатель не работает с платой A4988
- Кнопка сброса не работает + не могу загрузить код, что не так?
- Grbl на Arduino Uno (Elegoo) с неработающим шаговым двигателем DM542 + nema24
- Принципиальная схема для работы биполярного шагового двигателя с использованием LDR
- Непрерывное обнаружение кнопок для шагового управления
- Справка по библиотеке AccelStepper - Одновременное управление двигателем
- Как позволить шаговому двигателю вращаться постоянно?
Почему вы делаете эти два
Serial.read(), не используя результат за пределами вашего последовательного кода? Если ваши данные поступят прямо перед этим, они будут просто удалены., @chrislЯ все еще нахожусь в процессе изучения объектно-ориентированного кодирования. Я думал, что команда Serial.read() обеспечит более быстрое чтение последовательных входов. Как мне лучше оценить это? Например, вместо того, как в данный момент он не изменит направление немедленно, когда я даю новую команду, как мне использовать команду Serial.read() для быстрого перехода к новому циклу., @Gabriel Adams
Кажется, у вас странное понимание параметров функции, которые не используются функциями. Кстати: прототипирование функций выполняется за вас IDE, но если вы делаете это самостоятельно, делайте это правильно: параметры должны подходить., @DataFiddler