Forum Rule: Always post complete source code & details to reproduce any issue!

# Thread: New Stepper Motor Library

1. I just released version 2 of TeensyStep on GitHub

New features:
• Improved rotational mode
• Possibility to override speed and acceleration of a group of motors on the fly (rotational mode only)
• Callback when a target is reached

I also started a small documentation page which can be found here: https://luni64.github.io/TeensyStep/

2. Hi Luni
I wonder if you could give me some advice on my project?
I have a carriage on a 6m long guide. The carriage is pulled by a 8Nm stepper power by a 48v supply. The stepper has a 1:2 reduction and the looped belt has a ratio of 1:0.6. The carriage will move about 400mm per revolution of the motor.
The objective:
I have to accelerate the carriage in the first 2m to 8m/s then maintain that for 2m and then decelerate for the last 2m. This is done both ways.

I am having problems conceptualizing how to use the library to achieve this. If the acceleration could be specified for a distance or a duration, then it could be done.

3. @luni — just wondering if the library will work with the new Teensy 4.0

4. Sorry, not yet. The timers of the T4 behave differently from those of the T3s. So, I need to rethink a few concepts to utilize the speed of the T4 which will take some time.

5. Thanks @luni — I guess in real terms the library doesn’t really need the power of 4.0

6. Hello,

sorry for my english. Im german.

i have a problem with this library.
i have a motor with 800steps/revolution
i need 48khz (3600rpm) for output. this function is ok.
But i can max set the setAcceleration(); to 10000
I need 4-5seconds for full speed.
Can i change the teensystep.h or others to make higher the acceleration

can you me help?

regards
Stefan

7. For an acceleration from 0 to 48kHz in 4s you need a setting of 48'000/4 = 12'000 stp/s^2. TeensyStep allows values from 1 to 500'000 so this should be no problem.

But i can max set the setAcceleration(); to 10000
This is very unlikely. Can you post an -ideally very short- sketch showing the effect?

8. this is the code

Code:
```#include "TeensyStep.h"
// stepper and  controller
constexpr int stpPin = A8, dirPin = 1;
Stepper motor(stpPin, dirPin);
//StepControl controller;
RotateControl controller;

constexpr int stopPin = 2;
const int ALARM = A5;
const int ENA = A4;
int ENAstate=0;
long frq;
long acc;
long rpm;

// stopwatches
elapsedMillis displayStopwatch = 0;  // timing the display of the current position
elapsedMillis blinkStopwatch = 0;    // timing the heartbeat LED
elapsedMillis debounceTimer = 0;     // debouncing input pins

int lastPos = 0;

void handlePins();
void handleCommands();

void setup()
{
Serial.println("  m: move motor Pin A8");
Serial.println("  r: RPM motor, r 1000");
Serial.println("  a: acceleration, a 1000");
Serial.println("  s: stop motor");
Serial.println("  e: ENA motor Pin A4");
Serial.println("  x: emergency stop");
Serial.println("  h: display this help");
motor.setMaxSpeed(1000);
motor.setAcceleration(1000);
pinMode(ALARM, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(stopPin, INPUT_PULLUP);  // touch the pin with GND to stop the motor
}

void loop()
{

// handle incomming commands on the serial interface ------------------
handleCommands();

// handle input from pins ---------------------------------------------
handlePins();

// the usual heartbeat ------------------------------------------------
if (displayStopwatch > 2000)
{
controller.stopAsync();
displayStopwatch = 0;
}
}

void handleCommands()
{
if (Serial.available() > 0)                 // skip if the serial buffer is empty
{

displayStopwatch = 0;
digitalWriteFast(LED_BUILTIN, 1);
delay(10);
digitalWriteFast(LED_BUILTIN, 0);
switch (cmd)                            // ... and analyze it
{
case 'm':                               // move command
if (!controller.isRunning())        // skip move command if motor is running already
{
controller.rotateAsync(motor);
Serial.println("Started motor movement");
}
else
{
}
break;

case 's':                               // stop command
controller.stopAsync();             // initiate stopping procedure
Serial.println("Stopping motor");
break;

case 'a':                               // stop command
while (Serial.available()) {
if (read.substring(0, 1) == " ") {
motor.setAcceleration(acc);
Serial.println(acc);

}
} //end Serial.available
break;
case 'r':                               // stop command
while (Serial.available()) {
if (read.substring(0, 1) == " ") {
frq=rpm/0.075;
motor.setMaxSpeed(frq);
Serial.println(frq);
}
} //end Serial.available
break;
case 'x':                               // emergency stop command
controller.emergencyStop();
Serial.println("Emergency Stop");
break;

case 'e':                               // ENA  command
controller.emergencyStop();
ENAstate=!ENAstate;
digitalWrite(ENA,ENAstate);
delay(100);
Serial.println("ENA");
break;

case 'h':                               // help / usage command
case 'u':
Serial.println("\nUsage:");
Serial.println("  m: move motor Pin A8");
Serial.println("  r: RPM motor, r 1000");
Serial.println("  a: acceleration, a 1000");
Serial.println("  s: stop motor");
Serial.println("  e: ENA motor Pin A4");
Serial.println("  x: emergency stop");
Serial.println("  h: display this help");
break;

default:
break;
}
}

}

void handlePins()
{
if (controller.isRunning() && !digitalReadFast(ALARM) && debounceTimer > 200)
{
debounceTimer = 0;
controller.stopAsync();              // initiate stopping procedure
Serial.println("Stopping motor");
ENAstate=!ENAstate;
digitalWrite(ENA,ENAstate);
delay(1000);
ENAstate=!ENAstate;
digitalWrite(ENA,ENAstate);
delay(1000);
controller.rotateAsync(motor);

}
}```

