1

I'm trying to make a box that revolves around a pivot point using a NEMA17 stepper motor. The idea is straightforward: US1881 Hall effect sensor will change state based on magnets on the base of the box acting as an end stop, when the PIR sensor detects movement the stepper should move until the status of the Hall effect sensor changes, then wait 10 seconds before accepting any new movement.

I tried multiple times but something doesn't work. either the stepper won't move, or the trigger is not working properly, I assume there is an issue in the logic but I can't quite get it, and last attempt basically bricked the Arduino since RX and TX are always active.

This is the latest iteration of my code:

#include <AccelStepper.h>
// Define pins
#define HALL_SENSOR_PIN 2
#define PIR_SENSOR_PIN 3
#define STEP_PIN 4
#define DIR_PIN 5
// Create stepper object
AccelStepper stepper(1, STEP_PIN, DIR_PIN); // 1 is the half-step mode
// Define variables
volatile bool hallTriggered = false; // Interrupt flag
bool pirTriggered = false;
unsigned long pirStartTime = 0;
int motorState = 0; // 0: stopped, 1: moving forward, -1: moving backward
int cycleCount = 0;
bool initialMoveComplete = false; // Flag for initial movement
bool hallPreviousState; // Declare hallPreviousState globally
void setup() {
 pinMode(HALL_SENSOR_PIN, INPUT_PULLUP);
 pinMode(PIR_SENSOR_PIN, INPUT);
 attachInterrupt(digitalPinToInterrupt(HALL_SENSOR_PIN), hallInterrupt, CHANGE); // Interrupt on any state change
 stepper.setMaxSpeed(1000); // Adjust as needed
 stepper.setAcceleration(100); // Adjust as needed
 // Initial movement: Move until Hall sensor state changes
 hallPreviousState = digitalRead(HALL_SENSOR_PIN); // Initialize previous state
 while (digitalRead(HALL_SENSOR_PIN) == hallPreviousState) {
 stepper.run();
 }
 stepper.stop();
 motorState = 0;
}
void loop() {
 handlePIRTrigger();
 if (hallTriggered) {
 handleHallTrigger();
 hallTriggered = false; // Reset the interrupt flag
 }
 stepper.run();
}
void hallInterrupt() {
 hallTriggered = true;
}
void handlePIRTrigger() {
 if (digitalRead(PIR_SENSOR_PIN) == HIGH &&!pirTriggered && millis() - pirStartTime > 10000) {
 pirTriggered = true;
 if (motorState == 0) { // Only start moving if currently stopped
 motorState = 1;
 stepper.run(); // Start motor continuously
 }
 }
}
void handleHallTrigger() {
 if (motorState!= 0) { // If moving, stop immediately
 stepper.stop();
 motorState = 0;
 // Check for 4 cycles and reverse
 cycleCount++;
 if (cycleCount == 4) {
 cycleCount = 0;
 stepper.move(-stepper.currentPosition()); // Reverse direction using move()
 }
 pirTriggered = false; // Reset PIR trigger
 pirStartTime = millis(); // Start 10-second delay after Hall trigger
 }
}

The sensors are working correctly, I tested them in isolation, but they don't seem to play nicely together or I'm missing something.

This is how everything is connected:

Fritzing diagram

Greenonline
3,1527 gold badges36 silver badges48 bronze badges
asked Feb 12 at 6:45
4
  • Test the stepper motor separately. Maybe it is missing adequate power supply. Commented Feb 12 at 17:46
  • @liaifat85: Thanks for your input. It's powered by an external 12v 5A power supply, I don't think it's the stepper. I tested every part of the circuit independently, in separation they work. It's when you tie them together that they don't work as intended. Commented Feb 12 at 18:57
  • I see. Since parts are alright, I think you need to edit your code. Commented Feb 13 at 14:15
  • @liaifat85: Any suggestions? Commented Feb 13 at 19:32

2 Answers 2

1

Is the circuit diagram you provided an exact one? As far as I can see, it looks like the power line connections are missing. The HC-SR501 and US1881 have their power and GND connected to each other, but they are not connected to the Arduino Nano.

My fundamental advice is to first confirm that each sensor can be read properly and that the motor can be driven individually. After that, you should move on to considering the software logic. If you try to do everything at the same time, it will make troubleshooting much harder.

Edited

By your comment, I understand that the power is correctly wired and each element works individually. Now, let's check the logic.

Are you familiar with the AccelStepper library? stepper.run() is not for setting step count or position but acts as a scheduler, executing movement set by move() or moveTo().

