New Stepper Motor Library

I've just tried the bugfix branch and the slow speed issue seems to be gone. I had to uncomment the line in startStopping again to stop the motors in overrideSpeed from being unresponsive after their first move.

I also had to comment out the serial.print in TMR.h otherwise using 2 motors at once with overrideSpeed would make the motors stutter.

So far so good!
I'll keep testing, but for now it's working fine.

Thanks again!
 
Correction!

There was a bug in my code.
The only thing I've adjusted from your bugfix branch is to comment out all serial print commands.

It's currently working smooth as butter!
I'll do a longer test to see how stable it is.
 
Great!
When testing, I had the impression it still had an issue with doing successive overrideSpeed calls. Did you test this as well? If it works now I'll remove the debug prints and merge it into the main branch.
 
I'm looking at using this lib for may motorized table saw fence. I'm able to get working where I can get the position during a move for feedback to the user.

I did have an audible beep upon pressing keys on the TFT LCD. however attempting to run a stepper after a "beep" and the steppers barely spin.

Have a look at the modified example,

Thoughts on how I can use this lib in conjunction with analogWrite?

Code:
/*==========================================================================
 * This is a minimal sketch showing the usage of TeensyStep
 *  
 * STEP Pulses on Pin 2    (can be any pin)
 * DIR  Signall on Pin 3   (can be any pin)
 * 
 * The target position is set to 1000 steps relative to the
 * current position. The move command of the controller 
 * moves the motor to the target position.  
 *  
 * Default parameters are 
 * Speed:          800 steps/s
 * Acceleration:  2500 steps/s^2
 * 
 * (slow, but good to start with since they will work on any normal stepper)
 *
 ===========================================================================*/

#include "TeensyStep.h"

Stepper motor(3, 0);     // STEP pin: 2, DIR pin: 3
StepControl controller;  // Use default settings

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


  beep(); // this works fine


// this next move works fine
  motor.setMaxSpeed(3200);
  motor.setAcceleration(10000);
  motor.setTargetRel(1000);  // Set target position to 1000 steps from current position
  controller.move(motor);    // Do the move

// this beep no longer works
  beep();


// motor speed is extremely slow
  motor.setMaxSpeed(3200);
  motor.setAcceleration(10000);
  motor.setTargetRel(1000);  // Set target position to 1000 steps from current position
  controller.move(motor);    // Do the move
}

void loop() {
}

void beep() {
  analogWriteFrequency(6, 2000);
  analogWrite(6, 100);
  delay(100);
  analogWrite(6, 0);
  delay(100);
}
 
Successive overrideSpeed calls seem fine with my code at the moment.


EDIT:: I new I would speak too soon!! Corrected with new findings.

