Управление шаговым двигателем с помощью PIR и датчика Холла

Я пытаюсь сделать коробку, вращающуюся вокруг точки опоры, используя шаговый двигатель NEMA17. Идея проста: датчик Холла US1881 будет менять состояние в зависимости от магнитов в основании коробки, действующих как концевой упор. Когда PIR-датчик обнаруживает движение, шаговый двигатель должен двигаться до тех пор, пока не изменится состояние датчика Холла, а затем подождать 10 секунд, прежде чем принимать новое движение.

Я пробовал несколько раз, но что-то не работает. Либо шаговый двигатель не двигается, либо триггер не работает должным образом. Я предполагаю, что проблема в логике, но не могу ее понять. Последняя попытка фактически вывела Arduino из строя, поскольку RX и TX всегда активны.

Это последняя версия моего кода:

#include <AccelStepper.h>

// Определить контакты
#define HALL_SENSOR_PIN 2
#define PIR_SENSOR_PIN 3
#define STEP_PIN 4
#define DIR_PIN 5

// Создать объект степпера
AccelStepper stepper(1, STEP_PIN, DIR_PIN); // 1 — полушаговый режим

// Определить переменные
volatile bool hallTriggered = false; // Флаг прерывания
bool pirTriggered = false;
unsigned long pirStartTime = 0;
int motorState = 0; // 0: остановлен, 1: движется вперед, -1: движется назад
int cycleCount = 0;
bool initialMoveComplete = false; // Флаг начального движения
bool hallPreviousState; // Объявляем hallPreviousState глобально

void setup() {
  pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
  pinMode(PIR_SENSOR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(HALL_SENSOR_PIN), hallInterrupt, CHANGE); // Прерывание при любом изменении состояния

  stepper.setMaxSpeed(1000); // Отрегулируйте по мере необходимости
  stepper.setAcceleration(100); // Отрегулируйте по мере необходимости

  // Начальное движение: Двигаться до тех пор, пока не изменится состояние датчика Холла
  hallPreviousState = digitalRead(HALL_SENSOR_PIN); // Инициализируем предыдущее состояние
  while (digitalRead(HALL_SENSOR_PIN) == hallPreviousState) {
    stepper.run();
  }
  stepper.stop();
  motorState = 0;
}

void loop() {
  handlePIRTrigger();

  if (hallTriggered) {
    handleHallTrigger();
    hallTriggered = false; // Сбросить флаг прерывания
  }
  stepper.run();
}

void hallInterrupt() {
  hallTriggered = true;
}

void handlePIRTrigger() {
  if (digitalRead(PIR_SENSOR_PIN) == HIGH &&!pirTriggered && millis() - pirStartTime > 10000) {
    pirTriggered = true;
    if (motorState == 0) { // Начинать движение только если в данный момент остановлен
      motorState = 1;
      stepper.run(); // Непрерывный запуск двигателя
    }
  }
}

void handleHallTrigger() {
  if (motorState!= 0) { // Если движется, немедленно остановитесь
    stepper.stop();
    motorState = 0;

    // Проверка на 4 цикла и обратный ход
    cycleCount++;
    if (cycleCount == 4) {
      cycleCount = 0;
      stepper.move(-stepper.currentPosition()); // Изменить направление с помощью move()
    }

    pirTriggered = false; // Сброс триггера PIR
    pirStartTime = millis(); // Запустить 10-секундную задержку после срабатывания датчика Холла
  }
}

Датчики работают правильно, я тестировал их по отдельности, но, похоже, они плохо работают вместе, или я что-то упускаю.

Вот как все связано:

Диаграмма Фритцинга

, 👍1

Обсуждение

Проверьте шаговый двигатель отдельно. Возможно, ему не хватает питания., @liaifat85

@liaifat85: Спасибо за ваш ответ. Он питается от внешнего источника питания 12 В 5 А, не думаю, что дело в шаговом двигателе. Я проверил каждую часть схемы по отдельности, по отдельности они работают. А вот когда их соединяешь вместе, они не работают как надо., @MDChaara

Понятно. Поскольку с деталями всё в порядке, думаю, тебе нужно отредактировать код., @liaifat85

@liaifat85: Есть предложения?, @MDChaara


2 ответа


Лучший ответ:

1

Точная ли схема, которую вы предоставили? Насколько я вижу, на ней отсутствуют соединения линии питания. У HC-SR501 и US1881 питание и земля соединены друг с другом, но они не подключены к Arduino Nano.

Мой главный совет — сначала убедиться, что показания каждого датчика считываются корректно, а двигатель может управляться индивидуально. После этого следует перейти к рассмотрению логики программного обеспечения. Если вы попытаетесь сделать всё одновременно, это значительно затруднит поиск и устранение неисправностей.

Отредактировано

Судя по вашему комментарию, я понимаю, что питание подключено правильно, и каждый элемент работает независимо. Теперь давайте проверим логику.

