[solved] Indexing a stepper motor & stopping it with home switch in void setup()

Indexing a nema 17 stepper and stopping it with home switch in void setup()

Hi, the code below only works if the flag is already located in the photoelectric sensor when I power on the machine.

However, when I power it on and there is no flag it indexes continuously without stopping even after I insert the flag.

The enaPin should disable the stepper motor based on the driver that I have it connected to so I don't understand what the problem is.

Can someone please help as to why it continuously indexes even after I've inserted the flag into the sensor?

I implemented this based on what I found on the forums
(basically at each step it should check the high/low status of the sensor):

for (int x = 0; x < OneRev && OpticalLimitSwitchValue == LOW; x++)
/*
Plate rotates and stops rotating once it hits photoelectric switch
*/

// defines pins numbers
const int stepPin = 3;
const int dirPin = 4;
const int enaPin = 5;

const int shortPulse = 10;
const int stepIndexInterval = 4000;

const int OpticalLimitSwitch = 2;

const int OneRev = 6400;

void setup()
{
  Serial.begin(9600);

  // Sets pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enaPin, OUTPUT);

  pinMode(OpticalLimitSwitch, INPUT); // LOW --> No flag , HIGH --> Flag

  digitalWrite(enaPin, LOW);
  digitalWrite(dirPin, HIGH); // Enables the motor to move in a CW direction

  int OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);

  if ( OpticalLimitSwitchValue == LOW)
  {
    for (int x = 0; x < OneRev && OpticalLimitSwitchValue == LOW; x++)
    {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(shortPulse);                   // most stepper drivers just need a short pulse
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepIndexInterval);             // this value is the interval between steps
    }
  }
  else
  {
  digitalWrite(enaPin, HIGH);
  }
  delay(1000);
}

void loop()
{
}

You need to put the digitalRead() for the limit switch in a loop to constantly check it.
The way you have it now, it checks it once, then continues on, never to check it again.

The simple way to HOME a stepper motor is to move one step and check the limit switch. Repeat as needed.

If the motor is already at the HOME position it would be a good idea to move it away clear of the switch and then home it again.

...R

@evanmars

You need to put the digitalRead() for the limit switch in a loop to constantly check it.
The way you have it now, it checks it once, then continues on, never to check it again.

The issue I have is that I need it to home only once when I power on the machine.
After that I have repetitive cycles in the void loop () function and I want to avoid homing every cycle step.

@Robin2

Isn't this checking every step?

for (int x = 0; x < OneRev && OpticalLimitSwitchValue == LOW; x++)

I will attempt to do this with the code below and try it out right now:

The simple way to HOME a stepper motor is to move one step and check the limit switch. Repeat as needed.

/*
  Plate rotates and stops rotating once it hits photoelectric switch
*/

// defines pins numbers
const int stepPin = 3;
const int dirPin = 4;
const int enaPin = 5;

const int shortPulse = 10;
const int stepIndexInterval = 4000;

const int OpticalLimitSwitch = 2;

const int OneRev = 6400;

void setup()
{
  Serial.begin(9600);

  // Sets pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enaPin, OUTPUT);

  pinMode(OpticalLimitSwitch, INPUT); // LOW --> No flag , HIGH --> Flag

  digitalWrite(enaPin, LOW);
  digitalWrite(dirPin, HIGH); // Enables the motor to move in a CW direction

  int OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);

  for (int x = 0; x < OneRev; x++)
  {
    if (OpticalLimitSwitchValue == LOW)
    {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(shortPulse);                   // most stepper drivers just need a short pulse
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepIndexInterval);             // this value is the interval between steps
    }
    else
    {
      digitalWrite(enaPin, HIGH);
    }
  }
  delay(1000);
}

void loop()
{
}

knightridar:
Isn't this checking every step?

for (int x = 0; x < OneRev && OpticalLimitSwitchValue == LOW; x++)

No. You need a digitalRead() to get the value

...R

I did include this before the for loop:

int OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);

I tried the latest code below but I get the same situation.
It simply does not stop moving when I insert a flag into the sensor.

If I have the flag already inserted before startup it doesn't move after I remove the flag.
(this makes sense to me).

I wanted to keep things simple for this specific problem, but here is the full scenario:

Cycle steps:

  1. Machine powered on
  2. Index plate rotates once until it reaches home switch and then stops

This should happen continuously in loop:

  1. Two capacitive sensors are touched
  2. Stepper motor rotates 90 degrees
  3. Solenoid activates
  4. Solenoid deactivates

Full code for reference:

/*
  Cycle steps:
  1. Machine powered on
  2. Index plate rotates once until it reaches home switch and then stops

  This should happen continuously in loop:
  
  3. Two capacitive sensors are touched
  4. Stepper motor rotates 90 degrees
  5. Solenoid activates
  6. Solenoid deactivates

  Microsteps Wanted = (Wanted Angle/360) * Driver Micro Steps Setting
*/

// defines pins numbers
const int stepPin = 3;
const int dirPin = 4;
const int enaPin = 5;

const int shortPulse = 10;
const int shortStopPulse = 0;
const int stepInterval = 1000;
const int stepIndexInterval = 4000;

