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

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!

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!

Your Answer

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.