1st issue, -- fixed by (but probably not correctly fixed)
Code:
void StepperBase::rotISR()
    {
        mode = mode_t::rotate;       // ADDED to keep mode in rotate mode. With fast motion "mode = mode_t::stopping;" at crossing point so overrideSpeed doesn't run due to if statement mode NOT rotate
        int32_t v_abs;

What the problem was...
if I quickly change from +ve overrideSpeed to -ve (left to right on a joystick) the motor will move CCW to CW. FINE... however, if I move -ve to +ve (right to left) the motor only moves CW. Which holds true if I go +ve, -ve, +ve, -ve. The motor will move CCW, CW, CW, CW.... and CW forever more until I slow down moving the joystick. Moving the joystick like this wouldn't be the normal use, but if I need to stop the motor and move the mount away from a hazard the automatic reaction would be to move it in the opposite direction.


2nd, seems to be an issue running rotateAsync + overrideSpeed AFTER running a "StepperGroup xxx.move();" on those motors.
When overrideSpeed is run on stepper that moved the furthest (maybe called the leadStepper) in the group move, makes any of the other motors that weren't the leadStepper move.
Motors that weren't in the group move aren't effected.

Looks like the motors need to be released from the leadStepper grouping, or at least zero'd.

Hope that helps!!
 
Last edited:
ok, so I think I've bodge fixed both issues for now.


This checks what mode we're in before doing steps, otherwise when doing an overrideSpeed it will cycle through the StepperBase object created when doing a group move.
Code:
void StepperBase::doStep()
    {
        digitalWriteFast(stepPin, HIGH);
        s += 1;
        pos += dir;

        if (mode == mode_t::target) {
            StepperBase* stepper = next;
        
            while (stepper != nullptr) // move slave motors if required
            {
                if (stepper->B >= 0)
                {
                    digitalWriteFast(stepper->stepPin, HIGH);
                    stepper->pos += stepper->dir;
                    stepper->B -= this->A;
                }
                stepper->B += stepper->A;
                stepper = stepper->next;
            }
        }
    }



and like I said above this bodge fixes alternating polarity fast moves. Mode=stopping, stops overrideSpeed from executing so I make sure it stays mode= rotate until stopped.

Code:
void StepperBase::rotISR()
    {
        mode = mode_t::rotate;             // Keep mode as  "rotate" while rotateAsync is still moving
...
...
...
            {
                stpTimer->stop();
                TimerFactory::returnTimer(stpTimer);
                stpTimer = nullptr;
                isMoving = false;
                v_sqr = 0;

                mode = mode_t::target;         // Change mode back to "target" when rotateAsync stopped.
            }
 
I know you enjoy a plot. With the current bugfix you can see the overrideSpeed works multiple times, but with the code below you can see the issue of moving 1 motor after a group-move has finished. The stepper group that was created affects the rotateAsync.

Screenshot 2023-08-16 at 17.35.34.png

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

using namespace TS4;

Stepper s1(19, 18);
Stepper s2(17, 16);
Stepper s3(15, 14);

elapsedMillis stopwatch;

IntervalTimer t1;
void onTimer()
{
  Serial.printf("%d\t%6d\t%6d\t%6d\n",(unsigned)stopwatch, s1.getPosition(), s2.getPosition(), s3.getPosition());
}


void setup()
{
  TS4::begin();

  while (!Serial);

  t1.begin(onTimer, 50'000);  // print out motor positions

  s1.setMaxSpeed(1000);
  s1.setAcceleration(1000);

  s2.setMaxSpeed(1000);
  s2.setAcceleration(1000);

  stopwatch = 0;
  rotateTest();
}

void rotateTest(){
  s1.rotateAsync(1000);           // move 2 motors
  s2.rotateAsync(2000);
  delay(1000);

  s1.overrideSpeed(0.1);          // change motor 1 speed
  delay(2000);
  s1.overrideSpeed(0.9);          // change motor 1 speed
  delay(5000);

  s1.stopAsync();                 // stop both motors
  s2.stopAsync();

  delay(5000);

  s1.setTargetAbs(0);     
  s2.setTargetAbs(0);
  StepperGroup ({s1, s2}).move(); // move both motors back to 0

  delay(5000);

  s2.rotateAsync(2000);           // move only 1 motor but actually moves 2 motors!
  delay(5000);
}

void loop(){}

The 'fixes' I mentioned in a previous post fixes the issue, but there is probably a better implementation of what I've done.
 
Thanks for the fix and the tests. Result looks perfect. Hope to be able to add this to the library over the weekend.
 
@KrisKasprzak: Sorry for the late reply. Your beep() probably clashes with the timers used by TeensyStep. It defaults to the 4 timers of the TMR3 module. It can be changed to the other TMRs if needed:
Code:
//...
void setup()
{
    TS4::begin(false); // don't use the default timer module
    TimerFactory::attachModule(new TMRModule<0>()); // attach a custom timer module (currenty TMRModule<0>... TMRModule<3> only) 
    //...
}
Hope that helps
 
@luni
Here's a little proof that things are working fine.
Teensy 3.2 & Teensy 4.0 side by side.

https://youtu.be/xohfqF01irU

And I know I haven't said it enough already, THANK YOU for all your work on this. I'm forever grateful!
 
Last edited:
Is it possible now to override the speed of a group in TeensyStep4?
Added that to the current version on gitHub. Let me know if it works for you.

Example:
Code:
#include "Arduino.h"
#include "teensystep4.h"

using namespace TS4;

Stepper s1(0, 1);
Stepper s2(2, 3);
Stepper s3(4, 5);

void setup()
{
    TS4::begin();

    s1
        .setMaxSpeed(10'000)
        .setAcceleration(10'000);

    s2
        .setMaxSpeed(8'000)
        .setAcceleration(15'000);

    s3
        .setMaxSpeed(20'000)
        .setAcceleration(5'000);

    s1.moveAbs(10'000);          // move single motor to target

    StepperGroup g{s1, s2, s3};  // define a motor group
    g.startRotate();             // rotate the motors in the group, fixed speed ratio as defined by their maxSpeed settings

    delay(2000);
    g.overrideSpeed(0.5);        // reduce speed of all motors to half

    delay(2000);
    g.stopAsync();               // stop the motors
}

void loop()
{
}
 
@luni
Everything seems to be working great with the latest commit... Apart from, when doing a group rotate, and a -ve overrideSpeed, only the first motor changes direction, the other 2 keep going in the same direction.

grouprotate.jpg

Test code:
Code:
#include "Arduino.h"
#include "teensystep4.h"

using namespace TS4;

Stepper s1(19, 18);
Stepper s2(17, 16);
Stepper s3(15, 14);

elapsedMillis stopwatch;

IntervalTimer t1;
void onTimer() {
  Serial.printf("%6d\t%6d\t%6d\n", s1.getPosition(), s2.getPosition(), s3.getPosition());
}

void setup() {
  Serial.begin(9600);
  TS4::begin();
  while (!Serial)
    ;
  t1.begin(onTimer, 50'000);    // print out motor positions
  stopwatch = 0;

  s1.setMaxSpeed(4000);
  s1.setAcceleration(3000);
  s2.setMaxSpeed(2000);
  s2.setAcceleration(2000);
  s3.setMaxSpeed(1000);
  s3.setAcceleration(2000);
}

void loop() {
  StepperGroup g{s1, s2, s3};   // Create stepper group

  s1.setTargetAbs(4000);
  s2.setTargetAbs(2000);
  s3.setTargetAbs(-3000);
  g.move();                     // Group Move

  g.startRotate();              // Group Rotate

  delay(3000);
  g.overrideSpeed(0.3);         // overrideSpeed +ve

  delay(3000);
  g.overrideSpeed(-0.7);        // overrideSpeed -ve

  delay(3000);
  g.stopAsync();                // Stop Group Rotate

  delay(6000);
  
  s1.setTargetAbs(0);
  s2.setTargetAbs(0);
  s3.setTargetAbs(0);
  g.move();                     // Group Move back to 0, 0, 0
}
 
This seems to fix the -ve factor issue for group rotates.
Feels like another hack, but it seems to work for now.

Code:
    void StepperBase::doStep()
    {
        digitalWriteFast(stepPin, HIGH);
        s += 1;
        pos += dir;

        StepperBase* stepper = next;
        while (stepper != nullptr) // move slave motors if required
        {
            if (stepper->B >= 0)
            {
                digitalWriteFast(stepper->stepPin, HIGH);
                if (mode == mode_t::rotate) 
                {
                    if (dir == -1)
                    {
                        stepper->pos -= stepper->dir;
                    } else
                    {
                        stepper->pos += stepper->dir;
                    }
                } else
                {
                    stepper->pos += stepper->dir;
                }
                stepper->B -= this->A;
            }
            stepper->B += stepper->A;
            stepper = stepper->next;
        }
    }
 
I'm afraid this only affects the counter but not the actual motors. One needs to set the dir pins as well. But doing this right before the step is too late. Drivers need a couple of us lead time on the dir signal...
 
I managed teensystep4 running three steppers quite well, including overrideSpeed().

However, teensystep4 seriously clashes with the serial ports. Or rather, use of the serial ports clash with teensystep4 so neither operate. :-(
I tried using Serial1, Serial3, and Serial4 with similar results. If I initialize Serial1, but don't attempt to communicate, the steppers all work. If I get a byte of an incoming message, the steppers all stop. I _sometimes_ get the first byte of the received serial data.Then everything seizes up. :-(

I have used this code snippet in my teensystep4 TMR.h library. (Not my code, but copy-and-paste from others.)

// #include "imxrt.h"

#define IMXRT_TMR1_ADDRESS 0x401DC000
#define IMXRT_TMR2_ADDRESS 0x401E0000
#define IMXRT_TMR3_ADDRESS 0x401E4000
#define IMXRT_TMR4_ADDRESS 0x401E8000

Should I be using other timers than those defined above, or perhaps I should use some version of imxrt.h to avoid the timers used by the serial ports?

I am also planning to use the Bounce2.h, SD.h, and EEPROM.h libraries and the usual delay(), millis(), etc. Bounce2 _seems_ to work so far, but I have yet to try the others.

Thanks in advance,
Bill D.
 
Hi Bill,

I've not found teensystep4 to clash with any of the serial ports.
I run teensystep4 with 3 steppers and 3 serial ports fine. No clashing.
You shouldn't have to add those IMXRT lines to the TMR.h library either. Maybe that's what's causing the issue.

If you can link me to your code / GitHub I'll have a look.

Thanks,
Col
 
Hi Col,

I sort of knew this might be the problem because it didn't seem 100% right.

My present (ancient) version of TeensyDuino was missing imxrt.h so wouldn't compile the original code, of course. :-( I then found that snippet of code and copied and pasted so it _would_ compile.

After reading your post and giving it bit more thought, I updated my IDE and my TeensyDuino to the latest versions, and restored that section of code.

Voilà it now works perfectly!

Thank you so much for your help.
I manages to muddle through somehow. I am afraid I am just a script kiddy when it comes to dealing with timers, inline code, etc.

Bill D.
 
Hello all,

I'm new here.

Before I ask a question, I would like to say big "thank you" to Luni for your work with TeensyStep. It helped me make a lot of progress with my project:)

The question is: Is it possible to invert the step signal from HIGH to LOW in TeensyStep4? The code I wrote works very well, but for testing purposes, I'm using A4988. However, in the end, I need to use Leadshine DM805, which requires a falling pulse for the step.
 
Are you sure that the DM805 needs a falling edge? This would be very unusual for Leadshine. Can you post a datasheet?
 
Thanks for the datasheet. Looks like you are right. Currently TeensyStep4 has the pulse polarity hardcoded, so I see 2 possibilities
  1. You'll need a level shifter anyway since the driver requires >3.5V logic level. So, using an inverting shifter seems to be the simplest solution (something like a 74ACT04)
  2. You can change the library code to invert the pulse polarity. You need to change HIGH to LOW here: https://github.com/luni64/TeensySte...79036adc36d18/src/stepperbase.h#L87C14-L87C58
    and you need to change LOW to HIGH here: https://github.com/luni64/TeensySte...d7cd11ab079036adc36d18/src/stepperbase.h#L238
Hope that helps
 
Last edited:
The opto interface on that Leadshine unit has common anodes (+ve supply), so the inputs are indeed active-low.
 
Back
Top