Управление шаговым двигателем — отправка в определенные позиции по команде «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();
  }

  }
}

, 👍0

Обсуждение

Я думаю, проблема в том, что Astepper.run() не ждет, пока двигатель достигнет целевой позиции. Предполагается, что его следует вызывать очень часто, и он выполнит шаг, когда наступит подходящее время, и вернется, когда это не так. В вашем коде он перемещается ровно до тех пор, пока счетчик не увеличится в следующий раз, потому что тогда вы больше не будете вызывать метод run. Я сейчас не уверен. Напишу ответ, когда будет время проверить исходный код, @chrisl


2 ответа


0

В библиотеке AccelStepper есть несколько методов, похожих на run.

Тот, который вы используете, run(), предназначен для вызова при КАЖДОМ проходе через loop(), и он будет вызывать шаг только в том случае, если он необходим, на основе внутреннего состояния библиотеки (т. е. текущей позиции, целевой позиции, профиля ускорения и т. д.). Так часто вызывать безопасно — она определит сама, если есть какое-либо движение нужно.

Вы можете переместить вызов run() в место внутри loop(), но за пределами операторов if.

>

В качестве альтернативы существует функция runToPosition(), которая блокирует — она останавливает все выполнение вашего кода до тех пор, пока шаговый двигатель не окажется в целевой позиции. Это было бы хорошо для вашего текущего опубликованного кода, но если вы хотите также отслеживать счетчик оборотов, то это не лучший вариант.

,

1

Спасибо. Ваше описание неисправности имеет для меня смысл. Как вы заметили, блокировка будет проблемой, поскольку мне нужно, чтобы счетчик продолжал регистрироваться во время выполнения движения. Я переработал сценарий, как вы предлагаете - внутри цикла, но вне оператора 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, но все еще находится в цикле

  }
,