Control stepper with optical limit switch

I am working on making a device to automate a tapping operation for some small metal parts. I have an Arduino Uno as the controller. I am using a NEMA 23 stepper motor with a TB6600 stepper controller (step and dir pins) This is attached to a round disc with cutouts for the metal parts that are to be tapped.

The stepper rotates 90 degrees, then a relay is activated which turns on the tapping head, then when the tappnig is finished (checked by a hall effect sensor), the table rotates 90 deg again and taps...etc. I have a homing function at startup that uses an optical sensor to detect the correct start position of the table (small slit in the table). There is a run/stop switch and pushbuttons to activate the tap or cycle the table independantly.

This all works as it is now. But what happens over time is the table starts to loose position. I think this is because there are ocassional burrs in the parts that sometimes get hung up as they slide on the table and that causes a missed step here or there. Eventually things get too far out of alignment. Seems that since I have an optical sensor for initially homing the table, I should use that to verify the table has moved to the correct position. But I'm struggling to think of how to integrate that into my sketch.

I have the code broken up into functions:
home(); performes the initial homing.
cycle(); rotates the stepper 50 steps (90 deg).
tap(); activates the relay that activates the tap.

The loop function then just checks the position of the sensors and buttons and calls the appropriate function.

The thing I can't get my head around is how to change the cycle function to use the optical sensor instead of just stepper.move(50);

Also, when the next cycle needs to start and the table needs to move again, the optical sensor will already be showing that the table is in the correct position. How do I move it until the optical sensor input (homeSwitch) goes low then stops on high again?

I was so proud of working out what I have so far...this seems like such a simple thing to get hung up on.

Here is the code:


#include <AccelStepper.h>
#include <LiquidCrystal_I2C.h>  // Library for LCD


//DEFINE PINS
//STEPPER PINS
const int stepPin = 2;
const int dirPin = 3;

//<<<-----INPUT PINS
const int runSwitch = 4;
const int tapSense = 5;
const int cycleButton = 7;
const int tapButton = 8;
const int homeSwitch = 9;

//------>>>OUTPUT PINS
const int tapRelay = 6;

//DECLARATIONS
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
LiquidCrystal_I2C lcd(0x27, 16, 2);  //I2C address, 16 column, 2 rows


//VARIABLES
int runState = 0;
int tapState = 0;
int cycleButtonState = 0;
int tapButtonState = 0;
int stepsMoved = 0;
int cycleCount = 0;
int homeState = 0;
long initial_homing = -1;

void setup() {
  //Pin Setups
  pinMode(runSwitch, INPUT_PULLUP);
  pinMode(tapSense, INPUT_PULLUP);
  pinMode(tapRelay, OUTPUT);
  pinMode(cycleButton, INPUT_PULLUP);
  pinMode(tapButton, INPUT_PULLUP);
  pinMode(homeSwitch, INPUT_PULLUP);

  //LCD Setup
  lcd.init();
  lcd.backlight();
  lcd.clear();

    // Stepper Settings
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(10000);
  stepper.setSpeed(1000);
  stepper.setCurrentPosition(0);

//HOME STEPPER
  home();

  //SET LCD TEXT
  lcd.setCursor(0, 1);
  lcd.print("CYCLE:");
}

void loop() {

  //READ SWITCHES SENSORS & BUTTONS
  runState = digitalRead(runSwitch);
  tapState = digitalRead(tapSense);
  cycleButtonState = digitalRead(cycleButton);
  tapButtonState = digitalRead(tapButton);

  //IF RUN=ON AND TAP=READY, CYCLE TABLE
  if (runState == LOW
      && tapState == LOW) {
    cycle();
  }
  //IF STEPPER HAS MOVED, RUN=IS ON, AND TAP=READY...ACTIVATE TAP
  if (stepper.distanceToGo() == 0
      && tapState == LOW
      && runState == LOW) {
    tap();
  }

  //IF RUN=OFF, AND TAP=READY, AND TAP BUTTON=PRESSED...ACTIVATE TAP
  if (runState == HIGH
      && tapState == LOW
      && tapButtonState == LOW) {
    tap();
  }

  //IF RUN=OFF, AND TAP=READY, AND CYCLE BUTTON=PRESSED...CYCLE TABLE
  if (runState == HIGH
      && tapState == LOW
      && cycleButtonState == LOW) {
    cycle();
  }
}

