Maintain linear speed of stepper motor

55 views
Skip to first unread message

Robert Cole

unread,
Oct 15, 2025, 3:57:45 AM (12 days ago) Oct 15
to accelstepper
Hi All,
 I am stuck with a particular challenge:
I have a NEMA23 motor using the TMC2160 driver set at 8MRES.
The NEMA23 is geared to the shaft at 1:3 (motor pulley 20 tooth, shaft pulley 60 tooth).
The micro is the Arduino Mega 2560.

The NEMA23 motor pulls a reel of labels onto the shaft.
An optical sensor reads the labels as they are pulled through and I record the time, in milliseconds, between each label.

The challenge is that as the spool increases in diameter, the linear speed of the labels increases, as the time between labels decreases.

In order for the machine to remain in sync, I must maintain the linear speed of the labels by decreasing the speed of the motors with - setspeed() - as the time between each label decreases.

The initial start speed of the NEMA23 is -3500 (reverse running).
A typical duration between labels is 1900 milliseconds.

Do you have any idea as to how I can achieve the above?   

Mike McCauley

unread,
Oct 15, 2025, 6:18:14 AM (11 days ago) Oct 15
to accelstepper, Robert Cole

Hmmm,


sounds like a classic case of feedback controller. Measure the time for each label, compare to the required time, adjust the speed, possibly with the help a PID controller?

--

Mike McCauley           VK4AMM                   mi...@airspayce.com

Airspayce Pty Ltd 9 Bulbul Place Currumbin Waters QLD 4223 Australia  

http://www.airspayce.com                                 5R3MRFM2+X6

Phone +61 7 5598-7474


Robert Cole

unread,
Oct 15, 2025, 6:28:58 AM (11 days ago) Oct 15
to accelstepper
This is what I have running the first label:

new23speed: -4000.00
Steps: -5717
Duration: 2006.00

The next label will be about 
Duration: 1997.00

gjgsm...@gmail.com

unread,
Oct 15, 2025, 6:33:01 AM (11 days ago) Oct 15
to accelstepper
Hello Robert, 

