Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 4 FirstFirst 1 2 3 4 LastLast
Results 51 to 75 of 85

Thread: TeensyStep - How to switch from 1 speed to another

  1. #51
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    I meanwhile summarized this development as an application on the TeensyStep Hompage https://luni64.github.io/TeensyStep/...ations/winder/
    @jpk: I'm not a violin string winder at all. I hope I described everything correctly. Feel free to correct and add content if you like. (The source of the page is in the gh-pages branch)

  2. #52
    I managed to prepare a small video, see here: https://www.youtube.com/watch?v=SYRmfHMnmTE

  3. #53
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    That's really cool! If you need somebody to outsource series production to, let me know :-)

    I'll add that to the application page if you don't mind.

  4. #54
    Quote Originally Posted by luni View Post
    That's really cool! If you need somebody to outsource series production to, let me know :-)
    That could be the case any time sooner or later Thanks for letting me know!

    Quote Originally Posted by luni View Post
    I'll add that to the application page if you don't mind.
    Please feel free to ad it!

  5. #55
    Quote Originally Posted by luni View Post
    I'm not a violin string winder at all.
    You are almost there

    Quote Originally Posted by luni View Post
    I hope I described everything correctly. Feel free to correct and add content if you like. (The source of the page is in the gh-pages branch)
    Perfect, I added 2 minor details...

  6. #56
    I want to share another observation: if I issue a stop command during deceleration the motor would speed up and begin a new deceleration ramp:

    Code:
    #include "TeensyStep.h"
    
    Stepper motor(22, 41);
    StepControl controller;
    
    int accel = 500;
    int speed = 1000;
    int target = 2000;
    
    void setup() {
      motor
      .setAcceleration(accel)
      .setMaxSpeed(speed)
      .setTargetRel(target);
    
      controller.moveAsync(motor);
      delay(3500);
      controller.stopAsync();
    }
    Since a sudden speed up could break my thin winding wires I work around as follows:

    Code:
    #include "TeensyStep.h"
    
    Stepper motor(22, 41);
    StepControl controller;
    
    int accel = 500;
    int speed = 1000;
    int target = 2000;
    
    void setup() {
      motor
      .setAcceleration(accel)
      .setMaxSpeed(speed)
      .setTargetRel(target);
    
      float decel = speed / accel;       // calc accel duration
      decel = decel * decel * accel / 2; // calc travel
      decel = target - decel;            // calc start of decel
    
      controller.moveAsync(motor);
      delay(3500);
      if (motor.getPosition() < decel) {controller.stopAsync();}
    }
    But I wonder if that is elegant since the library must already know the position where deceleration starts...?

  7. #57
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    The bug is in the development branch right? I did a lot of work on the new RotateController recently, looks like the new StepController needs some attention as well. I'll have a look tomorrow.

  8. #58
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    That should be fixed now, can you give it a try?

  9. #59
    Quote Originally Posted by luni View Post
    The bug is in the development branch right?
    Yes. I checked the master branch and it did only happen with the develop branch...

    Quote Originally Posted by luni View Post
    That should be fixed now, can you give it a try?
    I just tried: it's fixed! Many thanks!! It helps a lot in my multi layer winding applications when spooling fibers from one spool to another. Following your earlier suggestion I use the StepController for this, moving both motors to a target and change the direction of the feeder periodically. That works well!

  10. #60
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    Thanks a lot for testing, I think it finally is time to merge the development branch into master.

  11. #61
    Quote Originally Posted by luni View Post
    Thanks a lot for testing
    Thansk for fixing! But with the new version it seems I can't get callbacks working:

    Code:
    #include "TeensyStep.h"
    
    Stepper motor(22, 41);
    StepControl controller;
    
    bool flag = 0;
    
    void setup() {
      motor.setTargetRel(2000);
      controller.setCallback(finished);
      controller.moveAsync(motor);
    }
    
    void finished() {flag = 1;}
    
    void loop() {if (flag == 1) {Serial.println("finished"); flag = 0;}}

  12. #62
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    Thanks again! I fixed this and uploaded. Looks like it got lost during one of the merges. Should work now.

  13. #63
    Quote Originally Posted by luni View Post
    Should work now.
    I can confirm: it works. Thanks again for the great support!!!!

  14. #64
    A new observation: moveAsync works only if stp.controller is defined in global space:

    Code:
    #include "TeensyStep.h"
    
    Stepper motor1(22, 41);
    Stepper motor2(43, 42);
    
    void setup() {
      StepControl controller1;
      motor1.setTargetRel(1000);
      controller1.move(motor1);      // works
    
      StepControl controller2;
      motor2.setTargetRel(1000);
      controller2.moveAsync(motor2); // does not work
    }
    
    void loop() {}

  15. #65
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    Sorry, that can't work. You generated the controller objects on the stack of Setup(). Thus, they automatically will be (and need to be) destructed before Setup is left and the allocated stack on which they lived is released. Destruction happens immediately after your (non blocking) call to moveAsync so the controller has no chance to do its work before it is destructed.

    If you replace the moveAsync() by a blocking move() it should work as you expect.

    Edit: BTW: the controllers are prepared to handle a destruction while they are still running. -> The first thing they do in their destructors is calling emergencyStop(), then the allocated timers will be stopped and released, so nothing bad will happen in your code.

  16. #66
    Quote Originally Posted by luni View Post
    Sorry, that can't work. You generated the controller objects on the stack of Setup(). Thus, they automatically will be (and need to be) destructed before Setup is left
    Thanks for clarifying!

    Quote Originally Posted by luni View Post
    BTW: the controllers are prepared to handle a destruction while they are still running. -> The first thing they do in their destructors is calling emergencyStop()
    I see! Does this mean I also could delete a controller manually and define a new one within the scope, re-using the resources?

  17. #67
    Quote Originally Posted by jpk View Post
    Thanks for the links, great project!!! I will try to learn from these examples. I have to say: a big big thank to luni for his help and his library!!! He saves my project.



    Nice!!!! Yes, teensyfied and lunified indeed But as further I get, the farer the destination seems... I will keep you informed and will provide videos as soon as something is showable! For the moment I can show my recently completed PCBs, basically a board for the periphery of the well known teensy breakout-board:

    Attachment 16352

    The ICs used are: ADS1231, MAX3490, LM335, MCP100-475D one each, and multiple 74HCT125, 74LVC245, ULN2803A.



    Sorry, I didn't make this clear: I don't need changes of acceleration for the speed changes of a single motor, but as soon as both motors change speed I want them to be in sync. I updated my diagram accordingly:

    Attachment 16354
    jpk - is this board for sale ?

  18. #68
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    I see! Does this mean I also could delete a controller manually and define a new one within the scope, re-using the resources?
    Yes, but you should never directly call a destructor. (https://isocpp.org/wiki/faq/dtors#do...-dtor-on-local).
    Basically, you have two options.

    1. Dynamically create the object on the heap with new and delete it if you don't need it anymore. (this is the usual way how to do this in c++)
    2. Use braces to generate as much scopes as you need and declare your objects within those scopes. They will be destroyed when the code leaves the scope. This will generate the objects on the stack. So, if you are paranoid about not generating objects on the heap, you will like this method.



    Here a few examples and the generated output:

    Code:
    #include "Arduino.h"
    #include "TeensyStep.h"
     
    Stepper a(0,1), b(2,3), c(4,5), d(6,7), e(8,9);
      
    void setup() 
    {
      // heap version ---------------------------------------------
      RotateControl *rctrl_heap_1 = new RotateControl();
      RotateControl *rctrl_heap_2 = new RotateControl();
      RotateControl *rctrl_heap_3 = new RotateControl();
      RotateControl *rctrl_heap_4 = new RotateControl(); 
    
      a.setMaxSpeed(1500);
      b.setMaxSpeed(3000);
      c.setMaxSpeed(2000);
      d.setMaxSpeed(4000);
      e.setMaxSpeed(6000);
    
      // do something with the controllers
      rctrl_heap_1->rotateAsync(a, b);
      rctrl_heap_2->rotateAsync(c);
      rctrl_heap_3->rotateAsync(d);
      rctrl_heap_4->rotateAsync(e);
    
      // stop rctrl_heap2 and rctrl_heap3 after 2s
      delay(2000);
      rctrl_heap_3->stop();
      rctrl_heap_2->stop();
    
      // get rid of two controllers, implicitley emergency stops them and releases timers
      delete rctrl_heap_1;
      delete rctrl_heap_4;
      
      // construct new controllers
      StepControl *sctrl_heap_1 = new StepControl(5, 1000);
      StepControl *sctrl_heap_2 = new StepControl(3, 10000);
    
      a.setTargetRel(1000);
      b.setTargetRel(5000);
    
      sctrl_heap_1->moveAsync(a);
      sctrl_heap_2->moveAsync(b);
      rctrl_heap_2->rotateAsync(c,d);
      rctrl_heap_3->rotateAsync(e);
    
      while(sctrl_heap_1->isRunning() || sctrl_heap_2->isRunning());
      
      delete sctrl_heap_1;
      delete sctrl_heap_2;
      delete rctrl_heap_2;
      delete rctrl_heap_3;
    
      // stack - version -------------------------------------------
    
      delay(500);
    
       // this generates a new scope, the controllers will be 
       // deleted automatically when the program leaves the scope
      {  
        RotateControl r_stack_1;
        RotateControl r_stack_2;
        RotateControl r_stack_3;
        RotateControl r_stack_4;
    
        r_stack_1.rotateAsync(a);
        r_stack_2.rotateAsync(b, c);
        r_stack_3.rotateAsync(d);
        r_stack_4.rotateAsync(e);
    
        delay(1000);   // leave scope after 1s, this will emergency stop the motors
      }
    
      // new scope
      {
        RotateControl r_stack_5;
        RotateControl r_stack_6;
    
        r_stack_5.rotateAsync(a,b);
        r_stack_6.rotateAsync(c,d);
    
        delay(1000);
    
        r_stack_5.stopAsync();
        r_stack_6.stopAsync();
        
        while(r_stack_5.isRunning() || r_stack_6.isRunning()); // wait until motors stopped
      } 
    }
    
    void loop()
    {
      
    }

    Click image for larger version. 

Name:	scopes.jpg 
Views:	13 
Size:	57.3 KB 
ID:	16532

  19. #69
    Quote Originally Posted by luni View Post
    Dynamically create the object on the heap with new and delete it if you don't need it anymore.
    Many thanks for your example! I played with it but couldn't do the following:
    Code:
    #include "TeensyStep.h"
    
    Stepper a(22, 41);
    
    void setup() {
      RotateControl *rctrl_heap_1 = new RotateControl();
      rctrl_heap_1->rotateAsync(a);
      delay(2000);
    }
    
    void loop() {
      rctrl_heap_1->stop();
      delete rctrl_heap_1;
      
      while (1);
    }
    Is there any way to create a controller and remove it at another place?

    Also I noticed that negative override factors do decelerate and accelerate again, but without actually toggling the dirPin:
    Code:
    #include "TeensyStep.h"
    
    Stepper motor(22, 41); RotateControl ctrl(5, 1000);
    
    void setup() {
      ctrl.rotateAsync(motor); delay(2000);
      ctrl.overrideSpeed(-1);  delay(2000);
      ctrl.overrideSpeed(1);   delay(2000);
      ctrl.stopAsync();
    }
    
    void loop() {}
    I could write the dirPin manually, but I hoped that you intended the library to do so... BTW your earlier suggestion about the HCT125s works great: maybe add these to your "Hooking up a Driver / Logic Level Conversion" page...?
    Click image for larger version. 

Name:	SN74HCT125 connections.jpg 
Views:	10 
Size:	25.4 KB 
ID:	16540
    Quote Originally Posted by Gadget999 View Post
    jpk - is this board for sale ?
    I have only one left and that has bugs, but I can send you my (corrected) KiCad files if you PM me your email address!
    Last edited by jpk; 05-03-2019 at 07:15 AM. Reason: added HCT125 diagram

  20. #70
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    Quote Originally Posted by jpk View Post
    ....
    Is there any way to create a controller and remove it at another place?
    Technically this is trivial, just declare the pointer to the controller in global space. But beware, this can very quickly lead to a complete mess. Usually you try not to pass responsibility for deleting objects around.

    Code:
    #include "TeensyStep.h"
    
    Stepper a(22, 41);
    RotateControl* rctrl_heap_1;
    
    void setup() 
    {
      rctrl_heap_1 = new RotateControl();
      rctrl_heap_1->rotateAsync(a);
      delay(2000);
    }
    
    void loop() 
    {
      rctrl_heap_1->stop();
      delete rctrl_heap_1;
      
      while (1);
    }

    BTW: What do you want to achieve? I'm sure there are better ways...


    Quote Originally Posted by jpk View Post
    Also I noticed that negative override factors do decelerate and accelerate again, but without actually toggling the dirPin:[CODE]#include "TeensyStep.h"
    That used to work perfectly, I'll have a look later today or tomorrow.


    Quote Originally Posted by jpk View Post
    BTW your earlier suggestion about the HCT125s works great: maybe add these to your "Hooking up a Driver / Logic Level Conversion" page...?
    Click image for larger version. 

Name:	SN74HCT125 connections.jpg 
Views:	10 
Size:	25.4 KB 
ID:	16540
    That's a good idea, I'll add it on the weekend.

  21. #71
    Quote Originally Posted by luni View Post
    BTW: What do you want to achieve? I'm sure there are better ways...
    At the moment I am using 2 rotate and 2 step controllers for my 5 motors and get along with them if used carefully - but if I add a new motor (say for a future grinding device) I will get in troubles, so I thought I could for each move create the controller on the fly and destroy it afterwards. As I try to run the motor movements non-blocking I do most stuff by activating a flag so that loop() knows when to execute for example a stop command. So I need to be careful not to mess up the use of controllers as I only have 2 of each sort. But at the moment I am fine with that! Just wondered if it were better to generate and destroy the controllers only when needed:
    Code:
    void setup() {
      create_controller();
      start_motor();
    }
    
    void process_serial() {
      if (something_is_true) {flag = 1;}
    }
    
    void loop() {
      process_serial();
      if (flag) {
        stop_motor();
        delete_controller();
        flag = 0;
      }
    }
    Another approach could be to merge the 2 types of controllers into one. Deceleration for a pre specified target I do with a rotate controller as shown in the 2nd code block of #56: so if I run out of controllers I could code everything for rotate controllers, but I am not sure if I should prepare for this now.

    (BTW the bug I described in #32 is still there, and also setPullInSpeed is not enabled yet...)

  22. #72
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    Also I noticed that negative override factors do decelerate and accelerate again, but without actually toggling the dirPin
    This is fixed now! The problem only occurred when using default speed settings and not calling setMaxSpeed. Now it should work correctly for default values as well. Thanks for spotting that one.

    At the moment I am using 2 rotate and 2 step controllers for my 5 motors and get along with them if used carefully - but if I add a new motor (say for a future grinding device) I will get in troubles, so I thought I could for each move create the controller on the fly and destroy it afterwards. As I try to run the motor movements non-blocking I do most stuff by activating a flag so that loop() knows when to execute for example a stop command. So I need to be careful not to mess up the use of controllers as I only have 2 of each sort.
    I see your problem. Doing that in a clean way is interesting. From the first trials I'd say something like a ControllerFactory for generating and disposing the controllers and a state machine based approach for your asynchronous commands might be a good solution. This might be interesting for other users as well. I'll work something out and add an example to the webpage.

    (BTW the bug I described in #32 is still there, and also setPullInSpeed is not enabled yet...)
    Yes, I know, I need to dig into this timing issue sometime. As already mentioned, as a workaround you can insert a short delay after the estop then should work. Regarding the pullInSpeed. I'm not sure if this feature is really useful? Do you have a use case for it?

  23. #73
    Quote Originally Posted by luni View Post
    This is fixed now! The problem only occurred when using default speed settings and not calling setMaxSpeed. Now it should work correctly for default values as well. Thanks for spotting that one.
    Thanks for fixing! And sorry for so many requests...
    Quote Originally Posted by luni View Post
    Regarding the pullInSpeed. I'm not sure if this feature is really useful? Do you have a use case for it?
    Yes, I think it's good to have. Some of my winding processes move really slow, for example when threading in the wires. With thin wires I could end up with feeder speeds below pullin-speed. So I tried to take this into account: I set it to the lowest possible value and used that value for calculations. I don't know yet how often I will need such slow speeds though...

  24. #74
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    423
    At the moment I am using 2 rotate and 2 step controllers for my 5 motors and get along with them if used carefully - but if I add a new motor (say for a future grinding device) I will get in troubles, so I thought I could for each move create the controller on the fly and destroy it afterwards. As I try to run the motor movements non-blocking I do most stuff by activating a flag so that loop() knows when to execute for example a stop command. So I need to be careful not to mess up the use of controllers as I only have 2 of each sort.
    I did some experiments on your problem and came up with a quite simple and obvious solution. The only reason why the number of controllers was limited to a total number of 4 was that each controller reserves one interval-timer and two FTM channels. The controllers grabbed those at construction time and only released them when it (the controller) was destructed. In the new scheme the controller only grabs the timers when it really needs them, i.e. during the movement. After the motor reaches the target or is stopped the timers are released.

    While the change seems to be marginal it has a huge impact on the usage of the controllers: You can now generate as much controllers as you like as long as you make sure that you don't operate more than 4 at the same time. This makes handling much easier. E.g. you can define 4 RotateControllers and 4 StepControllers and switch between Rotational and Target modes without the need to dispose the objects in between.

    The lib can be found in the DevTimer branch.
    Here a quick example (BTW: the emergencyStop bug from #33 is also fixed)
    Code:
    #include "TeensyStep.h"
    
    Stepper m1(0, 2), m2(4, 6);
    
    RotateControl rc1, rc2, rc3, rc4, rc5;   
    StepControl sc1, sc2, sc3, sc4, sc5;
    
    void setup()
    {
      m1
          .setMaxSpeed(2000)
          .setAcceleration(2000);
    
      m2
          .setMaxSpeed(2000)
          .setAcceleration(2000);
    
      m1.setTargetRel(2000);
      sc1.moveAsync(m1);
    
      m2.setTargetRel(100);
      sc2.move(m2);
    
      m2.setTargetRel(500);
      sc3.moveAsync(m2);
      delay(300);
      sc3.emergencyStop();
    
      m2.setTargetRel(100);
      sc4.move(m2);
    
      m2.setTargetRel(100);
      sc5.move(m2);
    
      while (sc1.isRunning());
    
      goHome(m1, m2);
    
      //------------
      delay(100);
      startMotor(m1, rc5);
      startMotor(m2, rc1);
    
      stopMotor(m1, rc5);
      stopMotor(m2, rc1);
    }
    
    void loop() {}
    
    //-----------------------------------------------------------------------
    void goHome(Stepper &motor_A, Stepper &motor_B)
    {
      StepControl localSC;
    
      motor_A
          .setAcceleration(25000)
          .setMaxSpeed(10000)
          .setTargetAbs(0);
    
      motor_B
          .setAcceleration(25000)
          .setMaxSpeed(10000)
          .setTargetAbs(0);
    
      localSC.move(motor_A, motor_B);
    }
    
    void startMotor(Stepper &m, RotateControl &rc)
    {
      m.setMaxSpeed(5000);
      rc.rotateAsync(m);
      delay(500);
    }
    
    void stopMotor(Stepper &m, RotateControl &rc)
    {
      rc.stopAsync();
    }
    Click image for larger version. 

Name:	devTimer1.jpg 
Views:	3 
Size:	45.0 KB 
ID:	16584

    Would be great if you could test it...
    Last edited by luni; 05-09-2019 at 07:09 PM.

  25. #75
    Quote Originally Posted by luni View Post
    Here a quick example (BTW: the emergencyStop bug from #33 is also fixed)
    Would be great if you could test it...
    Thanks a lot!! I think it's a good solution. I did some tests on my machine, everything works fine. Also the e-stop I can now execute faster without the delay!

    EDIT: just noticed that slow movements don't work well. I will figure it out and try to give some code asap...

    EDIT2: I did some more tests: the 3rd code block of #21 does not work.
    Last edited by jpk; 05-10-2019 at 07:15 PM.

Posting Permissions

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