Stepper motors issues

Hi all. I have an issue with my Stepper Motor/Controller. I am using the below part code. The full code have a transmitter controller, that sent Analog signals to 4 Receiver controllers via ESP-NOW.
I have a total of 12 Stepper Motors where I control 4 steppers per controller, but I operate max two steppers at any time between the controllers. I have a 5v 4A power supply to the 4 Receiver boards.
The issue is that the motors run to its set positions as intended but when it should return back to its start position it struggle.
I can hear the PWM signal but the motors jitter back and forward but do not reach its starting point.
I am using L298N mini driver boards.
Code:

#include <esp_now.h>
#include <WiFi.h>
#include <EEPROM.h>
#include <AccelStepper.h>

uint8_t incoming_mac1[] = {0xC0, 0x49, 0xEF, 0xD4, 0x58, 0x48};
uint8_t incoming_mac2[] = {0xe0, 0x5a, 0x1b, 0x6c, 0x8f, 0xf4}; 

typedef struct {
  int switch3;
  int switch4;
  int switch5;
  int switch6;
  int switch7;
  int switch8;
  int switch9;
  int switch10;
  int switch11;
  int switch12;
  int switch13;
  int switch14;
} struct1_message1;

typedef struct {
  float pedalA;
  float pedalB;
  float pedalC;
  float pedalD;
  float pedalE;
} struct2_message2;

typedef struct  {
  int LLValue;
  int RRValue;
  int switch1;
  int switch2;
} struct3_message3;

struct1_message1 myData1;
struct2_message2 myData2;
struct3_message3 myData3;

AccelStepper stepper1(AccelStepper::FULL4WIRE, 27, 14,13, 12);
AccelStepper stepper4(AccelStepper::FULL4WIRE, 15, 2,0 , 4);
AccelStepper stepper5(AccelStepper::FULL4WIRE, 16, 17,18,5);

const int potPin1 = 35;
const int potPin2 = 32;
const int potPin3 = 39; // Changed to a different pin

int val1 = 0;
int val2 = 0;
int val3 = 0;

long newval1 = 0;
long newval4 = 0;
long newval5 = 0;

void setup() {
 // Serial.begin(9600);
  stepper1.setMaxSpeed(2000); 
  stepper1.setAcceleration(1000);
  stepper4.setMaxSpeed(2000);
  stepper4.setAcceleration(1000);
  stepper5.setMaxSpeed(2000);
  stepper5.setAcceleration(1000);

  WiFi.mode(WIFI_STA);
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    return;}
  esp_now_register_recv_cb(OnDataRecv);
}
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {
    if (memcmp(mac_addr, incoming_mac1, 6) == 0) {
       // Serial.println("Data received from MAC1:");
       // Process data intended for mac1
        memcpy(&myData1, incomingData, sizeof(myData1));
    } else if (memcmp(mac_addr, incoming_mac2, 6) == 0) {
       // Serial.println("Data received from MAC2:");
        // Process data intended for mac2
        memcpy(&myData2, incomingData, sizeof(myData2));
    }
}

void loop() {
  val1 = analogRead(potPin1); // kneeData.LLValue
  val2 = analogRead(potPin2); // kneeData.RRValue

  myStepper.step(1);
  Serial.print("steps:");
  Serial.println(stepCount);
  stepCount++;
  delay(500);
  
  float pedalA = myData2.pedalA;
  float pedalB = myData2.pedalB;
  float pedalC = myData2.pedalC;
  float pedalD = myData2.pedalD;
  float pedalE = myData2.pedalE;

  /////////// STEPPER1 F# TO G
  if (pedalD > 0) {
    newval1 = map(pedalD, 0, 2023, 0, 100);
    stepper1.moveTo(newval1);
    stepper1.enableOutputs(); // Enable stepper
  } else {
    stepper1.disableOutputs(); // Disable stepper
  }

  /////////// STEPPER4  E TO F
  if (pedalE > 0) {
    newval4 = map(pedalE, 0, 2023, 0, 200);
    stepper4.moveTo(newval4);
    stepper4.enableOutputs(); // Enable stepper
  } else {
    stepper4.disableOutputs(); // Disable stepper
  }

 /*   /////////// STEPPER4  E TO F#
else if (val2 > 2200) {
    newval4 = map(val2, 2200, 4095, 0, 100); 
    stepper4.moveTo(newval4);
  }

    /////////// STEPPER4  E TO D#
else if (val2 < 2000) {
    newval4 = map(val2, 0, 2000, 0, -100);
    stepper4.moveTo(newval4);
  }*/

  /////////// STEPPER5  B TO C#
  if (val1 > 0) {
    newval5 = map(val1, 0, 950, 0, 200);
    stepper5.moveTo(newval5);
    stepper5.enableOutputs(); // Enable stepper
  } else {
    stepper5.disableOutputs(); // Disable stepper
  }

  // Update motors
  stepper1.runSpeedToPosition();
  stepper4.runSpeedToPosition();
  stepper5.runSpeedToPosition();
/*}

  Serial.print("  LL Knee : " + String(val1)); //Pin34
  Serial.println(" RR Knee : " + String(val2));//Pin18
  //Serial.print("  STRING 1 : " + String(myData1.switch5));//Pin1
  //Serial.print("  STRING 2 : " + String(myData1.switch6));
  Serial.print("  A : " + String(myData2.pedalA)); //Pin34
  Serial.print("  B : " + String(myData2.pedalB));//Pin18
  Serial.print("  C : " + String(myData2.pedalC));//Pin18
  Serial.print("  D : " + String(myData2.pedalD));//Pin18
  Serial.println("  E : " + String(myData2.pedalE));//Pin18
   //delay(50);*/
}