9. I tested your code and don't see a problem with acceleration.

I changed the following for my tests:

Code:
```void setup()
{
while(!Serial);                                      //<<<<<<<<<<<<<<<<<<<<<<<< Need to wait until the serial monitor is ready, otherwise the following text might not be displayed.

Serial.println("  m: move motor Pin A8");
Serial.println("  r: RPM motor, r 1000");
Serial.println("  a: acceleration, a 1000");
Serial.println("  s: stop motor");
Serial.println("  e: ENA motor Pin A4");
Serial.println("  x: emergency stop");
Serial.println("  h: display this help");
motor.setMaxSpeed(48000);                     //<<<<<<<<<<<<<<<<<<  As you requested in the originial post
motor.setAcceleration(100000);                //<<<<<<<<<<<<<<<<<<  Tested it with 10000, 20000 and 100000 all works as expected.
pinMode(ALARM, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(stopPin, INPUT_PULLUP); // touch the pin with GND to stop the motor
}```
For testing I pressed "m" and recorded the signal on the STP pin. Here some screen shots:

Acceleration 100000stp/s^2, you can clearly see the acceleration

It should take t=v/a = 48000 / 100000 = 480ms to reach the speed of 48000 step/sec. Here a screenshot of the pulse sequence some 500ms after the start:

Showing 48kHz

As mentioned, I don't see anything strange.

Remark: It is quite confusing to use the "A" pin numbers for digital pins. Technically it doesn't matter but it is much clearer to say
Code:
`int stpPin = 22`
Code:
`int stpPin = A8`

10. Hello Luni.

Thanks. I will test.
and i will make a video when the test is not ok.
what do you have for a osszi? :-) looks fine.

11. what do you have for a osszi? :-) looks fine.
https://www.az-delivery.de/products/...1681d4d4&_ss=r

13. now is ok.
this was my failure.

I thought the higher the value the longer the acceleration. This was not correct.
lower value = longer acceleration

14. ## getCurrentSpeed() issues

luni, thank you for your fabulous work on this library!

I'm using a Teensy 3.5 and programming it with the Arduino IDE. I'm working on a project using the TeensyStep library which will be documented here. I've run into two library issues to bring to your attention:

Issue 1
getCurrentSpeed() reports non-zero values when the motor is stopped. Before rotation begins, it reports 1. After rotation has been stopped using stop() or stopAsync(), it reports 5. I would expect zero in both cases.

Issue 2
getCurrentSpeed() continues to return the last running speed after an emergency stop (it is not reset to zero). This prevents us from being able to test for issue 1 when using emergencyStop().

The following example code can be used to demonstrate these issues. It also shows my crude initial method of deriving the motor RPM in real time, but I suspect my data types and math functions are not 100% optimal and probably cause rounding issues, hence the warning to prevent someone from blindly trusting this code for this purpose.

