Nema 23, CNC shield, TMC2160, Solenoid, Proximity sensor pogram works but needs to be improved

Hi There,

I am working on a project that does the following so far:

  1. Switch a solenoid to disengage a pin
  2. Turn a NEMA 23 stepper motor clockwise for at least one rotation
  3. Senses a proximity sensor at a certain location
  4. Stops the motor
  5. Turns the motor back 60 steps onto it's homing position.
  6. Releases the solenoid

Everything works fine for now, but the motor turns extremely slow as I am not using any libraries to turn the motor at the homing procedure but instead switching the Dir and Step pins High and LOW so that I can check if the limit switch was triggered in between steps.

I was wondering if anyone could please assist me in fine tuning the code for better use.

I am using a Nema 23 stepper motor with a TBC2160 driver and CNC shield onto a Arduino Mega. I want this hardware setup to allow further upgrades in the future.

This is the code I have so far. Please note I know the basics and am not an advanced programmer.

#include <FlexyStepper.h>


//
// pin assignments
//

const int LED_PIN = 13;
const int MOTOR_X_STEP_PIN = 2;
const int MOTOR_X_DIR_PIN = 5;
const int STEPPERS_ENABLE_PIN = 8;
const int solenoidPin = 53; //This is the solenoid output pin on the Mega
#define home_switch 52 // Pin 52 connected to Proximity sensor used as limit switch

int steps;        // Used to set HOME position after Homing is completed

//
// create the stepper motor object
//

FlexyStepper stepperX;

void setup() 
{
  //
  // setup the LED pin and enable print statements
  //
  pinMode(LED_PIN, OUTPUT);
  pinMode(STEPPERS_ENABLE_PIN, OUTPUT);
  pinMode(solenoidPin, OUTPUT);

  
  Serial.begin(9600);


  //
  // connect and configure the stepper motor to its' IO pins
  //
  
  stepperX.connectToPins(MOTOR_X_STEP_PIN, MOTOR_X_DIR_PIN);
 

  //
  // enable the stepper motor
  //
  
  digitalWrite(STEPPERS_ENABLE_PIN, LOW);

  //
  // set the speed and acceleration rates for the stepper motor
  //
  
  //stepperX.setSpeedInStepsPerSecond(1000);
  //stepperX.setAccelerationInStepsPerSecondPerSecond(1000);

  digitalWrite(solenoidPin, HIGH); //Switch Solenoid ON

  delay(1000);
  
  //
  // Note Rotating the motor in the forward direction one revolution (200*8 steps) as the driver is set to this setting. 
 
  while (!digitalRead(home_switch)) { // Do this until the switch is activated

    digitalWrite(MOTOR_X_DIR_PIN, HIGH); 
    digitalWrite(MOTOR_X_STEP_PIN, LOW);
    delay(10);                       // More delay to slow even more while moving away from switch
    digitalWrite(MOTOR_X_STEP_PIN, HIGH);
    delay(10);
    
  }

  steps=0;  // Reset position variable to zero
  

    //stepperX.moveRelativeInSteps(-1660); // this could be used for a full rotation + 60 steps

  
Toolchanger();

   
}