// When Sig Output is high, touch sensor is being pressed
#define CapacitiveTouchSensorLeft 11 // Pin for capacitive touch sensor
#define CapacitiveTouchSensorRight 12

const int OpticalLimitSwitch = 2;

const int IndexRev = 1600; //6400 pulses in revolution, 1600 pulses equal 25% revolution
const int OneRev = 6400;

int led = 13; // pin for the LED
int SolidStateRelay = 10; // pin for Solid State Relay

void setup()
{
  Serial.begin(9600);

  // Sets pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enaPin, OUTPUT);

  pinMode(CapacitiveTouchSensorLeft, INPUT);
  pinMode(CapacitiveTouchSensorRight, INPUT);

  pinMode(OpticalLimitSwitch, INPUT);

  pinMode(led, OUTPUT);
  pinMode(SolidStateRelay, OUTPUT);

  digitalWrite(led, LOW);
  digitalWrite(SolidStateRelay, LOW);
  Serial.println("Solenoid Inactive");

  digitalWrite(enaPin, LOW);
  digitalWrite(dirPin, HIGH); // Enables the motor to move in a CW direction

  int OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);

  for (int x = 0; x < OneRev; x++)
  {
    if (OpticalLimitSwitchValue == LOW)
    {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(shortPulse);                   // most stepper drivers just need a short pulse
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepIndexInterval);             // this value is the interval between steps
    }
    else
    {
      digitalWrite(enaPin, HIGH);
    }
  }
  delay(1000);
}

void loop()
{
  int CapacitiveTouchSensorLeftValue = digitalRead(CapacitiveTouchSensorLeft);
  int CapacitiveTouchSensorRightValue = digitalRead(CapacitiveTouchSensorRight);

  if (CapacitiveTouchSensorLeftValue && CapacitiveTouchSensorRightValue == HIGH)
  {
    digitalWrite(enaPin, LOW);
    digitalWrite(dirPin, HIGH); // Enables the motor to move in a CW direction
    {
      // Makes pulses for making 90 degree rotation
      for (int x = 0; x < IndexRev; x++)
      {
        digitalWrite(stepPin, HIGH);
        delayMicroseconds(shortPulse);                   // most stepper drivers just need a short pulse
        digitalWrite(stepPin, LOW);
        delayMicroseconds(stepInterval);             // this value is the interval between steps
      }
      
      delay(1000);

      digitalWrite(led, HIGH);
      digitalWrite(SolidStateRelay, HIGH);
      Serial.println("Solenoid Activated");

      delay(2000);

      digitalWrite(led, LOW);
      digitalWrite(SolidStateRelay, LOW);
      Serial.println("Solenoid Deactivated");

      delay(2000);
    }
  }
  else
  {
    digitalWrite(led, LOW);
    digitalWrite(SolidStateRelay, LOW);
    Serial.println("Solenoid Deactivated");
  }
}

I tried to do this, but it still didn't stop the indexer from rotating upon power up:

inserted this in between the stepper timings

OpticalLimitSwitchValue;

 int OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);

  for (int x = 0; x < OneRev; x++)
  {
    if (OpticalLimitSwitchValue == LOW)
    {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(shortPulse);                   // most stepper drivers just need a short pulse
      OpticalLimitSwitchValue;
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepIndexInterval);             // this value is the interval between steps
    }
    else
    {
      digitalWrite(enaPin, HIGH);
    }
  }

However, I know that this loop is being processed faster than I can react to insert a flag into the sensor.
I need to figure out how I can include it in a loop such that it will not constantly go to the home switch every time I run a cycle operation listed below. So somehow it needs to loop but only run once when I start up the machine. I'm wondering if adding a counter will help.

knightridar:
I did include this before the for loop:

int OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);

That's not much good when it should be inside the loop. digitalRead() does not keep updating itself - it only works once for each time it is called.

...R

Thanks so much!
I was unaware of this.
That fixed it.

For reference if anyone wants to use it.
Now I'll try to implement with Accelstepper library.

/*
  Plate rotates and stops rotating once it hits photoelectric switch
*/

// defines pins numbers
const int stepPin = 3;
const int dirPin = 4;
const int enaPin = 5;

const int OpticalLimitSwitch = 2;

const int shortPulse = 10;
const int stepIndexInterval = 16000; // longer interval --> slower RPM

const int OneRev = 6400;

void setup()
{
  Serial.begin(9600);

  // Sets pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enaPin, OUTPUT);

  pinMode(OpticalLimitSwitch, INPUT); // LOW --> No flag , HIGH --> Flag

  digitalWrite(enaPin, LOW);
  digitalWrite(dirPin, HIGH); // Enables the motor to move in a CW direction

  for (int x = 0; x < OneRev; x++)
  {
    uint8_t OpticalLimitSwitchValue = digitalRead(OpticalLimitSwitch);
    
    if (OpticalLimitSwitchValue == LOW)
    {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(shortPulse);                   // most stepper drivers just need a short pulse
      digitalWrite(stepPin, LOW);
      delayMicroseconds(stepIndexInterval);             // this value is the interval between steps
    }
    else
    {
      digitalWrite(enaPin, HIGH);
    }
  }
  delay(1000);
}

void loop()
{
}