New Stepper Motor Library

Which Arduino / Teensyduino version do you use? Compiles here without problem for Arduino 1.8.5 and Teensyduino 1.44. (Of course you need to add

#include "RotateControl.h"
#include "ResponsiveAnalogRead.h"

to the code from #47, but it looks like you did that. Do you have any other includes in your code?
 
Ups, found it. I had a slightly newer version locally. It correctly includes <cmath> instead of <math.h>. This avoids conflicts with macros defined in wiring.h. Just uploaded the newest version which should fix it.
 
Last edited:
Ups, found it. I had a slightly newer version locally. It correctly includes <cmath> instead of <math.h>. This avoids conflicts with macros defined in wiring.h. Just uploaded the newest version which should fix it.

I tried your example code and it works now (Arduino 1.8.5 and Teensyduino 1.45).

I will do some more tests and report back if I find any bugs.

Once again, thanks a lot for your effort!!!
 
Hi Luni,

Do you know of a straightforward way to modify the library to have minimum speeds and accelerations less than 1?

Thanks!
 
Are you sure that you need a stepper library for speeds below 1s? You won't need acceleration for that low speeds so you can just do something like:
Code:
...

while(notAtTarget)
{
  digitalWriteFast(stepPin,HIGH)
  delayMicroseconds(10);
  digitalWriteFast(stepPin,LOW)

  delay(1000); 
  ...
}
...

Anyway, here some information from an older discussion about the same requirement: https://github.com/luni64/TeensyStep/issues/9
 
Speed Override Demo

Here a quick video demonstrating the new speed override feature of TeensyStep. It first accelerates a disk with 4 holes to 1500 rpm and then synchronizes the speed and position of a second motor to the disk by adjusting its speed on the fly. After the motors run synchronized pins of the second motor dive into the holes of the disk at 1500 rpm.

 
Hello,

I have tried your new library and everything seems to work except the stopAsync() function. The motor just goes to the target position with the velocity that it had when the stopAsync() function was called and then stops abruptly. Am I doing something wrong?

Thank you.

Code:
#include <StepControl.h>

Stepper motor(23, 22);         // STEP pin: 23, DIR pin: 22
StepControl<> controller;    // Use default settings 

void setup(){


  motor.setAcceleration(18750);
  motor.setMaxSpeed(18750);
  motor.setInverseRotation(true);
}

void loop() 
{

  motor.setTargetAbs(-100000);
  controller.moveAsync(motor);    // Do the move
  delay(2000);
  controller.stopAsync();
  delay(2000);
  
  motor.setTargetAbs(0);
  controller.move(motor);    // Do the move
  delay(1000);
  controller.stopAsync();
}
 
I didn't test your code yet but there are some things to note:

First block in loop:
Instead of the delay(2000) after the stopAsync you should wait until the motor really stopped (e.g. place a while(controller.isRunning(){delay(10);} after stopAsync) or you can use stop() instead which does exactly this. Sending new target position while the motor runs will mess up internal state of the motor. (Since this seems to be a common error I'll add some checks in the call...)

Second block:
After your stopAsync you leave the loop without waiting for the motor to stop. A couple of microseconds later you set a new targetPosition while the motor is in full movement. This won't work.

Unless you really need it, I recommend to use the synchronous (blocking) commands instead of the async (non blocking) commands. I.e. move() instead of moveAsync(), and stop() instead of stopAsync()
 
Hello luni,

Thank you for the quick reply and for pointing the mistakes in my test code. I believe I have fixed them.

Unfortunately neither the stop() or stopAsync() functions seem to work properly for me with this new library. The code below just moves once (i.e. doesn't loop) to the position 100000 and back to 0 and completely ignores both the stop() and stopAsync() commands (the code below works fine with the old library).


Code:
#include <StepControl.h>

Stepper motor(23, 22);         // STEP pin: 23, DIR pin: 22
StepControl<> controller;    // Use default settings

void setup() {


  motor.setAcceleration(18750);
  motor.setMaxSpeed(18750);
  motor.setInverseRotation(true);
}

void loop()
{

  motor.setTargetAbs(100000);
  
  controller.moveAsync(motor);    // Do the move (non-blocking)
  
  delay(2000);
  
  controller.stop();              // Stop the motor before move is finished (blocking)
  

  motor.setTargetAbs(0);
  
  controller.moveAsync(motor);         // Do the move (non-blocking)
  
  delay(1000);
  
  controller.stopAsync();             // Stop the motor before move is finished (non-blocking)
  
  while (controller.isRunning()) {
    delay(10);                        // Wait until the motor is stopped 
  }
}
 
Sorry for the late response, I was busy with another project on the weekend. You are right, there was a bug in the development branch. I hope I fixed it, can you give it a try (Branch: develop)?

Here the code which I tried:
Code:
#include "TeensyStep.h"

Stepper motor(23, 22);  // STEP pin: 23, DIR pin: 22
StepControl controller; // Use default settings

void setup()
{
  motor
      .setAcceleration(18750)
      .setMaxSpeed(18750)
      .setInverseRotation(true);
}

void loop()
{
  motor.setTargetAbs(100000);

  controller.moveAsync(motor); // Do the move (non-blocking)
  delay(2000);
  controller.stop();           // Stop the motor before move is finished (blocking)

  motor.setTargetAbs(0);
  controller.moveAsync(motor); // Do the move (non-blocking)
  delay(1000);
  controller.stopAsync();      // Stop the motor before move is finished (non-blocking)

  while (controller.isRunning())
  {
    delay(10); // Wait until the motor is stopped
  }  
}
 
Hi luni,

Thank you very much for your help! The functions seem to work as expected now. I'm trying to build a camera slider and your library seems to be perfect for this application.

Cheers
 
Hi Luni,

I try to use your librairy for my project:
https://groups.io/g/TeenAstro/wiki/home

Currently when I use your library before I start a new move I have to check that the motor is not running.
When the library is use with an human machine interface it is quite annoying. Is it on your todo list to improve that?
For my purpose it would be great if the target can be change any time.
For example the absolute stepper position is 10000, I send an absolute move to 0, the motor starts to rotate and accelerate.... now I send a command move absolute to 20000, the motor must first decelerate and then goto the new target.

Charles
 
Currently when I use your library before I start a new move I have to check that the motor is not running.
Yes, the design goal was automated synchronized movements

When the library is use with an human machine interface it is quite annoying.
Agreed.

Is it on your todo list to improve that?
Sort of.
First of all, solving that for one motor would be quite simple, but the whole architecture of the library is done for multiple synchronized motors. So what should happen to the other motors if you change the target for one motor on the fly? Technically you'd need to recalculate all acceleration and Bresenham parameters, take care that the transistion is smooth for all motors etc... So I'm a bit reluctant to open that can of worms.

However, I recently added the possibility to override the speed in the rotational modes. (see the development branch of the library). This can easily be used to do a very simple position regulator. The motor will then follow any change of the target position as quick as possible. I think that this could be used for a human interface as well.

Here a few examples showing the application of that feature

The slider/pen in this example follows a simple function (cos(k*phi) calculated from the rotation angle (phi) of the spindle motor. Instead of calculating the target you could of course use some user input.


Here the speed and precision of the principle is demonstrated.


And here https://github.com/luni64/TeensyStep/blob/develop/examples/Path_Following/RoseFunctionFollower/RoseFunctionFollower.ino some code showing (again) a function follower (Rose functions in this case )


I'll post an example following user input on the weekend.

Hope that helps
 
So I'm a bit reluctant to open that can of worms.
I can understand that :D

Could you confirm that the development branch is compiling, I had some issue this afternoon, with my Teensy3.2
I'll post an example following user input on the weekend.
Thanks
Charles
 
Hi Luni,
I tried the new control interface on the dev branch but without success. If you have time it would be nice, if you can update the sample. for my applications I will need all the controllers... For me it seems that there is on the devbranch all what I need.
 
I am almost done. I am not the interrupt expert, and maybe can somebody help me.
on my Teensy 3.2 the pin 23 is used in PWM mode, in the TeensyStep IRQ in the config.h is set to default and an IntervalTimer is used for the Movement tracking.
The problem is in that configuration the led on the pin 23 is always off, but the stepper works has expected
If I change in the config.h the IRQ to TIMER_FTM1, the LED on pin 23 is on, but the Stepper in rotation override mode doesn't work any more.

is there away to clearly assign the IntervalTimer to an IRQ?

Charles
 
I tried the new control interface on the dev branch but without success. If you have time it would be nice, if you can update the sample. for my applications I will need all the controllers... For me it seems that there is on the devbranch all what I need.
I updated the examples in the development branch to the new interface. Should compile now out of the box.
 
I am almost done. I am not the interrupt expert, and maybe can somebody help me.
on my Teensy 3.2 the pin 23 is used in PWM mode, in the TeensyStep IRQ in the config.h is set to default and an IntervalTimer is used for the Movement tracking.
The problem is in that configuration the led on the pin 23 is always off, but the stepper works has expected
If I change in the config.h the IRQ to TIMER_FTM1, the LED on pin 23 is on, but the Stepper in rotation override mode doesn't work any more.

If you post a minimal example showing the effect I can have a look into it.

is there away to clearly assign the IntervalTimer to an IRQ?
TeensyStep should not have problems with other code using IntervalTimers as long as there are some left. (Each controller uses one interrupt timer, total number of available timers: 4)
 
Here a quick implementation of a "user input follower". I simulated the user input by using a random number between +/- 10000 as target and update that number every second. The motor regulates its position to the new target in the background. The regulator is implemented as a very simple P regulator (if necessary, extending to a full PID is straight forward). The picture shows the motor position (blue) and the target posiiton (orange) over time.

follower2.PNG

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

constexpr unsigned PID_Interval = 10; // ms  
constexpr float P = 0.01;             // (P)roportional constant of the regulator needs to be adjusted (depends on speed and acceleration setting)

Stepper stepper(0, 1);
RotateControl controller;

int32_t target = 0;

void pid()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > PID_Interval)
  {    
    float delta = (target - stepper.getPosition()) * (P / PID_Interval);  // This implements a simple P regulator (can be extended to a PID if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  while (!Serial && millis() < 1000);

  stepper
      .setMaxSpeed(10000)
      .setAcceleration(75000);

  controller.rotateAsync(stepper);
  controller.overrideSpeed(0); // start with stopped slide
}

elapsedMillis retargetTimer = 0;
elapsedMillis outputTimer = 0;

void loop()
{
  pid();
  
  if(retargetTimer > 1000)  // new random target every second 
  {
    retargetTimer = 0;
    target = random(-10000, 10000);
  }

  if (outputTimer > 20)  // print position for display
  {
    outputTimer = 0;
    Serial.printf("%d\t%d\t%d\n", millis(), stepper.getPosition(), target);
  }
}
 
Last edited:
Thanks luni!
The graph looks really really good. Great video Documentation and I like the implementation too.
just a small information for people that have problem to compile the TeensyStep lib: please update your arduino IDE and Teensy lib.
***dein Lib ist hammergeil***
 
Hi luni,

I guess, I found a small bug on the dev branch in the method getCurrentSpeed
Code:
inline int getCurrentSpeed()
  {
    return timerField.getStepFrequency();
  }
timerField has no method called getStepFrequency.

Charles
 
Sorry for the late answer, I was quite busy the last days. Fixed that and updated the code on GitHub. Should work now.
 
Thanks!
it works very well, there is just a minor bug: when it is no more running, it returns the last valid speed and not 0. But it is a minor issue.
I added you to the list of contributors of my project.
Merci beaucoup.
Charles
 
Great that everything works. I'll have a look at the issue with the returned speed.
I'm currently working on a documentation web page, may I add a link to your project page in the applications section?
 
Back
Top