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,152
  • 7
  • 36
  • 48
MDChaara
  • 207
  • 1
  • 3
  • 13

2 Answers2

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!

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 &gt;= 1000) {
  if ((checkForHigh &amp;&amp; digitalRead(hallSensorPin) == HIGH) || 
      (!checkForHigh &amp;&amp; digitalRead(hallSensorPin) == LOW)) {
    motorRunning = false; // Stop the motor
    movementCount++;     // Increment movement count
    coolDownActive = true; // Start cool-down period
    coolDownStart = millis();

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

    // Reverse direction every 4 movements
    if (movementCount % 4 == 0) {
      directionForward = !directionForward;
      digitalWrite(dirPin, directionForward ? HIGH : LOW);
      Serial.println(&quot;Direction reversed.&quot;);
    }

    // Alternate between HIGH and LOW detection
    checkForHigh = !checkForHigh;
    Serial.print(&quot;Next Hall effect detection: &quot;);
    Serial.println(checkForHigh ? &quot;HIGH&quot; : &quot;LOW&quot;);

    Serial.println(&quot;Starting 10-second cool-down period...&quot;);
  }
}

} 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!

MDChaara
  • 207
  • 1
  • 3
  • 13