Code:
```#include "TeensyStep.h"

Stepper motor(2, 3);
RotateControl ctrl(5, 5000);   // params are step pulse width (µs) and speed update period (µs) (defaults are 5,5000)

float motorsteps = 200.0;  // motor steps per rotation
float microstep = 1.0;     // match to DIP switch setting on microstep driver
float rpm = 1500.0;        // desired initial speed setting in RPM

int lastUpdateMillis = 0;
int updateInterval = 250;  // (ms) interval between serial monitor updates

void setup() {
motor.setMaxSpeed((rpm / 60) * motorsteps * microstep);
motor.setAcceleration(1000 * microstep);

Serial.begin(9600);
delay(1000);
Serial.println("TeensyStep library: display current speed in serial monitor in PPS and RPM");
Serial.println("(no need for an actual microstep driver or motor to be present)");
Serial.println("(note that variable types and math functions are likely not ideal in this test code)");
Serial.println("Send characters to cause events:");
Serial.println(" 'r' to begin rotation with rotateAsync");
Serial.println(" 'o' to override speed");
Serial.println(" 's' for stopAsync (non-blocking)");
Serial.println(" 'b' for stop (blocking)");
Serial.println(" 'e' for emergency stop");
}

void loop() {

if (millis() - updateInterval >= lastUpdateMillis)
{
lastUpdateMillis = millis();
int calculatedrpm = ctrl.getCurrentSpeed() * 60 / motorsteps / microstep;
Serial.printf("position: %d, pulses/sec: %d, rpm: %d\n", motor.getPosition(), ctrl.getCurrentSpeed(), calculatedrpm);
}

if (Serial.available())
{

if (inChar == 'r')  // rotate (initially to max speed specified)
ctrl.rotateAsync(motor);

if (inChar == 'o')  // change to a new speed
ctrl.overrideSpeed(.5);

if (inChar == 's')  // stop rotation with the non-blocking code
ctrl.stopAsync();

if (inChar == 'b')  // stop rotation with the blocking code
ctrl.stop();

if (inChar == 'e')  // emergency stop (instantaneous; no deceleration)
ctrl.emergencyStop();
}
}```

15. Sorry, this is a known bug. See here for a simple workaround. https://github.com/luni64/TeensyStep...ment-499847557. You can also use the development branch (DevTimer) which fixed this and a couple of other things already. Hope to find some time soon to merge the fixes into the master branch. Too much projects at the same time...

16. I see; thanks! The underlying cause of not being able to set a timer to delay infinitely makes total sense, and that simple workaround addresses it perfectly.

I noticed is that when the motor has been rotated and stopped, I can resume rotation using overrideSpeed(). If I have never started rotation using rotateAsync(), calling overrideSpeed() has no effect and the motor remains stopped.

I also happened to notice that if I specify setAcceleration() a second time later in the program, it has no effect. This is not something that I expect will be necessary in my application, but I'm curious how tricky it would be to implement an overrideAcceleration() functionality. I imagine declaring the initial value does some fancy math that stores simpler values for repeated later efficient use, and recalculating on the fly would require more fancy math on the fly. I also expect that triggering a new acceleration ratio while the motor is currently accelerating would require being able to ramp smoothly from one acceleration rate to the new one, which would add a whole additional layer of complexity. Is this about right?

17. I noticed is that when the motor has been rotated and stopped, I can resume rotation using overrideSpeed(). If I have never started rotation using rotateAsync(), calling overrideSpeed() has no effect and the motor remains stopped.
Yes, OverrideSpeed(f) just changes the speed of a running motor by multiplying the set speed by the factor f. If you choose f to be zero the motor "runs" with speed 0. This is different from actually stopping the motor.

I also happened to notice that if I specify setAcceleration() a second time later in the program, it has no effect. This is not something that I expect will be necessary in my application,
All the "SetXX" functions only work with a stopped motor since they pre calculate all the parameters required for the move. As said above, overrideSpeed(0) will not stop the motor....

I'm curious how tricky it would be to implement an overrideAcceleration() functionality.
Not tricky anymore since it is already implemented in the development branch. This example https://luni64.github.io/TeensyStep/..._winder/winder makes heavy use of the feature when fine adjusting the pitch of a winding machine for violin strings.

