Управление шаговым двигателем — отправка в определенные позиции по команде «buttonPushCounter ==», вперед и назад.
Я работаю над проектом, использующим Arduino для управления шаговым двигателем. Двигатель приводит в движение ходовой винт, который перемещает цветные фильтры в определенные положения по линейной дорожке — вперед и назад. Движения запускаются другим устройством, которое подсчитывает обороты (с помощью датчика). Arduino считывает входные данные и активирует двигатель на определенных оборотах, т. е. при 10 — перемещение на 70 мм вперед, при 30 — перемещение на 70 мм назад. Я могу управлять степпером, чтобы он неоднократно выполнял точные движения одно за другим, независимо от счетчика. Я могу подключить Arduino к счетчику и включать/выключать светодиод при заданном счетчике. Но когда я пытаюсь запустить моторы от счетчика, он срабатывает, но движется лишь крошечными прерывистыми шагами и движется только в одну сторону. Вот этот скетч ниже. Любая помощь очень приветствуется. Спасибо.
// эта константа не изменится:
const int buttonPin = 2; // контакт, к которому прикреплена кнопка
const int ledPin = 7; // контакт, к которому прикреплен светодиод
// Переменные изменятся:
int buttonPushCounter = 0; // счетчик количества нажатий кнопок
int buttonState = 0; // текущее состояние кнопки
int lastButtonState = 0; // предыдущее состояние кнопки
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);
void forwardstep1() {
myMotor->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
myMotor->onestep(BACKWARD, DOUBLE);
}
AccelStepper Astepper1(forwardstep1, backwardstep1);
void setup() {
// инициализируем вывод кнопки как вход:
pinMode(buttonPin, INPUT);
// инициализируем светодиод как выход:
pinMode(ledPin, OUTPUT);
// инициализируем последовательную связь:
Serial.begin(9600);
AFMS.begin(); // создаем с частотой по умолчанию 1,6 кГц
//AFMS.begin(1000); // ИЛИ с другой частотой, скажем 1 кГц
TWBR = ((F_CPU / 500000l) - 16) / 2; // Изменяем тактовую частоту i2c на 400 кГц
Astepper1.setAcceleration(6000.0);
Astepper1.setMaxSpeed(600);
Astepper1.setSpeed(600); // об/мин
// пока (switchIsOff) {
//поворот сервопривода в одном направлении -
//сообщаем сервоприводу, что это 0
}
void loop() {
// читаем входной контакт кнопки:
buttonState = digitalRead(buttonPin);
// сравниваем состояние кнопки с предыдущим состоянием
if (buttonState != lastButtonState) {
// если состояние изменилось, увеличиваем счетчик
if (buttonState == HIGH) {
// если текущее состояние ВЫСОКОЕ, то кнопка переключилась из выключенного состояния во включенное:
buttonPushCounter++;
Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(buttonPushCounter);
} else {
// если текущее состояние НИЗКОЕ, то кнопка переключилась из включенного состояния в выключенное:
Serial.println("off");
}
// сохраняем текущее состояние как последнее для следующего прохода цикла
lastButtonState = buttonState;
if (buttonPushCounter == 10) {
digitalWrite(ledPin, HIGH);
Astepper1.moveTo(600);
Astepper1.setSpeed(600);
Astepper1.run();
}
if (buttonPushCounter == 30) {
digitalWrite(ledPin, LOW);
Astepper1.moveTo(200);
Astepper1.setSpeed(600);
Astepper1.run();
}
}
}
@EJStudio, 👍0
Обсуждение2 ответа
В библиотеке AccelStepper есть несколько методов, похожих на run
.
Тот, который вы используете, run()
, предназначен для вызова при КАЖДОМ проходе через loop()
, и он будет вызывать шаг только в том случае, если он необходим, на основе внутреннего состояния библиотеки (т. е. текущей позиции, целевой позиции, профиля ускорения и т. д.). Так часто вызывать безопасно — она определит сама, если есть какое-либо движение нужно.
Вы можете переместить вызов run()
в место внутри loop()
, но за пределами операторов if
.
В качестве альтернативы существует функция runToPosition()
, которая блокирует — она останавливает все выполнение вашего кода до тех пор, пока шаговый двигатель не окажется в целевой позиции. Это было бы хорошо для вашего текущего опубликованного кода, но если вы хотите также отслеживать счетчик оборотов, то это не лучший вариант.
Спасибо. Ваше описание неисправности имеет для меня смысл. Как вы заметили, блокировка будет проблемой, поскольку мне нужно, чтобы счетчик продолжал регистрироваться во время выполнения движения. Я переработал сценарий, как вы предлагаете - внутри цикла, но вне оператора if - я сделал то, что вы имели в виду? Но возникает та же проблема — двигатель продвигается шагами.
// эта константа не изменится:
const int buttonPin = 2; // контакт, к которому прикреплена кнопка
const int ledPin = 7; // контакт, к которому прикреплен светодиод
// Переменные изменятся:
int buttonPushCounter = 0; // счетчик количества нажатий кнопок
int buttonState = 0; // текущее состояние кнопки
int lastButtonState = 0; // предыдущее состояние кнопки
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);
void forwardstep1() {
myMotor->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
myMotor->onestep(BACKWARD, DOUBLE);
}
AccelStepper Astepper1(forwardstep1, backwardstep1);
void setup() {
// инициализируем вывод кнопки как вход:
pinMode(buttonPin, INPUT);
// инициализируем светодиод как выход:
pinMode(ledPin, OUTPUT);
// инициализируем последовательную связь:
Serial.begin(9600);
AFMS.begin(); // создаем с частотой по умолчанию 1,6 кГц
//AFMS.begin(1000); // ИЛИ с другой частотой, скажем 1 кГц
TWBR = ((F_CPU / 500000l) - 16) / 2; // Изменяем тактовую частоту i2c на 400 кГц
Astepper1.setAcceleration(6000.0);
Astepper1.setMaxSpeed(600);
Astepper1.setSpeed(600); // об/мин
// пока (switchIsOff) {
//поворот сервопривода в одном направлении -
//сообщаем сервоприводу, что это 0
}
void loop() {
// читаем входной контакт кнопки:
buttonState = digitalRead(buttonPin);
// сравниваем состояние кнопки с предыдущим состоянием
if (buttonState != lastButtonState) {
// если состояние изменилось, увеличиваем счетчик
if (buttonState == HIGH) {
// если текущее состояние ВЫСОКОЕ, то кнопка переключилась из выключенного состояния во включенное:
buttonPushCounter++;
Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(buttonPushCounter);
} else {
// если текущее состояние НИЗКОЕ, то кнопка переключилась из включенного состояния в выключенное:
Serial.println("off");
}
// сохраняем текущее состояние как последнее для следующего прохода цикла
lastButtonState = buttonState;
if (buttonPushCounter == 10 ) {
digitalWrite(ledPin, HIGH);
Astepper1.moveTo(20000);
Astepper1.setAcceleration(6000.0);
Astepper1.setSpeed(600);
//Astepper1.setSpeed(600);
Astepper1.run();
}
Astepper1.run();//эта команда вышла из оператора if, но все еще находится в цикле
if (buttonPushCounter == 30) {
digitalWrite(ledPin, LOW);
Astepper1.moveTo(200);
Astepper1.setSpeed(600);
}
Astepper1.run();//эта команда вышла из оператора if, но все еще находится в цикле
}
- Как я могу использовать степпер для определенной степени?
- Arduino uno + cnc Shield v3 + драйвер шагового двигателя A4988 + AccelStepper?
- Шаговый двигатель не поворачивается/не поворачивается против часовой стрелки
- Шаговый двигатель с концевыми выключателями
- Запустить два степпера одновременно
- Попытка понять постоянную скорость AccelStepper
- Шаговый двигатель - концевой выключатель положения
- Могу ли я запретить библиотеке Stepper удерживать двигатель?
Я думаю, проблема в том, что Astepper.run() не ждет, пока двигатель достигнет целевой позиции. Предполагается, что его следует вызывать очень часто, и он выполнит шаг, когда наступит подходящее время, и вернется, когда это не так. В вашем коде он перемещается ровно до тех пор, пока счетчик не увеличится в следующий раз, потому что тогда вы больше не будете вызывать метод run. Я сейчас не уверен. Напишу ответ, когда будет время проверить исходный код, @chrisl