Управление шаговым двигателем с помощью 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-секундную задержку после срабатывания датчика Холла
}
}
Датчики работают правильно, я тестировал их по отдельности, но, похоже, они плохо работают вместе, или я что-то упускаю.
Вот как все связано:

@MDChaara, 👍1
Обсуждение2 ответа
Лучший ответ:
Точная ли схема, которую вы предоставили? Насколько я вижу, на ней отсутствуют соединения линии питания. У 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
Примечание: этот ответ — это обновление с кодом, который я написал для получения нужного мне результата
Благодаря Ацуши Ёкояме мне пришлось переосмыслить всю логику скетча. Я переписал код, понимая, что мне не нужно проверять количество шагов, а значит, использование 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.");
}
}
}
}
Спасибо!
- В чем отличие датчика Холла от индуктивного?
- Как заставить Arduino Nano управлять шаговым двигателем с помощью Firmata
- Перегорают ли мои шаговые двигатели? В чем здесь проблема?
- Запутанная реакция степпера на увеличение delayMicroseconds()
- Не удалось получить показания для "Двигателя с энкодером"
- Выбираю мотор для своего проекта
- avrdude ser_open() can't set com-state
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
Проверьте шаговый двигатель отдельно. Возможно, ему не хватает питания., @liaifat85
@liaifat85: Спасибо за ваш ответ. Он питается от внешнего источника питания 12 В 5 А, не думаю, что дело в шаговом двигателе. Я проверил каждую часть схемы по отдельности, по отдельности они работают. А вот когда их соединяешь вместе, они не работают как надо., @MDChaara
Понятно. Поскольку с деталями всё в порядке, думаю, тебе нужно отредактировать код., @liaifat85
@liaifat85: Есть предложения?, @MDChaara