(Iwas about to post this when Mike's reply appeared...)

There would be a couple of ways to achieve what you need but for me I think the easiest would a simple feedback routine to control the motor speed. As you already have the interval between labels to determine speed you can use you that to control motor speed.

I added a few lines to the constant speed example.
This code is untried and untested but could be a starting point.

```
#include <AccelStepper.h>

#define STEPPER_DIR_PIN 9
#define STEPPER_STEP_PIN 10
AccelStepper stepper(AccelStepper::DRIVER, STEPPER_STEP_PIN, STEPPER_DIR_PIN);

void setup()
{  
   stepper.setMaxSpeed(4000);
   stepper.setSpeed(3500);         // Swap two motor wire on the stepper motor to change direction.
   
   long set_interval = 1900; // The desired time interval between labels.  millis
   long labelInterval = 0;   // The measured time interval between labels.  millis
   float new_speed = 0;
   int speed_increment = 1;
}

void loop()
{   labelInterval = get_new_interval(); // Function to get the latest label interval time. (millis).

if(labelInterval < set_interval)
{
 new_speed = stepper.speed() - speed_increment)
}

   stepper.setSpeed(new_speed);  
   stepper.runSpeed();
}
```

Robert Cole

unread,
Oct 15, 2025, 6:45:18 AM (11 days ago) Oct 15
to accels...@googlegroups.com
Many thanks,
I will create a new sketch for your code and decrease the new label time in increments of 6 milliseconds.
Then output results.
Running out of labels for testing 🤬

--
You received this message because you are subscribed to the Google Groups "accelstepper" group.
To unsubscribe from this group and stop receiving emails from it, send an email to accelstepper...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/accelstepper/3f0cb741-555c-411f-8439-bdcde33d18efn%40googlegroups.com.

gjgsm...@gmail.com

unread,
Oct 15, 2025, 7:03:03 AM (11 days ago) Oct 15
to accelstepper
If you are refering to my example code then it's speed we are changing not label time. I would recommend leaving the  'speed_increment = 1' initially as stepper speed could change very rapidly as the code loops.
Naturally, a reset will be needed for each new roll or some code to reset the starting speed as needed.

Robert Cole

unread,
Oct 15, 2025, 7:40:33 AM (11 days ago) Oct 15
to accelstepper
Ok, I am running the following edited example of your code as a test.
I change the label interval - but the speed is not affected.
long set_interval = 1900;  // The desired time interval between labels.  millis
long labelInterval = 0;    // The measured time interval between labels.  millis
float new_speed = 0;
int speed_increment = 1;

float speedMotor = 4000;
long newLabelInterval = 1900;
int labelCount = 0;

void setup() {
  Serial.begin(115200);
}

void loop(){
 
  labelInterval = (newLabelInterval);  // Function to get the latest label interval time. (millis).

  if (labelInterval < set_interval) {
    new_speed = (speedMotor - speed_increment);
  }

  labelCount++;
  newLabelInterval = (newLabelInterval - 6);

  Serial.print("Label Count: ");
  Serial.println(labelCount);

  Serial.print("New Speed: ");
  Serial.println(new_speed);

  Serial.print("New Label Interval: ");
  Serial.println(newLabelInterval);

  Serial.println("----------------------");

  delay(1000);
}
My output is:

Label Count: 1
New Speed: 0.00
New Label Interval: 1894
----------------------
Label Count: 2
New Speed: 3999.00
New Label Interval: 1888
----------------------
Label Count: 3
New Speed: 3999.00
New Label Interval: 1882
----------------------
Label Count: 4
New Speed: 3999.00
New Label Interval: 1876
----------------------
Label Count: 5
New Speed: 3999.00
New Label Interval: 1870
----------------------
Label Count: 6
New Speed: 3999.00
New Label Interval: 1864
----------------------
Label Count: 7
New Speed: 3999.00
New Label Interval: 1858
----------------------
Label Count: 8
New Speed: 3999.00
New Label Interval: 1852
----------------------
Label Count: 9
New Speed: 3999.00
New Label Interval: 1846
----------------------
Label Count: 10
New Speed: 3999.00
New Label Interval: 1840
----------------------
Label Count: 11
New Speed: 3999.00
New Label Interval: 1834
----------------------
Label Count: 12
New Speed: 3999.00
New Label Interval: 1828
----------------------
Label Count: 13
New Speed: 3999.00
New Label Interval: 1822
----------------------
Label Count: 14
New Speed: 3999.00
New Label Interval: 1816
----------------------
Label Count: 15
New Speed: 3999.00
New Label Interval: 1810
----------------------
Label Count: 16
New Speed: 3999.00
New Label Interval: 1804
----------------------
Label Count: 17
New Speed: 3999.00
New Label Interval: 1798
----------------------
Label Count: 18
New Speed: 3999.00
New Label Interval: 1792
----------------------
Label Count: 19
New Speed: 3999.00
New Label Interval: 1786
----------------------
Label Count: 20
New Speed: 3999.00
New Label Interval: 1780
----------------------
Label Count: 21
New Speed: 3999.00
New Label Interval: 1774
----------------------
Label Count: 22
New Speed: 3999.00
New Label Interval: 1768
----------------------
Label Count: 23
New Speed: 3999.00
New Label Interval: 1762
----------------------

gjgsm...@gmail.com

unread,
Oct 15, 2025, 7:16:50 PM (11 days ago) Oct 15
to accelstepper
New Speed: 3999.00 is the give away. Your 'new_speed' formular cannot return any other result. (4000 - 1 = 3900)
More importantly nothing will work because you have removed all the Accelstepper library functions:
stepper.setMaxSpeed(4000);
stepper.speed()
stepper.setSpeed(new_speed);  
stepper.runSpeed();

Robert Cole

unread,
Oct 15, 2025, 7:49:25 PM (11 days ago) Oct 15
to accelstepper
Many thanks,
I removed all the Accelstepper library functions as my intention was to create a simulation of your code to reduce the motor speed as the duration interval increases.
The reason is that I do not have unlimited label stock to test.
Wow, it is 1:48am here and I am still banging my head.

Robert Cole

unread,
Oct 15, 2025, 8:19:27 PM (11 days ago) Oct 15
to accelstepper
I was wondering if this makes sense.
I know the label duration.
I have an initial start speed.
If I create a relationship factor between speed and duration.
(speedMotor / set_interval) (4000 / 1900) = 2.10526
Then: new_speed = (labelInterval * 2.10526)

Output:
Label Count: 1
New Speed: 0.00
New Label Interval: 1899
----------------------
Label Count: 2
New Speed: 3997.89
New Label Interval: 1898
----------------------
Label Count: 3
New Speed: 3995.78
New Label Interval: 1897
----------------------
Label Count: 4
New Speed: 3993.68
New Label Interval: 1896
----------------------
Label Count: 5
New Speed: 3991.57
New Label Interval: 1895
----------------------
Label Count: 6
New Speed: 3989.47
New Label Interval: 1894
----------------------
Label Count: 7
New Speed: 3987.36
New Label Interval: 1893
----------------------

Robert Cole

unread,
Oct 15, 2025, 8:22:09 PM (11 days ago) Oct 15
to accelstepper
Mike mentioned the use of a PID controller.
However, I have looked into this and cannot make sense of PID

gjgsm...@gmail.com

unread,
Oct 15, 2025, 10:40:53 PM (11 days ago) Oct 15
to accelstepper
A couple of points...
Because you are simulating label time interval and there are no other inputs you can test the code without the motor if you are just looking at the serial monitor. Obviously this means no need for any labels.

If you use a fixed relationship between label_interval and motor speed you will have no flexibility controlling the motor and it will probably be subject to cumulative error.

A feedback loop will be your best bet for the time being as it is simple to implement. The motor will automatically synchronise with the label speed because it will only step when the 'if' statement condition is met. The condition being that the measured time interval is less than the set time interval. If the 'condition' is met then a new_speed is required. The new_speed will be 1s/s less than the current speed (not a fixed speed). The 'current' speed will change everytime the 'condition' is met, this means the speed will always only change by 1s/s each time.
The feedback loop will react in milliseconds to changes in label speed as each label time interval is received. If the new_speed changes are not keeping up with the label speed then another if statement can be added to change the 'speed_increment' up or down as required.

Robert Cole

unread,
Oct 15, 2025, 11:40:08 PM (11 days ago) Oct 15
to accelstepper
OK.
Could you assist with the code - this is difficult for me to accomplish,

gjgsm...@gmail.com

unread,
Oct 16, 2025, 1:45:15 AM (11 days ago) Oct 16
to accelstepper
Ok but, it might take a day or two, time is limited.
Post here or email me the code that measures the time interval and updates a variable.
What are you using, it is an IR sensor and you're timing between pulses...?
Reply all
Reply to author
Forward
0 new messages