//------------------HOMING FUCNTION-----------------
void home() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("HOMING...");

  while (digitalRead(homeSwitch)) {
    stepper.moveTo(initial_homing);
    initial_homing--;
    stepper.run();
    delay(5);
  }

  stepper.setCurrentPosition(0);
  stepper.setMaxSpeed(100.0);  //set slower for better accuracy
  stepper.setAcceleration(100.0);
  initial_homing = 1;

  stepper.setCurrentPosition(0);

  lcd.clear();
  lcd.print("HOMING COMPLETED");
  delay(2000);
}


//----------------RUN CYCLE--------------------------
void cycle() {
  stepper.move(50);
  lcd.setCursor(0, 0);
  lcd.print("MOVING          ");
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }
  if (stepper.distanceToGo() == 0) {
    lcd.setCursor(0, 0);
    lcd.print("       ");
  }
}

//------------------TAPPING FUNCTION-------------------
void tap() {

  digitalWrite(tapRelay, HIGH);  //ACTIVATE TAP HEAD
  lcd.setCursor(0, 0);
  lcd.print("TAPPING");
  delay(1000);
  digitalWrite(tapRelay, LOW);
  cycleCount = cycleCount + 1;  //ADD 1 to CYCLE COUNT
  lcd.setCursor(7, 1);
  lcd.print(cycleCount);
  delay(1000);
}

Pic of the wiring schematic and a pic of the rotary table CAD:


Perhaps the slot you have is TOO LARGE. Or the slot edges are reflective. Or there is stray light getting to the sensor.

Surely you are not trying to power the stepper from Arduino Vcc, as the (also otherwise incorrect) wiring diagram suggests. Why does the diagram show an A4988 driver, when your post mentions TB6600?

Please post an accurate wiring diagram, with the correct parts and wiring clearly annotated.
Hand drawn is fine.

Correct, not trying to power the stepper from the arduino VCC. I was using Wokwi to work out the wiring and test the code so I used that screenshot. Wokwi only has that stepper driver to use so it's a stand in for the one I'm actually using. Those GND's and VCC's are just to get the simulation to work. They're wired separate from the Arduino in real life.

I only posted the wiring diagram because I thought I was supposed to. I thought I saw that in a sticky post on here someplace (maybe I didn't). I thought it was strongly suggested that you post a wiring diagram and your full code. But perhaps that is confusing in this case. There is nothing wrong with the wiring or connections.

The only thing I want to do is change the way I am moving the stepper 90 deg. Currently I am moving it by telling it to move 50 steps. That works the way I have it, but over time it looses position. What I want to do is have it move until the optical sensor senses a slot and then the stepper stops there. Similar to what I am doing in the homing routine. The only difference is that I am now going to start with the optical sensor reading High, then move the stepper until the senor is Low, then High again. I just can't get my head around how to do that. I'm sure it's simple...but I have very little programming experience. I'm shocked that I was able to get as far as I have. :slight_smile:

Is the sensor activated for only 1 motor step? In other words, is the sensor ON for step 50 and OFF for steps 49 and 51? Are the slots exactly 90 degrees (50 steps) apart? If after 50 steps the sensor is NOT ON, cancel the tap operation.

I don't know how many steps the slots cover. They are exactly 90 deg apart.

Yes, I could check the optical sensor before tapping and that would prevent the tap operation from happening while the parts are out of position. I was thinking that perhaps there's a better way to locate the position than just using the number of steps. Especially since the optical sensor is already there for homing.

You could step the motor until the sensor activates, but the sensor would have to "see" only 1 motor step at a time and the motor would have to stop instantly on that step. Can your motor do that?

So that's kind of what I was thinking. Step, check sensor, step again if needed.

That's kind of how the homing function works...so I think I can figure that out eventually. My biggest mental hurdle is how to start the motor stepping when it's starting with the sensor in the same condition as the stopping point. Like it needs to make a few steps, then start checking the sensor and stopping when it goes back high again (sensor=high when it detects the slot).

Ignore the sensor, take a few step to get off the sensor, then start watching for the sensor.

Your sensor should ONLY be active at ONE single motor step!

State change detection.*  For argument's sake let the processor see a LOW when a slot is under the sensor.  By some means the disc is started turning.  When this happens the slot signal will shortly go HIGH.  Keep turning until you see the slot signal go LOW again then stop.

The aim is to sense when the signal goes low, not when it is low.

* IDE -> file/examples/digital

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.