The L298N are H-Bridge parts and my experience with them are as DC motor controllers, not stepper motor controllers. Usually people use A4988 like parts for stepper motor control. Pololu - A4988 Stepper Motor Driver Carrier

I think the author is using 5v steppers similar to this:

Readily available for no money, and quite useful, my lidar uses one. But they are too weak clumsy to drive for use in 3d printers, cnc’s, etc…

Having used one I know they have a tendency to jitter and mis-step with a weak power supply. And they can draw a lot at peak when they start in motion. Enough to brown-out the ESP32.

I had massive issues on the lidar when I tried using it with a small (1A) phone charger with thin wires and a dodgy USB plug… Digging a better charger and cable out cured all that.

So, I suggest you need to sort out the PSU… 4A spread between 12 motors is not nearly enough. I think you need 4x as much.

If that is impractical, you should at least use heavy wiring for the supply and put a nice big capacitor (450u or more) across the supply as close to the stepper driver as possible to handle the transient current peaks.

1 Like

Ya I was thinking of those tiny stepper motors too but the OP is using the L298N for driving each stepper so has to be far larger steppers to use those drivers instead of the uln2003 driver which typically are sold with the little 28ybj-48 steppers.

Agreed that it’s likely a power issue and have seen those little breadboard jumper wires used to power stepper motors and wonder why they studder and jiggle instead of operate smoothly. They put really small wires in too many things these days. USB cable voltage drops have bit me many times.

I agree, but some do use it as Stepper drivers. The thing that does not make sense is that the stepper motors do go to its intended position without an issue. but fall over only on its way back.

If you have an O’scope you can start by looking at the L298n control signals and see if they are doing what’s needed to move the steppers backwards. Otherwise I’d be looking for a logic analyser to really look at whats happening.

Another option is to strip it down to one motor, one driver, one POT and see if you can get it going in both directions. I can’t imagine the motor driver library you are using isn’t bidirectional but you might check.

I do agree with you on the power supply. I will change it to a higher current value.

I connected a pot directly, by-passing the transmitter analog and it go a lot better but still seems to lose steps on its way back. I will try an A3967 EasyDriver and see how it go.

some of those ESPs don’t have lots of interrupts and the wireless is handled on the same CPU core as other stuff. Which ESP32 are you using since some are single core and some are multi-core?

Hi all thanks for your assistance. I changed the drivers to A3967 EasyDriver and it work, however. I it does not return to its starting position and also it run slower on its return. Any suggestions.
I am using the same input to make sure they all run the same before I set up the different inputs as intended. Code:

#include <WiFi.h>
#include <EEPROM.h>
#include <AccelStepper.h>

uint8_t incoming_mac1[] = {0xC0, 0x49, 0xEF, 0xD4, 0x58, 0x48};
uint8_t incoming_mac2[] = {0xe0, 0x5a, 0x1b, 0x6c, 0x8f, 0xf4}; 

typedef struct {
  int switch3;
  int switch4;
  int switch5;
  int switch6;
  int switch7;
  int switch8;
  int switch9;
  int switch10;
  int switch11;
  int switch12;
  int switch13;
  int switch14;
} struct1_message1;

typedef struct {
  float pedalA;
  float pedalB;
  float pedalC;
  float pedalD;
  float pedalE;
} struct2_message2;

typedef struct  {
  int LLValue;
  int RRValue;
  int switch1;
  int switch2;
} struct3_message3;

struct1_message1 myData1;
struct2_message2 myData2;
struct3_message3 myData3;

AccelStepper stepper1(AccelStepper::FULL2WIRE, 26, 27);
AccelStepper stepper2(AccelStepper::FULL2WIRE, 12, 13);
AccelStepper stepper3(AccelStepper::FULL2WIRE, 2, 15);
AccelStepper stepper4(AccelStepper::FULL2WIRE, 16 , 4);
AccelStepper stepper5(AccelStepper::FULL2WIRE, 18,5 );
AccelStepper stepper6(AccelStepper::FULL2WIRE, 22,21 );