Вы знакомы с библиотекой AccelStepper? stepper.run() не предназначен для задания количества шагов или положения, а действует как планировщик, выполняя движение, заданное функцией move() или moveTo().

В setup(), перед вызовом stepper.run(), разве не следует сначала указать движение с помощью move() или moveTo()? Кроме того, поскольку loop() уже вызывает stepper.run() на каждой итерации, другим функциям не нужно его вызывать. В handlePIRTrigger() вам, скорее всего, нужно move() или moveTo(), а не run().

Подводя итог, stepper.run() следует вызывать только в loop() как можно чаще, в то время как другие функции должны использовать move(), moveTo() или stop().

Надеюсь, это поможет!

,

Привет, @Atsusui! Они подключены к 5 В и GND Arduino. Я проверил каждый элемент отдельно. Они работают. Проблема, насколько я вижу, возникает, когда они все соединены вместе. Спасибо за ваш ответ!, @MDChaara

Мой ответ становится слишком длинным, поэтому я отредактирую исходное сообщение. Пожалуйста, проверьте его ещё раз., @Atsushi Yokoyama

Жаль, что я не увидел полную версию! Это определённо помогает. Попробую внести некоторые изменения и отпишусь., @MDChaara


1

Примечание: этот ответ — это обновление с кодом, который я написал для получения нужного мне результата

Благодаря Ацуши Ёкояме мне пришлось переосмыслить всю логику скетча. Я переписал код, понимая, что мне не нужно проверять количество шагов, а значит, использование AccelStepper для решения этой задачи необязательно.

Следующий код делает именно то, что мне нужно, и я публикую его на случай, если он кому-то понадобится:

// Определения контактов
const int hallSensorPin = 2;    // Датчик Холла
const int pirSensorPin = 3;     // ПИР-датчик
const int dirPin = 4;           // Направляющий контакт для A4988
const int stepPin = 5;          // Шаговый вывод для A4988

// Переменные
bool motorRunning = false;      // Отслеживает, работает ли двигатель
bool coolDownActive = false;    // Отслеживает, активен ли период охлаждения
unsigned long coolDownStart = 0; // Отслеживает начало периода охлаждения
unsigned long motorStartTime = 0; // Отслеживает момент запуска двигателя
int movementCount = 0;          // Отслеживает количество перемещений
bool directionForward = true;   // Отслеживает направление двигателя
bool checkForHigh = true;       // Поочередно определяет HIGH и LOW

void setup() {
  // Режимы фиксации
  pinMode(hallSensorPin, INPUT);
  pinMode(pirSensorPin, INPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(enablePin, OUTPUT);

  // Включить драйвер двигателя
  digitalWrite(enablePin, LOW);

  // Инициализируем последовательный порт для отладки
  Serial.begin(9600);
  Serial.println("System Initialized. Waiting for PIR trigger...");
}

void loop() {
  // Проверяем, работает ли двигатель
  if (motorRunning) {
    // Перемещаем мотор: меняем задержку для управления скоростью
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2500);

    // Проверяем, сработал ли датчик Холла (конечный упор)
    // Проверяйте только через 1 секунду после начала движения двигателя
    if (millis() - motorStartTime >= 1000) {
      if ((checkForHigh && digitalRead(hallSensorPin) == HIGH) || 
          (!checkForHigh && digitalRead(hallSensorPin) == LOW)) {
        motorRunning = false; // Остановить двигатель
        movementCount++;     // Увеличить счетчик движений
        coolDownActive = true; // Начать период охлаждения
        coolDownStart = millis();

        Serial.println("Hall effect sensor triggered. Motor stopped.");
        Serial.print("Movement count: ");
        Serial.println(movementCount);

        // Менять направление каждые 4 движения
        if (movementCount % 4 == 0) {
          directionForward = !directionForward;
          digitalWrite(dirPin, directionForward ? HIGH : LOW);
          Serial.println("Direction reversed.");
        }

        // Поочередно между ВЫСОКИМ и НИЗКИМ обнаружением
        checkForHigh = !checkForHigh;
        Serial.print("Next Hall effect detection: ");
        Serial.println(checkForHigh ? "HIGH" : "LOW");

        Serial.println("Starting 10-second cool-down period...");
      }
    }
  } else {
    // Проверяем, активен ли период охлаждения
    if (coolDownActive) {
      if (millis() - coolDownStart >= 10000) { // 10-секундное охлаждение
        coolDownActive = false;
        Serial.println("Cool-down period ended. Ready for new PIR trigger.");
      }
    } else {
      // Проверяем, сработал ли ИК-датчик
      if (digitalRead(pirSensorPin) == HIGH) {
        motorRunning = true; // Запустить двигатель
        motorStartTime = millis(); // Записываем время запуска двигателя
        Serial.println("PIR sensor triggered. Motor started.");
      }
    }
  }
}

Спасибо!

,