Stepper motors freezing after first position obtained through ethernet shield

I have a robotic arm-type setup with 3 28BYJ-48 stepper motors each driven by a ULN2003 board. I am using an Arduino Mega with an Arduino Ethernet 2 shield.
I am sending roll, pitch, and yaw coordinates from the FlightGear simulator through a router and reading it with the ethernet shield on the Arduino. I have tested this individually and it works fine.
The issue is when I try and connect the stepper motors to move to the position read by the ethernet port, the motors move to the first position and then freeze. I never had this issue with servo motors when I had the same setup but now I need stepper motors to get 360 degrees instead of the 180 provided by the micro servo.
What is even weirder is that I was having this issue last week. Then this morning I ran the code again and everything worked. And then when I came back after lunch, the issue restarted once more. So I am very confused as to what might be causing this issue. Does anyone have any suggestions?
Here is the current code. I am using the AccelStepper library for the stepper motors


#include <Ethernet.h>
#include <EthernetUdp.h>
#include <AccelStepper.h>

#define HALFSTEP 8
#define SOME_THRESHOLD 40

#define s1_1  30     // stepper 1, IN1 on ULN2003 
#define s1_2  31     // stepper 1, IN2 on ULN2003 
#define s1_3  32     // stepper 1, IN3 on ULN2003 
#define s1_4  33     // stepper 1, IN4 on ULN2003 

#define s2_1  50     // stepper 2, IN1 on ULN2003 
#define s2_2  51     // stepper 2, IN2 on ULN2003 
#define s2_3  52     // stepper 2, IN3 on ULN2003 
#define s2_4  53     // stepper 2, IN4 on ULN2003 

#define s3_1  40     // stepper 3, IN1 on ULN2003 
#define s3_2  41     // stepper 3, IN2 on ULN2003 
#define s3_3  42     // stepper 3, IN3 on ULN2003 
#define s3_4  43     // stepper 3, IN4 on ULN2003 

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0x48, 0xD3};
IPAddress ip(192, 168, 1, 177);

unsigned int localPort = 8888;      // local port to listen on

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged";        // a string to send back

// NOTE: The sequence 1-3-2-4 is required for proper sequencing of 28BYJ-48
AccelStepper stepper1(HALFSTEP, s1_1, s1_3, s1_2, s1_4);
AccelStepper stepper2(HALFSTEP, s2_1, s2_3, s2_2, s2_4);
AccelStepper stepper3(HALFSTEP, s3_1, s3_3, s3_2, s3_4);
int roll, pitch, yaw, map_roll, map_pitch, map_yaw, s1_orange, s2_yellow, s3_green;
int init_pos = 90;

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
  //Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);   // MKR ETH shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy++ 2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
  //Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet

  stepper1.setMaxSpeed(1000.0);
  stepper1.setAcceleration(100.0);
  stepper1.setSpeed(900);
  
  stepper2.setMaxSpeed(1000.0);
  stepper2.setAcceleration(100.0);
  stepper2.setSpeed(900);
  
  stepper3.setMaxSpeed(1000.0);
  stepper3.setAcceleration(100.0);
  stepper3.setSpeed(900);

  // start the Ethernet
  Ethernet.begin(mac, ip);

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start UDP
  Udp.begin(localPort);
}

void loop() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remote = Udp.remoteIP();
    for (int i=0; i < 4; i++) {
      Serial.print(remote[i], DEC);
      if (i < 3) {
        Serial.print(".");
      }
    }
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    //extract the roll pitch yaw values
    roll = atoi(strtok(packetBuffer, ","));
    pitch = atoi(strtok(NULL, ","));
    yaw = atoi(strtok(NULL, ","));

    Serial.print("FG Roll:");
    Serial.println(roll);
    Serial.print("FG Pitch:");
    Serial.println(pitch);
    Serial.print("FG Yaw:");
    Serial.println(yaw);
    
    s_setStepperTarget(stepper1, yaw);
    Serial.print("Stepper Yaw:");
    Serial.println(yaw);
    s_setStepperTarget(stepper2, map(roll, -180, 180, 0, 360));
    Serial.print("Stepper Roll:");
    Serial.println(map(roll, -180, 180, 0, 360));
    s_setStepperTarget(stepper3, map(pitch, -180, 180, 0, 360));
    Serial.print("Stepper Pitch:");
    Serial.println(map(pitch, -180, 180, 0, 360));

    // send a reply to the IP address and port that sent us the packet we received
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
    //Serial.println("here");
  }
  stepper1.run();
  stepper2.run();
  stepper3.run();
  //Serial.println("done running");
  
  delay(10);
}