In setup(), before calling stepper.run(), shouldn't you first specify movement with move() or moveTo()? Also, since loop() already calls stepper.run() every iteration, other functions don’t need to call it. In handlePIRTrigger(), what you likely need is move() or moveTo(), not run().

To summarize, stepper.run() should be called only in loop() as frequently as possible, while other functions should use move(), moveTo(), or stop().

Hope this helps!

answered Feb 12 at 11:25
3
  • Hi @Atsusui! They are connected to the 5V and GND of the arduino. I did test each individual element separately. They do work. The issue is when they are all placed together from what I see. Thanks for your input! Commented Feb 12 at 11:30
  • My answer is getting long, so I’ll edit the original post. Please check it again. Commented Feb 12 at 12:26
  • I wish I saw the long version! This definitely helps. I'll try some modifications and get back to you. Commented Feb 12 at 12:58
1

Note: This answer is and update with the code I wrote to get the result I'm seeking

With thanks to Atsushi Yokoyama, I had to rethink the whole logic of the sketch. I've rewritten the code realizing that I don't need to check the step count which meant that using AccelStepper is not necessary to accomplish this task.

The following code does exactly what I need, and I'm posting it in case someone needs it down the line:

// Pin Definitions
const int hallSensorPin = 2; // Hall effect sensor
const int pirSensorPin = 3; // PIR sensor
const int dirPin = 4; // Direction pin for A4988
const int stepPin = 5; // Step pin for A4988
// Variables
bool motorRunning = false; // Tracks if the motor is running
bool coolDownActive = false; // Tracks if the cool-down period is active
unsigned long coolDownStart = 0; // Tracks when the cool-down period started
unsigned long motorStartTime = 0; // Tracks when the motor started
int movementCount = 0; // Tracks the number of movements
bool directionForward = true; // Tracks the motor direction
bool checkForHigh = true; // Alternates between HIGH and LOW detection
void setup() {
 // Pin Modes
 pinMode(hallSensorPin, INPUT);
 pinMode(pirSensorPin, INPUT);
 pinMode(dirPin, OUTPUT);
 pinMode(stepPin, OUTPUT);
 pinMode(enablePin, OUTPUT);
 // Enable the motor driver
 digitalWrite(enablePin, LOW);
 // Initialize Serial for debugging
 Serial.begin(9600);
 Serial.println("System Initialized. Waiting for PIR trigger...");
}
void loop() {
 // Check if the motor is running
 if (motorRunning) {
 // Move the motor : Change the delay to control speed
 digitalWrite(stepPin, HIGH);
 delayMicroseconds(2500);
 digitalWrite(stepPin, LOW);
 delayMicroseconds(2500);
 // Check if the Hall effect sensor is triggered (end stop)
 // Only check after 1 second of motor movement
 if (millis() - motorStartTime >= 1000) {
 if ((checkForHigh && digitalRead(hallSensorPin) == HIGH) || 
 (!checkForHigh && digitalRead(hallSensorPin) == LOW)) {
 motorRunning = false; // Stop the motor
 movementCount++; // Increment movement count
 coolDownActive = true; // Start cool-down period
 coolDownStart = millis();
 Serial.println("Hall effect sensor triggered. Motor stopped.");
 Serial.print("Movement count: ");
 Serial.println(movementCount);
 // Reverse direction every 4 movements
 if (movementCount % 4 == 0) {
 directionForward = !directionForward;
 digitalWrite(dirPin, directionForward ? HIGH : LOW);
 Serial.println("Direction reversed.");
 }
 // Alternate between HIGH and LOW detection
 checkForHigh = !checkForHigh;
 Serial.print("Next Hall effect detection: ");
 Serial.println(checkForHigh ? "HIGH" : "LOW");
 Serial.println("Starting 10-second cool-down period...");
 }
 }
 } else {
 // Check if the cool-down period is active
 if (coolDownActive) {
 if (millis() - coolDownStart >= 10000) { // 10-second cool-down
 coolDownActive = false;
 Serial.println("Cool-down period ended. Ready for new PIR trigger.");
 }
 } else {
 // Check if the PIR sensor is triggered
 if (digitalRead(pirSensorPin) == HIGH) {
 motorRunning = true; // Start the motor
 motorStartTime = millis(); // Record the motor start time
 Serial.println("PIR sensor triggered. Motor started.");
 }
 }
 }
}

Thanks!

answered Feb 14 at 0:13

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.