void loop() 
{
  while (1) {          // not sure if a while loop is necessary here, but it does work
    if (steps > 0) {  //  To make sure the Stepper doesn't go beyond the Home Position

      digitalWrite(MOTOR_X_DIR_PIN, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
      digitalWrite(MOTOR_X_STEP_PIN, LOW);
      delay(1);
      digitalWrite(MOTOR_X_STEP_PIN, HIGH);
      delay(1);

    }      
  }
}

void Toolchanger()
{
  
  delay(1000);
  stepperX.moveRelativeInSteps(60); // move the stepper 60 steps anti-clockwise
  delay(1000);
  digitalWrite(solenoidPin, LOW); //Switch Solenoid OFF
  
}

I could find no data sheet for a TBC2160 stepper driver.

Those delays will result in 50 steps per second. If you want more speed, reduce the delays.

Most stepper driver step on the low to high transition or positive edge. So you do not need to keep the pulse high for more than about 20uS (microseconds). The speed is controlled by the duration of the low delay. See Robin2's simple stepper code.

1 Like

Thank you so much. I changed the delays to 1 and the problem was instantly solved. I have also taken a look at Robin2's simple stepper code. this will really help me a lot as I still need the motor to go to 12 specific positions from their previous positions.

1 Like

Also the TBC2160 was a typo the driver is a TMC2160. https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2160A-datasheet_Rev1.06.pdf

Here is a bit of code that may help. It will move a stepper to a number of pre-planned positions in a sequence and at selected speed. It uses AccelStepper library, but you can use that library or adapt to your choice.

#include <AccelStepper.h>

unsigned int xArray[] = {0, 900, 650, 400, 450, 100};
unsigned int xSpeeds[] = {200, 2000, 200, 100, 400, 50};
const unsigned int NUM_STEPS = sizeof(xArray) / sizeof(xArray[0]);

const byte stepPin = 2;
const byte dirPin = 5;
const byte enablePin = 8;

AccelStepper x_stepper(AccelStepper::DRIVER, stepPin, dirPin);

unsigned long betweenPositions = 200;

void setup()
{
   Serial.begin(115200);
   pinMode(enablePin, OUTPUT);
   digitalWrite(enablePin, LOW);
   x_stepper.setAcceleration(1000);
   x_stepper.setMaxSpeed(200);
   x_stepper.setSpeed(200);
   x_stepper.setCurrentPosition(0);
}

void loop()
{
   static unsigned int index = 0;
   if (x_stepper.run() == 0)
   {
      delay(betweenPositions);  //
      Serial.print(index);
      Serial.print("  ");
      Serial.print(xArray[index]);
      Serial.print("  ");
      Serial.println(xSpeeds[index]);
      x_stepper.moveTo(xArray[index]);
      x_stepper.setMaxSpeed(xSpeeds[index]);
      index++;
      if (index > (sizeof(xArray) / sizeof(xArray[0])))
      {
         Serial.println("*********** ARRAY SIZES MUST MATCH ********");
         index = 0;
      }
      if (index >= NUM_STEPS)
      {
         index = 0;
      }
   }
}
1 Like

This is perfect! Thank you so much!

what would be the best method to call each group of values in the array individually after a button was pressed or with a case sequence perhaps?

What does that mean? Do you mean to execute one position-speed pair for each button push?

That is correct yes. Each of the 12 positions need to be selected individually and it is divided exactly like a clocks numbering positions. say for instance i want to go to position 3 then upon pressing button 3 or getting a input for 3 it needs to go and stay at that position and the same for the rest.

You realize, you can't divide 200 steps by 12 evenly, each position would be 16.67 (16 2/3) steps. Is your motor geared or belted to whatever you are turning?

You make a fair point. I am using a driver with the micro step setting on 8*200 steps = 1600 steps per revolution. it does not have to be precisely exact when moving at first as the motor needs to run a bit further then it's final position for each place then turn back after it stopped , then seat with a ratchet mechanism into a pawl. I can just input the steps rounded off to the nearest number and and a few more steps to overshoot the position before turning back: for position1 = 133.33 = 133+60 and 2 = 266.66 = 267+60 and 3 = 399.99 = 400+60 etc. The driver has some sort of stall detection which I guess can somehow be utilized in Arduino?

So does that mean that there are 12 buttons?

getting a input for 3
From where?

So there is more than one motion of the stepper to reach a final position when the position changes. One (button) input would cause a train of movements leading to the final position?

So does that mean that there are 12 buttons?

I was thinking of using a 4X4 Matrix(16 KEY) membrane keypad for entering the designated position.

So there is more than one motion of the stepper to reach a final position when the position changes. One (button) input would cause a train of movements leading to the final position?

Yes 2 x movements for each input. Forward past the pawl and then backwards slightly to seat inside the pawl:

I have updated the quote and removed all the unnecessary stuff my two lines at the end of the setup does not seem to work, but the code you supplied for the array when it moves to the void loop works perfectly. What did I do wrong?

The two lines in the code are:

    x_stepper.moveTo(60); //Move backwards 60 steps? I think?
    x_stepper.setMaxSpeed(200);

And here is all of it I have commented out the void loop code for now:

#include <AccelStepper.h>

unsigned int xArray[] = {0, 900, 650, 400, 450, 100};
unsigned int xSpeeds[] = {200, 2000, 200, 100, 400, 50};
const unsigned int NUM_STEPS = sizeof(xArray) / sizeof(xArray[0]);

const byte stepPin = 2;
const byte dirPin = 5;
const byte enablePin = 8;

const int solenoidPin = 53; //This is the solenoid output pin
const int home_switch = 52; // Pin 52 connected to Home Switch (MicroSwitch)

AccelStepper x_stepper(AccelStepper::DRIVER, stepPin, dirPin);

unsigned long betweenPositions = 200;

void setup()
{
   Serial.begin(115200);
   pinMode(enablePin, OUTPUT);
   digitalWrite(enablePin, LOW);
   pinMode(solenoidPin, OUTPUT);

   digitalWrite(solenoidPin, HIGH); //Switch Solenoid ON

   delay(1000);
   
   while (!digitalRead(home_switch)) { // Do this until the switch is activated

    digitalWrite(dirPin, HIGH); 
    digitalWrite(stepPin, LOW);
    delay(5);                       // decrease the delay to increase the speed
    digitalWrite(stepPin, HIGH);
    delay(5);                       // decrease the delay to increase the speed
    
  }
  
   x_stepper.setAcceleration(1000);
   x_stepper.setMaxSpeed(200);
   x_stepper.setSpeed(200);
   x_stepper.setCurrentPosition(0);

  delay(200);
  
    x_stepper.moveTo(60); //Move backwards 60 steps? I think?
    x_stepper.setMaxSpeed(200);
}

void loop()
{
//   static unsigned int index = 0;
//   if (x_stepper.run() == 0)
//   {
//      delay(betweenPositions);  //
//      Serial.print(index);
//      Serial.print("  ");
//      Serial.print(xArray[index]);
//      Serial.print("  ");
//      Serial.println(xSpeeds[index]);
//      x_stepper.moveTo(xArray[index]);
//      x_stepper.setMaxSpeed(xSpeeds[index]);
//      index++;
//      if (index > (sizeof(xArray) / sizeof(xArray[0])))
//      {
//         Serial.println("*********** ARRAY SIZES MUST MATCH ********");
//         index = 0;
//      }
//      if (index >= NUM_STEPS)
//      {
//         index = 0;
//      }
//   }
}

You need x_stepper.run() in loop. That's where the actual stepping happens.

1 Like

Ok I see, thank you. how will I manage to make it move only once in the loop then? to home it basically.

You could home it in setup. While loop until distanceToGo is zero.

Thank you, I will try this. Except i am using x_stepper.setCurrentPosition(0); to zero the position and then from there i want to move 60 steps back and zero again as the home position. not sure how to implement this as the digitalWrite won't work? except maybe with a counter? I think I need to do some more research, learn more coding and get back on it as soon as I have a better understanding.

You stepped it to your home switch using digitalWrite. You can do the same thing to step away sixty steps rather than using the Accelstepper library..

So basically something like while(currentposition <> 60)
Then use the digital write again untill it reaches 60 steps then exit the loop and then zero everything again?

I'm not sure what you're doing with the library. You can step manually or you can use the library functions but I doubt you can intertwine them. You can do all your stepping with digitalWrite to get your initial position and then setCurrentPosition to zero and then switch over to accelStepper if you need to.

Personally, I find that library confusing so I usually just use digitalWrite and control the timing myself.