void s_setStepperTarget(AccelStepper& stepper, int angle){
  //1024 is about a quarter of a turn so 4096 will be a full turn
  long newTarget = map(angle, 0, 360, 0, 4096);
  long currentTarget = stepper.targetPosition();

  // Calculate the shortest path to the new target
  long currentPosition = stepper.currentPosition();
  long distance = newTarget - currentPosition;
  if (abs(distance) > 2048) {
    if (distance > 0) {
      newTarget -= 4096;
    } else {
      newTarget += 4096;
    }
  }
  
  stepper.setCurrentPosition(currentPosition);
  stepper.moveTo(newTarget);
  Serial.println(stepper.currentPosition());
}

Welcome Katherine, Your code looks great, I did not go through it as I think it is OK. That freezing sounds like hardware and or EMI issues. Can you post an annotated schematic as you have wired it with links to technical information on each of the hardware items. Be sure to show all power sources and a note if power is being supplied by the USB. If you are using a breadboard be sure everything is tight. Also none of the motor power should go through either the Arduino or proto board. If you like post a picture of your setup. Good Luck.

You should remove that delay. The run() method af AccelStepper must be called as often as possible. You cannot achive the speed you set in setup() with that delay().

Stepper motors need constant, holding voltage. Stepper motors do not, and microservos use less power. Can you describe your power supply in watts (V*A) and your stepper motor requirements (watts)?

I am using an external power supply for the stepper motors. It is set to 11.5V and 2A (max) because the ULN2003 driver boards can take 5 to 12V inputs. The steppers only seem to be pulling about 1.5A. The power supply is connected to the power rails of a breadboard. All 3 stepper motors feed off the same supply. I have also connected the ground of the Arduino to the ground of the breadboard so they share the same one.
I have noticed that the motors run VERY hot. As in I cannot touch them for more than a second. Also, they have melted the 3D print they are encased in. It seems like that is not a good thing, but I don't get what I am doing wrong

Ok, I'll give that a try and see if it helps speed things up, because it is indeed very slow when it does run

Thanks! I didn't think it was a code issue but you never know.
I am not entirely sure how to do a schematic. I used to use Fritzing but now it's paid access so I don't have a tool on hand. But here are some pictures. It's pretty straightforward. I am using a breadboard to allow the 3 stepper motors to feed off of the same external power supply. The Arduino ground is connected to the power supply ground. The Arduino is powered through my laptop (I do have another power supply that will power the Arduino eventually but I need the serial monitor for debugging and verification purposes so it has to remain plugged into my laptop anyway)

If you remove the arms from the motors from the 3D printing and run the same sketch, do the motors still become as (very) hot?

Thanks for the good news, frizzing is going to cost hopefully many less will use it. Download KiCad, it is a full blown Computer Aided Design program that is resident on your machine and free to use, no fees. You can go from design to PCB. Your work is neat and you take great pictures but they do not help me as I am not familiar with the particular hardware parts you are using. Posting links to the hardware items may help us help you.

Motor ratings etc are important. Stepper motors will get warm as they constantly draw power. Supplying them with the appropriate power is important.

Hear is a link to the ULN2003 IC Hopefully you can understand some parts of it; https://www.st.com/resource/en/datasheet/uln2001.pdf. Looking on the first page you can see you cannot pull more than 500mA on a channel. You can parallel channels but there is also a package maximum. I have a feeling you may have fried your driver board. Start with only one motor and get it working first. You might consider ordering another driver and some motors, depending on your time constraints and lead times.