18. Originally Posted by luni
If you choose f to be zero the motor "runs" with speed 0. This is different from actually stopping the motor.
As said above, overrideSpeed(0) will not stop the motor....
Understood. Here's the nuance I'm seeing that can be demonstrated using the code I posted above: If I power up the Teensy so the program starts fresh (and I don't call a rotateAsync() command) and I call overrideSpeed(), the motor does not move. If I stop a running motor using stopAsync() or stop() or emergencyStop(), I can then use overrideSpeed() to cause the motor to begin rotating again (at the specified speed factor) even though it appears "stopped".

So either the stop commands do not fully "stop" the motor in some manner, or rotateAsync() is capable of "starting" a stopped motor, but only if it has been called previously.

I think I will want to set a fairly high max speed initially, but be able to start rotation at a lower speed. I plan to simply call rotateAsync() and then immediately call overrideSpeed() to the lower starting speed. There should be so little delay between the two calls that the output signal will behave as if the new lower speed was the only thing it has been given. (yet to be tested with hardware, but it seems plausible)

Not tricky anymore since it is already implemented in the development branch. This example https://luni64.github.io/TeensyStep/..._winder/winder makes heavy use of the feature when fine adjusting the pitch of a winding machine for violin strings.
Is he changing the acceleration on the fly, or merely the speed? (and the acceleration has been set once at the beginning)

Either way, it sounds like I should figure out how to get the dev branch loaded onto my machine. ;-)

19. Hey @luni

2 Things

1. I have noticed in your discussions and github pages you show some timing and signals in a GUI interface that looks to be running on a desktop computer. I was wondering what software you were running to debug the stepper motor timing to produce those images.

2. Do you have an estimate for when the Teensy 4 will be supported?

Thanks

20. Hallo,

ich habe jetzt doch noch ein Problem mit dem Teensy (3.2,3.5).
Ich schreibe jetzt auch auf deutsch weil man das besser erklären kann.

Mein Programm funktioniert soweit nur habe ich das problem wenn ich die geschwindigkeit ändere stopt der motor und fährt dann von 0 auf die gewünschte geschwindigkeit. und nicht von 1000 auf 500.
das problem ist noch das die rampe (acc) bleiben muss, also er sollte langsam von z.b. 1000 auf 500 runterfahren und nicht ruckartig von z.b. 1000 auf 500 wenn ich die ACC ausschalte.

benutzte ich da vielleicht falsche befehle, async nehme ich.

grüße
Stefan

21. IMHO, it is not a good idea to write German posts in an English forum. If you feel uncomfortable you can always use https://www.deepl.com which does a great job translating technical texts in both directions

Hello,
I have a problem with the teensy (3.2,3.5) now after all. I write now also in german because it can be explained better.

My program works so far, but I have the problem that when I change the speed the motor stops and then goes from 0 to the desired speed. and not from 1000 to 500. The problem is that the ramp (acc) has to stay, so it should go down slowly from e.g. 1000 to 500 and not jerkily from e.g. 1000 to 500 when I switch off the ACC.

I might use wrong commands, async I use.

Greetings
Stefan
The main use case of TeensyStep is to move up to 10 motors per controller in such a way that the movement of the motors remains synchronized. If you would change the speed of a single motor, the synchronization would be lost. (The next version of the library will generate an error in such cases) Therefore, it is not possible to change the speed (or acceleration, or target position) of individual motors while moving.

If you need to change the speed during operation, you can use the OverrideSpeed function of the rotation controller (https://luni64.github.io/TeensyStep/...rotateControl/). This will change the speed of all motors so that they keep their synchronization. (https://www.youtube.com/watch?v=HcaStXmkH2w)

22. ok. thanks. I will test.

correct english forum, english write :-)

23. Hello,

this is now a problem. I will have only for one Motor.

i always want to change the speed of one motor when i start the seriel Input, for example with "r 1000" and then go higher with "r 2000", but it must change slowly.

Do you have an idea?
i am grateful for any help.

do you have the code what i see in the video?

24. i have test with overide function.
this is ok for my motor.

can i set a range with override_speed?
i need from 0 - 3600rpm and i will change +100rpm or -100rpm
can only be changed in percent?

25. OverrideSpeed multiplies the override factor by the speed you set at startup. So, you can as well set the speed at startup to 1 and use the override factor to set the required speed.

i.e.

Code:
```motor.setMaxSpeed(1);

...

ctrl.overrideSpeed(5000);```
will set the actual speed to 5000stp/sec

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•