const int potPin1 = 35;
const int potPin2 = 32;
const int OUTPUT_PIN2 = 2;
const int OUTPUT_PIN4 = 4;
const int OUTPUT_PIN5 = 5;
const int OUTPUT_PIN12 = 12;
const int OUTPUT_PIN13 = 13;
const int OUTPUT_PIN15 = 15;
const int OUTPUT_PIN16 = 16;
const int OUTPUT_PIN18 = 18;
const int OUTPUT_PIN21 = 21;
const int OUTPUT_PIN22 = 22;
int val1 = 0;
int val2 = 0;
int val3 = 0;
long newval1 = 0;
long newval2 = 0;
long newval3 = 0;
long newval4 = 0;
long newval5 = 0;
long newval6 = 0;

void setup() {
 // Serial.begin(9600);
  stepper1.setMaxSpeed(8000); 
  stepper1.setAcceleration(500);
  stepper2.setMaxSpeed(8000); 
  stepper2.setAcceleration(500);
  stepper3.setMaxSpeed(8000); 
  stepper3.setAcceleration(500);
  stepper4.setMaxSpeed(8000);
  stepper4.setAcceleration(500);
  stepper5.setMaxSpeed(8000);
  stepper5.setAcceleration(500);
  stepper6.setMaxSpeed(8000);
  stepper6.setAcceleration(500);
 
  WiFi.mode(WIFI_STA);
  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    return;}
  esp_now_register_recv_cb(OnDataRecv);
}
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {
    if (memcmp(mac_addr, incoming_mac1, 6) == 0) {
       // Serial.println("Data received from MAC1:");
       // Process data intended for mac1
        memcpy(&myData1, incomingData, sizeof(myData1));
    } else if (memcmp(mac_addr, incoming_mac2, 6) == 0) {
       // Serial.println("Data received from MAC2:");
        // Process data intended for mac2
        memcpy(&myData2, incomingData, sizeof(myData2));
    }
}

void loop() {
  val1 = analogRead(potPin1); // kneeData.LLValue
  val2 = analogRead(potPin2); // kneeData.RRValue

  float pedalA = myData2.pedalA;
  float pedalB = myData2.pedalB;
  float pedalC = myData2.pedalC;
  float pedalD = myData2.pedalD;
  float pedalE = myData2.pedalE;

  /////////// STEPPER1 F# TO G
  if (val1 > 0) {
    newval1 = map(val1, 0, 4000, 0, 100);
    stepper1.moveTo(newval1);
    stepper1.enableOutputs(); // Enable stepper
  } else {
    stepper1.disableOutputs(); // Disable stepper
  }

  /////////// STEPPER2  E TO F
  if (val1 > 0) {
    newval2 = map(val1, 0, 4000, 0, 100);
    stepper2.moveTo(newval2);
    stepper2.enableOutputs(); // Enable stepper
  } else {
    stepper2.disableOutputs(); // Disable stepper
  }

  /////////// STEPPER3  E TO F
  if (val1 > 0) {
    newval3 = map(val1, 0, 4095, 0, 100);
    stepper3.moveTo(newval3);
    stepper3.enableOutputs(); // Enable stepper
  } else {
    stepper3.disableOutputs(); // Disable stepper
  }

  /////////// STEPPER4  E TO F
  if (val1 > 0) {
    newval4 = map(val1, 0, 4095, 0, 100);
    stepper4.moveTo(newval4);
    stepper4.enableOutputs(); // Enable stepper
  } else {
    stepper4.disableOutputs(); // Disable stepper
  }

/////////// STEPPER5  B TO C#
if (val1 > 0) {
    newval5 = map(val1, 0, 4095, 0, 100); // Adjust the max value to 4095 if necessary
    stepper5.moveTo(newval5);
    stepper5.enableOutputs(); // Enable stepper
} else {
    stepper5.disableOutputs(); // Disable stepper
}

/////////// STEPPER6  B TO C#
if (val1 > 0) { 
    newval6 = map(val1, 0, 4095, 0, 100); 
    stepper6.moveTo(newval6);
    stepper6.enableOutputs(); // Enable stepper
} else {
    stepper6.disableOutputs(); // Disable stepper
}

  // Update motors
  stepper1.runSpeedToPosition();
  stepper2.runSpeedToPosition();
  stepper3.runSpeedToPosition();
  stepper4.runSpeedToPosition();
  stepper5.runSpeedToPosition();
  stepper6.runSpeedToPosition();
  
  }
 // Serial.print("  LL Knee : " + String(val1)); //Pin34
  //Serial.println(" RR Knee : " + String(val2));//Pin18
 /* //Serial.print("  STRING 1 : " + String(myData1.switch5));//Pin1
  //Serial.print("  STRING 2 : " + String(myData1.switch6));
  Serial.print("  A : " + String(myData2.pedalA)); //Pin34
  Serial.print("  B : " + String(myData2.pedalB));//Pin18
  Serial.print("  C : " + String(myData2.pedalC));//Pin18
  Serial.print("  D : " + String(myData2.pedalD));//Pin18
  Serial.println("  E : " + String(myData2.pedalE));//Pin18
   //delay(50);*/