Keep us in the loop we are here to help.

I'll give that a try. They are very light though so I doubt that is the issue

So I found out why everything would just stop. I took a step back and tested the 2 parts individually, ethernet communication and stepper control, again (I had done that before combining them and they both worked). And it turns out that the Arduino could not "see" the ethernet shield. So I took it off and put it back on. And everything worked great! It happened again yesterday but simply taking the shield off and putting it back on solved the issue once again. I'm not sure why that happens but at least now I know that its a quick fix.
The motors still run VERY hot though. I will try taking the motors out of the prints like @xfpd suggested to see if that helps with the heat but I do really need that setup so I am not sure what to do

The small steppers that can be seen on your pictures are usually 5V steppers. There are 12V variants, but they are rare. Look at the back your steppers to see what variants they are. The voltage you must apply is not the voltage the ULN can withstand, but the rated voltage of your steppers. You may damage your steppers with 12V.
If they are 5V steppers you may set you PSU to 6V, because there is a voltage loss at the ULN.

From your description I think you probably need another arduino. The connectors on the Arduino are not the best and have started to wear out from repeated insertion and removal of items from them. It may be possible to put some antioxidant on the shield pins which may solve the problem for a while or replace the connectors themselves. You can cable from the Arduino to the shield, the jumper connector pins may be a bit larger.

The . Each channel of the ULN2003 is rated at 500 mA continuous and can withstand peak currents of 600 mA. Suppression diodes are included for inductive load , the common pin 9 needs to be connected to the motor +. This eliminates any need for external flyback diodes. The forward voltage drop is going to be about 1.5 Volts in each leg so you will drop 3 volts for the motor. I am assuming the 12V power is connected to the Vin connector. So the 5V requirement of the stepper and the 3V drop of the drivers equates to 8V. Adjusting your power supply to 8V should solve the heat problem.

Let us know how it is going.

It is not the weight of the arm, but the multiplied weight of the length of the arm that might be causing the motor to overheat. A stepper "at rest" is still using power to hold it still.

These motors are unipolar steppers, and the ULN is not a H.bridge. So the voltage drop is only 1.5V per coil. And because these motors must not be driven with more than 100mA ( the coil resistance is 50 Ohm ) its even less. So you should not use more than 6V from the PSU (Assuming that it is the 5V version)

But this current is not dependent on the load. Therefor the length of the arm doesn't matter. If it's too long, the stepper is simply too week and cannot hold it.

1 Like

As @MicroBahner suggested, I brought down the voltage to 6V and set the max current to 1.5A (just so that doesn't become the bottleneck, the steppers never pull that much current anyway) and it seems to have solved the intense overheating. The motors still run pretty hot but not nearly as much as before. I will have to wait until I get new 3D prints to see if they still run hot enough to melt the prints but I doubt it because they can now be touched for some time before it gets too hot and I have to remove my hand. Previously, I couldn't keep my fingers on the motor for more than a second, it was that hot.
The reason I increased the voltage in the first place was because the middle motor of my setup was really struggling with the load and all 3 motors were kind of sluggish. But removing the delay(10) like @MicroBahner also suggested seems to have solved that issue.
So as of right now, everything seems to work pretty well. I am noticing though that even with significant changes in the pitch, the middle motor barely ever moves. I am hoping that the issue is just with the prints being so loose I don't see the movements because if that isn't the issue I wouldn't know where to look, the code for each of the motors is the same and it works fine for the yaw and the roll. Another possible reason for the lack of movement is that since it is connected to a flight simulator it is hard to keep an intense pitch angle for a long time. The motors also have a delay with respect to the data coming in since they only move one step every loop iteration. Maybe the new pitch that is back to normal overrides the intense pitch change that was observed only for a short amount of time, not allowing the motor to make it to the intense pitch angle before the update. I'm wondering if there is a way to solve that latency...

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