//}

@jdebruyn You are trying to do a lot here, and I wonder if you are simply hitting limitations of the library (as well as still hitting power supply issues?)

Have you read: AccelStepper - The Missing Manual | Hackaday.io ??

I can’t dig into this in detail; but I notice there that the author talks about missed steps and other issues under certain situations such as setting max speeds too high.

There is no real support forum for accelstepper any more (it was on google groups) but you may get more knowledgeable replies asking in the Arduino forums.

For testing I narrowed it down to one stepper but still the same. But thanks for the link I did go through it but will do it again, I must be doing something wrong. Thanks

I use a ESP32S Board with a dual CPU. I actually only use one CPU now that I’m thinking about it. I never had a code where I used both, do you know how to modify the code to use one for the WiFi and one for the rest?

There should be a number associated with that like ESP32S3(dual core) or ESP32S2(single core). Sounds like your problem might not be interrupt based if it works fine in one direction but not the other. I would also take Owen’s advice and besides dropping the acceleration and speed parameters down considerably, look into the docs of the library to see how or what’s different about reverse direction.
And make sure you have your motor windings setup correctly. a1-a2 and b1-b2

1 Like

The controllers only show the S, I will dig further though. I agree the fault I think is within the code, but I don’t know how to fix it. Looking at the command
if (pedalD > 0) {
newval1 = map(pedalD, 0, 2023, 0, 100);
stepper1.moveTo(newval1);
stepper1.enableOutputs(); // Enable stepper
} else {
stepper1.disableOutputs(); // Disable stepper
}

It state that, " padalD value is >0 " the steppers do respond correctly but if I return the padalD value to below 0 the stepper still on its way don’t know what to do as the value is below the starting point.
I ran different commands, but I guess I did not do it the right way I guess.
I am actually building my second Electro Steel guitar. The first one I used servo motors, which still working fine after more than a year. This guitar will work slightly different thus the reason I use steppers this time. Attach photo’s of the first (Bottom) and second (Top) which is 50% complete.

If PedalD value is supposed to be positive and/or negative, it’s a float so I expect so, then clearly the code is not handling the case when the value is 0 or below.

When PedalD is positive you are mapping the value to a range the stepper driver library wants. ie
newval1 = map(pedalD, 0, 2023, 0, 100);
maps a number from 0-2023 into the range of 0-100

If you’ve verified that PedalD value is correctly representing the position changes, ie going to the correct positive movement position and representing the correct negative/reverse movement position then try mapping to negative values.
ie newval1 = map(pedalD, 0, -2023, 0, -100);
You might have to determine when you are moving the POT backwards(counterclockwise?) and set your PedalD value appropriately(PedalD=PedalD*-1)

Does that sound like the missing link?

I suspect dougl is correct about the missing case where PedalD less than or equal to zero. I would suggest either of the following:

If (PedalD > 0)
{


}
else
{


}

Or possibly:

If (PedalD >= 0)
{


}
else
{


}

Or, if zero should always be ignored:

If (PedalD > 0)
{


}
else if (PedalD < 0)
{


}

Thanks for the help. I ended up using the suggested and it is working now.
** if (pedalA <= newval4) { **
However I ran into another issue. I need pedalA to move stepper4 for 1000 steps which is working thanks to your help. but I also need pedalC to move stepper4 which does not work. I asume that stepper4 is already driven 0speed by pedalA, so pedalC cannot drive it. I using the below non functional code and hope you can get me out of this issue.

** /////////// STEPPER4/String3 B TO C#
if (pedalA > 0) {
newval4 = map(pedalA, 0, 4095, 0, 1000); {
stepper4.moveTo(newval4);
stepper4.runSpeedToPosition();}
(pedalA <= newval4); {
stepper4.moveTo(newval4);
stepper4.runSpeedToPosition();}
}
else if (pedalC > 0) {
newval4 = map(pedalC, 0, 4095, 0, -1000);{
stepper4.moveTo(newval4);
stepper4.runSpeedToPosition();}
if (pedalC <= newval4); {
stepper4.moveTo(newval4);
stepper4.runSpeedToPosition();}
} **

Look at your logic and walk through using values you made up for PedalA and for PedalC and then step through the code using those values and watch for what you are setting the newval4 to based on your map() settings.