Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 4 1 2 3 ... LastLast
Results 1 to 25 of 88

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

  1. #1
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24

    TeensyStep - How to switch from 1 speed to another

    I'm stuck on figuring out how to actively choose a new speed and have my motors accel/decel from current to the new speed. The code below ramps up to the right speed, but on the new speed command it pops to Zero then starts the second speed. I suspect the delays are part of the issue, but still unsure how to resolve.

    My goal will be to have 10x motors spinning at their own constant speed. When a new set of speeds are received, each motor will adjust to their new desired RPM.

    thanks for any help!

    Code:
    #include <StepControl.h>
    
    Stepper motor_1(10, 9);         // STEP pin: 10, DIR pin: 9
    Stepper motor_2(5, 9);         // STEP pin: 5, DIR pin: 9
    StepControl<> controller;    // Use default settings 
    
    void setup(){
      motor_1
        .setPullInSpeed(800)
        .setAcceleration(40000); //lower = slow. ?won't go above max speed
    }
    
    void loop() {
    
      motor_1.setMaxSpeed(4000);
      controller.rotateAsync(motor_1);    // Do the move
      delay(10000); //how long to run for. at time, start decel
      
      motor_1.setMaxSpeed(400);
      controller.rotateAsync(motor_1, motor_2);    // Do the move
      delay(5000);
    }

  2. #2
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    Sorry, currently this is not possible. The library was designed to efficiently move a bunch of motors synchronized to a target position. It precalculates all movement parameters before the run. Changing those parameters on the fly will generate a mess.

    However, since this requirements pops up regularly I'm already working on a new controller which will allow synchronized rotation of up to 10 motors with on the fly adjustable speed.

    My goal will be to have 10x motors spinning at their own constant speed.
    Unfortunately the Teensies only have four 32bit timers. TeensyStep needs one of those timers for each independently moving group of motors.

    Click image for larger version. 

Name:	motors.png 
Views:	35 
Size:	19.1 KB 
ID:	15317

    So, if you really need those 10 motors running independently on one Teensy, TeensyStep unfortunately is not the right tool.
    Last edited by luni; 12-07-2018 at 08:32 PM.

  3. #3
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24
    Thanks for the quick and thorough reply.

    Ok no problem on not being able to run 10, but is there any way to run for 1 motor to run at a constant speed, then accel/decel to a new constant speed? Apologies if im misreading what you wrote above, I wouldn't want to not use this amazing library if I simply have to buy more teensy's.

    Or what about using a very very large target position, and instead of stopping at the target, a new position & slightly different maxSpeed is immediately chosen and the library switches instantly.

    I suspect there would be a hiccup at the change but haven't tested yet. My motors are spinning constant speeds between1700-2000 PPS (500-600 micros/pulse).

    Looking forward to future iterations of your library! Thanks for all of your hard work.

  4. #4
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    ...but is there any way to run for 1 motor to run at a constant speed, then accel/decel to a new constant speed?
    Currently not, but most probably this should be possible in a couple of days.

    Or what about using a very very large target position, and instead of stopping at the target, a new position & slightly different maxSpeed is immediately chosen and the library switches instantly. I suspect there would be a hiccup at the change but haven't tested yet.
    I'm afraid playing around with this is just wasting your time, the current design is simply not capable to do this. Anyway, I'd be happy if you could test the new controller as soon as it is ready.

  5. #5
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24
    Oh wow, sure thing. More than happy to test it out whenever you are ready. My coding skills aren't stellar but my application is pretty direct so should still be helpful.

    Thanks for being direct about capabilities. I'm creating an installation for mid-January but plan to revise it for additional uses down the road. If I buy drivers that work for 5v and 3.3v I can switch between Arduino/teensy at any point.

    Reach out anytime.

  6. #6
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    Great, the new controller works already. I need to clean up the code and optimize some parts but this makes good progress.
    I'm creating an installation for mid-January but plan to revise it for additional uses down the road.
    Just curious Is this going to be an art installation?

    If I buy drivers that work for 5v and 3.3v I can switch between Arduino/teensy at any point.
    Yesterday I ordered one of those cheap TB6600 "industrial" drivers for some tests. Pictures showing the inside of those drivers do not look very reassuring (as usual, you get what you pay for...) Anyway, I will have a look if they are really compatible to 3.3V as they state (doubt it...).

  7. #7
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24
    Awesome, excited to see it. Yep, its for an art installation ... 10-12x motors spinning at constant but precise RPMs to create an optical illusion.

    I'm trying to get beyond the phase of ordering random pieces, but the TB6600 was one of them. Also have a DRV8825, A4988 Pololu, and Big Easy Driver (A4988).

    I read in one of the comments that its not even a 6600 chip in some of these drivers (though I don't really understand chip-level details). I haven't opened mine up yet to see the guts, but the casing screws are so tightly screwed in the metal is a bit bent ... can't be a good sign for QC hah.

    Might need to order another driver sample that properly accepts 3.3v logic. Reach out if I can help at all.

  8. #8
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24
    I am adapting my plan to work for TeensyStep and am looking to better understand the library and hardware limitations (FTM/PIT/Interval Timers).

    Would the hardware limitations limit either Opt 1 or Opt 2?

    Current (and working) plan is :
    - set 10x motors max speed to slightly different speeds
    - move/start all 10 motors
    - spin at speed for 20s
    - ramp down/pause
    - slow reset to position zero

    ALT Option 1:
    - set 10x motors at same max speed/settings
    - start each motor 1 second after the previous
    - each motor repeats its move 4 times
    - all motors stop when their move is finished

    ALT Option 2: (*If WIP library-update allows it)
    - set 10x motors to same max speed
    - move/start all motors
    - spin at max speed for 20s
    - change 10x max speeds to slightly different speeds
    - accel/decel to new speed
    - spin at new max speeds
    - ramp down to zero / pause
    - slow reset to pos zero

    I don't mind adding add'l teensy's, but am a bit intimidated to co-ordinate them starting in sync. If this is advised, any suggestions on posts/reads to look into?
    Thanks.

  9. #9
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    Let me explain the constraints: Currently each controller uses its own PIT timer. Since there are only 4 PITs you are limited to 4 controllers. Each controller is able to move up to 10 (this can be increased easily) motors with a fixed speed ratio (Bresenham). Motors can be moved to independent fixed targets (move commands, speed ratio determined from the targets). Alternatively the motors can be continiously rotated with fixed speed ratios (rotate commands, speed ratio determined from the maxSpeed settings). Changing that ratio on the fly is not possible with the current design of TeensyStep.

    I'm currently working on an improvement which allows for overriding the overall speed of the controller. I.e., there will be something like a controller.overrideSpeed(float factor). Motors will correctly accelerate / decelerate to the new speed and all motors connected to the controller will stay in sync.

    Regarding your options:

    Option 1:
    each motor repeats its move 4 times
    Don't understand that. Do you mean 4 revolutions? Anyway, this should be possible already if you use one controller for each motor. You'd need 3 Teensies for 12 motors.

    Option 2:
    - change 10x max speeds to slightly different speeds
    If that means that the speed of all 10 motors will be changed by the same factor that should be possible with the new library.


    I don't mind adding add'l teensy's, but am a bit intimidated to co-ordinate them starting in sync. If this is advised, any suggestions on posts/reads to look into?
    Thanks.
    That shouldn't be a big deal, if you only need to start them at the same time a digital line from a master Teensy to the slave motor controller Teensies would be enough. If you need more control you could also setup a serial communication from the master to the slaves.

    Click image for larger version. 

Name:	12Steppers.png 
Views:	25 
Size:	11.0 KB 
ID:	15421

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    See here for the new version with speed override: https://forum.pjrc.com/threads/43491...l=1#post193806

  11. #11
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24
    I am running into issues compiling with 10 motors and can't figure out why. At the moment all are running at the same speed. For some reason the log says "Too many motors used", though I am only defining 10.

    My goal is to run 4 sets of motors at different speeds. I tried defining 2 sets of motors but these also don't compile when using "controller.move(motorSet_A, motorSet_B);"

    Where am i going wrong?

    Code:
    #include <Wire.h>
    #include <StepControl.h>
    
    unsigned long targetInterval = 5000; // read speed from master
    unsigned long pulsePerSec = 1000000/targetInterval;
    
    //Step, Dir
    Stepper M0(6, 5), M1(15, 14), M2(7, 8), M3(17, 16), M4(10, 9), M5(1, 0), M6(4, 3), M7(21, 20), M8(23, 22), M9(12, 11);
    StepControl<> controller;   // Use default settings 
    
    constexpr int spr = 16*200; // 3200 steps per revolution
    int acceleration = 1500;
    int pullInSpeed = 100;
    const byte numMotors = 9; //actually 10, but 0-9
    int microSteps = 4; 
    int PPR = 5000; //pulses per rotation wo microstepping
    
    int targetDist[numMotors] = {20*spr}; //50x decent
    //int S1MaxSpeed[numMotors] = {50000};
    //int S1MaxSpeed[numMotors] = {1*PPR*microSteps};
    int S1MaxSpeed[numMotors] = {8000};
    
    int scene = 0;
    
    // SCL/SDA Stuff
    byte b[3];  //byte array
    bool flag1 = LOW;
    
    void setup() {
      delay(2000);
      Wire.begin(8);                // join i2c bus with address #8
      Wire.onReceive(receiveEvent); // register event
      Serial.begin(9600);           // start serial for output
      delay(4000);
    
      Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3, &M4, &M5, &M6, &M7, &M8, &M9};
      for (int i = 0; i <= numMotors; i++) {
        motorSet_A[i]->setPullInSpeed(pullInSpeed);
        motorSet_A[i]->setAcceleration(acceleration);
        motorSet_A[i]->setMaxSpeed(S1MaxSpeed[0]);
        motorSet_A[i]->setTargetRel(targetDist[0]);
      }
      
    }
    
    void loop() {
      Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3, &M4, &M5, &M6, &M7, &M8, &M9};
    //  Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3, &M4};
    //  Stepper* motorSet_B[] = {&M5, &M6, &M7, &M8, &M9};
      
      scene = 0;
    //  if (scene != lastScene){  // only go through if scene changes
        switch (scene){
          case 0:                 
    //        M0.setMaxSpeed(8000);
    //        M1.setMaxSpeed(8000);
    //        M2.setMaxSpeed(8000);
    //        M3.setMaxSpeed(8000);
    //        M4.setMaxSpeed(8000);
    //        M5.setMaxSpeed(8000);
    //        M6.setMaxSpeed(8000);
    //        M7.setMaxSpeed(8000);
    //        M8.setMaxSpeed(8000);
    //        M9.setMaxSpeed(8000);
    //        M0.setTargetRel(targetDist[0]);
    //        M1.setTargetRel(targetDist[0]);
    //        M2.setTargetRel(targetDist[0]);
    //        M3.setTargetRel(targetDist[0]);
    //        M4.setTargetRel(targetDist[0]);
    //        M5.setTargetRel(targetDist[0]);
    //        M6.setTargetRel(targetDist[0]);
    //        M7.setTargetRel(targetDist[0]);
    //        M8.setTargetRel(targetDist[0]);
    //        M9.setTargetRel(targetDist[0]);
            
    //        for (int i = 0; i <= numMotors; i++) {                    // loop through all motors in motorSet_A...
    //          motorSet_A[i]->setTargetRel(targetDist[i]);                // ... set targets to 0...
    //          motorSet_A[i]->setMaxSpeed(S1MaxSpeed[i]);
    //          Serial.print(i); Serial.print(": MaxSpeed "); Serial.println(S1MaxSpeed[i]);
    //          Serial.print(i); Serial.print(": targetDist "); Serial.println(targetDist[i]);
    //        }
    //        Serial.print("M1: MaxSpeed "); Serial.println(S1MaxSpeed[0]);
    //        Serial.print("M1: TargetDist "); Serial.println(targetDist[0]);
            
            controller.move(motorSet_A);
    //        controller.move(motorSet_B);
    //          controller.move(motorSet_A, motorSet_B);
    //        controller.move(M0, M1, M2, M3, M4, M5, M6, M7, M8, M9);
    //        delay(5000);
            
            break;
    //      default:
    //        Serial.println("error");
    //        break;
        }
    //  lastScene = scene; 
    //  }
      
        if (flag1 == HIGH){
          if (b[0] == '*')
          {
            targetInterval = (b[1] << 8) | b[2]; 
            pulsePerSec = 1000000/targetInterval; //OLD SPEED STUFF
    //        Serial.print("Slave Speed: ");
    //        Serial.println(targetInterval, DEC); //target speed
            flag1 = LOW;
          }
        }
    
      delay(5000);
    }
    
    void receiveEvent(int howMany){
      for (int i = 0; i < howMany; i++){
        b[i] = Wire.read();
      }
      flag1 = HIGH;
    }

  12. #12
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    There is a known silly bug in stepcontrol.h line 8.

    Code:
    constexpr int MaxMotors = 10;
    You need to change MaxMotors to n+1 if you need n motors. I.e. set it to 11 if you need up to 10 motors. To do a quick test of your code I commented out the I2C stuff, compiled and had a look at a few motors with the logic analyzer. Seems to work, at lease at a first glance.

    Remarks:
    You probably know, but just in case you intended to initialize your arrays with the following code:
    Code:
    int targetDist[numMotors] = {20*spr}; //50x decent
    //int S1MaxSpeed[numMotors] = {50000};
    //int S1MaxSpeed[numMotors] = {1*PPR*microSteps};
    int S1MaxSpeed[numMotors] = {8000};
    This will only initialize the first element of the arrays to the given value, the rest of the array will be initialized to zero.

    Don't know if it is by purpose, but these arrays have only 9 elements. Your commented out code in loop suggests that you intended to have 10 not 9?
    Code:
    int targetDist[numMotors] = {20*spr}; //50x decent
    //int S1MaxSpeed[numMotors] = {50000};
    //int S1MaxSpeed[numMotors] = {1*PPR*microSteps};
    int S1MaxSpeed[numMotors] = {8000};
    Hope that helps

  13. #13
    Member
    Join Date
    Dec 2018
    Location
    Toronto Canada
    Posts
    24
    AMAZING! thank you for clarifying the bug and the array issue. I am sorry to ask so many questions, but really do appreciate your help.

    I still can't get 2 sets of motors to move. I get this error:
    no matching function for call to 'StepControl<>::move(Stepper* [5], Stepper* [5])'

    The other issue of only 1 case working i'll look into more online. If i comment out either case it seems to work
    (error: jump to case label [-fpermissive])

    Here's a vid of the progress (thanks to your help


    Main Loop:

    Code:
      int scene = 1;
      
    //  if (scene != lastScene){  // only go through if scene changes
        switch (scene){
    //      case 0:                         
    //        Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3, &M4, &M5, &M6, &M7, &M8, &M9};
    //        
    //        for (int i = 0; i < numMotors; i++) {                    // loop through all motors in motorSet_A...
    //          motorSet_A[i]->setTargetRel(targetDist[i]);                // ... set targets to 0...
    //          motorSet_A[i]->setMaxSpeed(S1MaxSpeed[i]);
    //        }
    //        
    //        controller.move(motorSet_A);
    ////        controller.move(motorSet_B);
    ////          controller.move(motorSet_A, motorSet_B);        
    //        break;
          case 1:
            Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3, &M4};
            Stepper* motorSet_B[] = {&M5, &M6, &M7, &M8, &M9};
    
            int distanceA = 20*spr;
            int distanceB = 20*spr;
            int speedA = 8000;
            int speedB = 7500;        
            
            for (int i = 0; i < 5; i++) {                    // 5 motors
              motorSet_A[i]->setTargetRel(distanceA);    
              motorSet_A[i]->setMaxSpeed(speedA);
              motorSet_B[i]->setTargetRel(distanceB);     
              motorSet_B[i]->setMaxSpeed(speedB);
            }
    
    //          M0.setTargetRel(distanceA);
    //          M0.setMaxSpeed(speedA);
    //          M1.setTargetRel(distanceA);
    //          M1.setMaxSpeed(speedA);
    //          M2.setTargetRel(distanceA);
    //          M2.setMaxSpeed(speedA);
    //          M3.setTargetRel(distanceA);
    //          M3.setMaxSpeed(speedA);
    //          M4.setTargetRel(distanceA);
    //          M4.setMaxSpeed(speedA);
    //          M5.setTargetRel(distanceA);
    //          M5.setMaxSpeed(speedA);
    //          M6.setTargetRel(distanceA);
    //          M6.setMaxSpeed(speedA);
    //          M7.setTargetRel(distanceA);
    //          M7.setMaxSpeed(speedA);
    //          M8.setTargetRel(distanceA);
    //          M8.setMaxSpeed(speedA);
    //          M9.setTargetRel(distanceA);
    //          M9.setMaxSpeed(speedA);
            
    //        controller.move(M0, M1, M2, M3, M4, M5, M6, M7, M8, M9);
            controller.move(motorSet_A, motorSet_B);
            break;
    //      default:
    //        Serial.println("error");
    //        break;
        }

  14. #14
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    I still can't get 2 sets of motors to move. I get this error:
    no matching function for call to 'StepControl<>::move(Stepper* [5], Stepper* [5])'
    Reason is that TeensyStep doesn't provide a method to pass in two arrays of steppers. I assume that your 4 motorSets are supposed to run independently? If so you need to setup a dedicated controller for each set. I.e. something like

    Code:
    StepControl<> controller1;
    StepControl<> controller2;
    StepControl<> controller3;
    StepControl<> controller4;
    Then, you can move a dedicated set of motors with each controller like this

    Code:
     
    Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3};
    Stepper* motorSet_B[] = {&M5, &M6, &M7, &M8, &M9, &M4};
    
    controller1.move(motorSet_A);
    controller2.move(motorSet_B);
    This would first move the motors from set A to their positions and then the motors from set B. If you want to run the motors from both sets in parallel you would do

    Code:
    Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3};
    Stepper* motorSet_B[] = {&M5, &M6, &M7, &M8, &M9, &M4};
    
    controller1.moveAsync(motorSet_A);
    controller2.moveAsync(motorSet_B);
    
    while(controller1.isRunning || controller2.isRunning) // optionally wait until movement is finished or continue with other tasks while the motors are running in the background
    {
      delay(10);
    }
    The other issue of only 1 case working i'll look into more online. If i comment out either case it seems to work
    (error: jump to case label [-fpermissive])

    c++ does not allow to define variables in a naked case statement https://stackoverflow.com/questions/...itch-statement . (motorSet_A[] in your case).

    Code:
    //      case 0:                         
    //        Stepper* motorSet_A[] = {&M0, &M1, &M2, &M3, &M4, &M5, &M6, &M7, &M8, &M9};
    //        
    //        for (int i = 0; i < numMotors; i++) {                    // loop through all motors in motorSet_A...
    //          motorSet_A[i]->setTargetRel(targetDist[i]);                // ... set targets to 0...
    //          motorSet_A[i]->setMaxSpeed(S1MaxSpeed[i]);
    //        }
    //        
    //        controller.move(motorSet_A);
    ////        controller.move(motorSet_B);
    ////          controller.move(motorSet_A, motorSet_B);        
    //        break;
    If you want to do that you have to wrap your case code in braces:

    Code:
    case 0:         
    { 
       ....
       break;
    }
    case 1: 
    { 
       ....
       break;
    }

    Had a look at your video, great work. Are you going to attach picture stripes on the faces to get a changing picture while moving? Anyway, looking forward to see TeensyStep moving 40 motors in parallel. I assume this has not been done before :-)
    Last edited by luni; 01-18-2019 at 06:56 AM.

  15. #15
    Hi again Luni! Fantastic, I am happy to be able to change one's motor speed on the fly, but where can I download the new library? The link you provided does not seem to still work... In the mean time I would like to ask if this can be done:

    Click image for larger version. 

Name:	1.jpg 
Views:	22 
Size:	37.4 KB 
ID:	16343

    For my winding application it would be great to fine-tune speeds on the fly while keeping accelereations / deccelerations in sync.

    The following would allow me some interesting winding patterns:

    Click image for larger version. 

Name:	2.jpg 
Views:	14 
Size:	37.6 KB 
ID:	16344

    Would this be possible with one controller? In case I need to use 2 controllers, I guess I would also need to pre-calculate the acceleration rates of the speed changes?

  16. #16
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    Nice coincident, I just came back from a Schumann /Schubert concert were I was wondering if they are already playing with your Teensyfied strings :-)

    but where can I download the new library
    Sorry, the new version is still on the development branch. (Just select branch:develop then you can download / clone) as usual).

    For my winding application it would be great to fine-tune speeds on the fly while keeping accelereations / deccelerations in sync.
    That will definitely be possible.

    ...[pictures] would this be possible with one controller?
    No, the motors moved by one controller will always rotate with a fixed speed ratio. But you can of course use two controller objects for that. However, what you have drawn seems to not only require an on-the-fly change of motor speed but also an on-the-fly change of acceleration? This currently is not possible, but shouldn't be a big deal to implement. Drop me a note if you really need this.

    Alternatively you could use a simple regulation algorithm and use the speed of motor1 to generate the target speed of motor2 (multiply speed1 by some factor). You'd then regulate motor2 to that target and change the factor on the fly. A similar thing is shown here
    https://forum.pjrc.com/threads/43491...l=1#post198919 and here https://forum.pjrc.com/threads/43491...l=1#post198994

  17. #17
    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.

    Quote Originally Posted by luni View Post
    Nice coincident, I just came back from a Schumann /Schubert concert were I was wondering if they are already playing with your Teensyfied strings :-)
    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:

    Click image for larger version. 

Name:	IMG_20190210_152320.jpg 
Views:	41 
Size:	187.9 KB 
ID:	16352

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

    Quote Originally Posted by luni View Post
    what you have drawn seems to not only require an on-the-fly change of motor speed but also an on-the-fly change of acceleration?
    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:

    Click image for larger version. 

Name:	3.jpg 
Views:	33 
Size:	50.0 KB 
ID:	16354

  18. #18
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    For the moment I can show my recently completed PCBs, basically a board for the periphery of the well known teensy breakout-board:
    They look good! So, you finally used a ECAD instead of Frizing? Looks like KiCad? One question: why do you have the T3.6 on the breakout and then the breakout on the board? Couldn't you design the T3.6 board directly into your board?

    Implementing your speed profile might be demanding. Therefore, of course, I'd like give it a try :-).

    However, I need some more information:
    1) First acceleration phase (t0-t1) This movement should be synced. I assume that the speed ratio of the motors and the acceleration are given to get the correct winding pitch. Right?
    2) At some time t2 you want to accelerate the red motor to a given, higher speed. Is the acceleration the same as at the beginning or is it arbitrary?
    3) At t3 you start decelerating in sync to new target speeds. Should the speed ratio of both motors be the same as it was in the first phase? Or are the target speeds given and the speed ratio follows?
    4) Same question for the last phase

    Given your winding application I thought that you would need a constant speed ratio all the time which would determine the target speeds of one of the motors, but I'm not sure. Especially the phase between 3) and 4) will definitely have a different ratio, looks like you want some larger pitch at the end of the winding?

  19. #19
    Quote Originally Posted by luni View Post
    Looks like KiCad? One question: why do you have the T3.6 on the breakout and then the breakout on the board? Couldn't you design the T3.6 board directly into your board?
    Yes, KiCad. I wanted to be able to replace it in case I again burn it so I used some boards I already had in hand which have socketed teensys. Also it seemed easier to not have to worry about the pogo pins needed for some of the inner teensy pads...

    Quote Originally Posted by luni View Post
    Implementing your speed profile might be demanding. Therefore, of course, I'd like give it a try :-)
    Many thanks!!!! I will try to explain: here a short video showing a test winding (with recycled i.e. crude and dirty material). The wires are fed towards the core in a way shown in the following diagram:

    Click image for larger version. 

Name:	wire.jpg 
Views:	15 
Size:	70.8 KB 
ID:	16363

    What I do during winding is to pull the winding wire slightly backwards to make the winding tighter: this is marked (b) on the above diagram. At the moment I have to stop the process, move the feeder a little bit backwards, start again and continue to wind, often with a tad narrower pitch. It would be amazing if I could adjust that on the fly. Also many winding wires are not perfectly even: so if the wire becomes thinner, I would reduce the speed of the feeder a little bit, ending up with a narrower pitch. There are many similar situations where I adjust the ratio, and I always have to stop, change the pitch and start again... This is doable, but...

    Quote Originally Posted by luni View Post
    1) First acceleration phase (t0-t1) This movement should be synced. I assume that the speed ratio of the motors and the acceleration are given to get the correct winding pitch. Right?
    Correct!

    Quote Originally Posted by luni View Post
    2) At some time t2 you want to accelerate the red motor to a given, higher speed. Is the acceleration the same as at the beginning or is it arbitrary?
    Arbitrary!

    Quote Originally Posted by luni View Post
    3) At t3 you start decelerating in sync to new target speeds. Should the speed ratio of both motors be the same as it was in the first phase? Or are the target speeds given and the speed ratio follows?
    The latter. From t2 to the end I wanted to keep the ratio.

    Quote Originally Posted by luni View Post
    4) Same question for the last phase
    Same answer, only that the target speed is zero. To be precise: I don't want the ratio to change during acceleration or deceleration. As long as I change only the speed of one of the motors all future speed changes shall have the new ratio until I again change the ratio by changing the speed of one of the motors.

    I can say that if you read my diagram in #17 backwards it happends exactly what I tried to describe: I start with a slower speed (t4), go higher as soon as I feel comfortable (t3 to t2), then lower the red speed (between t2 and t1: i.e. for pulling back the winding wire), and finally stop at t0.

  20. #20
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    Thanks for the explanation and the video. The speed and precision of the winding is quite impressive. I think I understand now what you want to achieve.

    To see what is possible I did a quick experiment with two controllers. I.e, I do not use the usual synced motion (which is not possible since you need to change the speed ratio on the fly). Instead I try to sync the motors by precalculating the acceleration of the red motor. (The following is only showing the first phase of your speed profile, I only wanted to test the accuracy of the method)

    Settings:
    The green motor is set to v=15000 / a=10000 the red motor to v=8000. Acceleration of the red motor is set to a=10000*(8000/15000) to reach the target speed at the same time as the green motor (theoretically). I print out time, motor positions, motor speeds and speed ratios every 20ms. Here the code if you want to experiment.

    Code:
    #include "Arduino.h"
    #include "TeensyStep.h"
    
    Stepper greenMotor(0, 1), redMotor(1, 2);
    RotateControl greenCtrl(5,10000), redCtrl(5,10000); //needed to increase the acc_update period to get required accuracy
    
    int greenSpeed = 15000;
    int greenAcc = 10000;
    
    int redSpeed = 8000;
    int redAcc =  greenAcc * redSpeed / greenSpeed;
    
    void setup()
    {
      while(!Serial);
      
      greenMotor
          .setMaxSpeed(greenSpeed)
          .setAcceleration(greenAcc);
    
      redMotor
          .setMaxSpeed(redSpeed)
          .setAcceleration(redAcc);
    
      redCtrl.rotateAsync(redMotor);
      greenCtrl.rotateAsync(greenMotor);
    }
    
    elapsedMillis stopwatch = 0;
    
    void loop()
    {
      if (stopwatch > 20)
      {
        stopwatch = 0;
    
        // printout position, speed and ratio for the motors
        // tab seperated for import to spreadsheet
        int greenPos = greenMotor.getPosition();
        int greenSpeed = greenCtrl.getCurrentSpeed();
        int redPos = redMotor.getPosition();
        int redSpeed = redCtrl.getCurrentSpeed();
        float ratio = (float)greenSpeed /redSpeed;
        
        Serial.printf("%d\t%i\t%i\t%i\t%i\t%.4f\n", millis(), greenPos, redPos, greenSpeed, redSpeed, ratio);
      }
    }
    While this works in principle, the accuracy of the method is somehow borderline. The reason is that the acceleration algorithm is integer based so that you don't get a perfect speed ratio during acceleration. To improve the situation I needed to increase the acceleration update time to 10ms.

    Below a plot of the motor speeds(red,green, left axis, Hz) and ratio (yellow, right axis) over time (ms):

    Click image for larger version. 

Name:	ratio1.PNG 
Views:	13 
Size:	11.8 KB 
ID:	16365

    All in all it might work, but I don't like it. A true synchronization would be much more elegant. I'll think of something better...

  21. #21
    Many thanks for the explanation and the code!!! I tried to play with your code and managed to run it, but observed some details I don't fully understand...

    Here is a version of your code with just the last 2 lines added / modded:

    Code:
    #include "Arduino.h"
    #include "TeensyStep.h"
    
    Stepper greenMotor(22, 41), redMotor(43, 42);
    RotateControl greenCtrl(5, 10000), redCtrl(5, 10000); //needed to increase the acc_update period to get required accuracy
    
    int greenSpeed = 15000;
    int greenAcc = 10000;
    
    int redSpeed = 8000;
    int redAcc =  greenAcc * redSpeed / greenSpeed;
    
    void setup(){
      while (!Serial);
    
      greenMotor
      .setMaxSpeed(greenSpeed)
      .setAcceleration(greenAcc);
    
      redMotor
      .setMaxSpeed(redSpeed)
      .setAcceleration(redAcc);
    
      redCtrl.rotateAsync(redMotor);
      greenCtrl.rotateAsync(greenMotor);
    }
    
    elapsedMillis stopwatch = 0;
    
    void loop(){
      if (stopwatch > 20){
        stopwatch = 0;
    
        // printout position, speed and ratio for the motors
        // tab seperated for import to spreadsheet
        int greenPos = greenMotor.getPosition();
        int greenSpeed = greenCtrl.getCurrentSpeed();
        int redPos = redMotor.getPosition();
        int redSpeed = redCtrl.getCurrentSpeed();
        float ratio = (float)greenSpeed / redSpeed;
        float ratioPos = (float)greenPos / redPos;
    
        Serial.printf("%d\t%i\t%i\t%i\t%i\t%.5f\t%.5f\n", millis(), greenPos, redPos, greenSpeed, redSpeed, ratio, ratioPos);
      }
    }
    The serial output gives me a constant speed-ratio but a differing position-ratio which starts a little to high and slowly decreases until it equals the speed-ratio. I tried to verify that with a one-controller version:

    Code:
    #include "Arduino.h"
    #include "TeensyStep.h"
    
    Stepper greenMotor(22, 41), redMotor(43, 42);
    RotateControl Motors(5, 10000);
    
    int greenSpeed = 15000;
    int greenAcc = 10000;
    
    int redSpeed = 8000;
    int redAcc =  greenAcc * redSpeed / greenSpeed;
    
    void setup(){
      while (!Serial);
    
      greenMotor
      .setMaxSpeed(greenSpeed)
      .setAcceleration(greenAcc);
    
      redMotor
      .setMaxSpeed(redSpeed)
      .setAcceleration(redAcc);
    
      Motors.rotateAsync(redMotor, greenMotor);
    }
    
    elapsedMillis stopwatch = 0;
    
    void loop(){
      if (stopwatch > 20){
        stopwatch = 0;
    
        // printout position, speed and ratio for the motors
        // tab seperated for import to spreadsheet
        int greenPos = greenMotor.getPosition();
        int redPos = redMotor.getPosition();
        float ratioPos = (float)greenPos / redPos;
    
        Serial.printf("%i\t%i\t%.5f\n", greenPos, redPos, ratioPos);
      }
    }
    Same observation. Is my understanding wrong...? I am not totally sure about this but I think I saw something similar during winding: the ratio slowly catches up after start acceleration... I though this was a drift because of wire unevenness, but now there is hope my wires are fine...?

    Another observation:

    Code:
    #include "TeensyStep.h"
    
    Stepper motor(22, 41);
    RotateControl controller(5, 1000);
    
    void setup() {
      delay(1000);
    
      motor
      .setMaxSpeed(-124)
      .setAcceleration(198);
    
      controller.rotateAsync(motor);     // not moving at all...
      delay(2000);
      controller.stop();
    
      motor
      .setMaxSpeed(124)
      .setAcceleration(198);
    
      controller.rotateAsync(motor);
      delay(2000);
      controller.stop();                 // not able to stop...
    }
    
    void loop() {}
    Here it seems the motor doesn't move at all in the negative direction at very slow speeds, and in the positive direction it starts but I can't stop it. Both worked with an older pre speedOverride() version and pullin-speed set to 50.

    (BTW I could only compile after removing the line "arduino.h" in stepper.h, and after renaming the folder "accelerators" to "Accelerators")

  22. #22
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    I would say your observed effect is simply an effect of discrete mathematics:
    Assume that the second motor runs at say 1/3 of the speed of the first motor. I.e, after 3 steps of the first motor the second motor makes one step (see table below). If you calculate the position ratio out of that you see the effect you observed. For small total step numbers the calculation "error" is large. Of course, the higher the step numbers get the smaller the relative "error" and you approach the expected value 0.333 for the ratio.

    Code:
    pos 1	pos2	pos2/pos1
    1	1	1.000
    2	1	0.500
    3	1	0.333
    4	2	0.500
    5	2	0.400
    6	2	0.333
    7	3	0.429
    8	3	0.375
    9	3	0.333
    10	4	0.400
    11	4	0.364
    12	4	0.333
    13	5	0.385
    14	5	0.357
    15	5	0.333
    16	6	0.375
    17	6	0.353
    18	6	0.333
    Here it seems the motor doesn't move at all in the negative direction at very slow speeds, and in the positive direction it starts but I can't stop it. Both worked with an older pre speedOverride() version and pullin-speed set to 50.
    I can reproduce that, looks like you found a bug for small speeds. I'll have a look into it.


    I also did some work on your original problem. Below you see the resulting motor speeds (red, green, using the left y-axis). The yellow curve is the speed ratio (using the right y-axis). Don't worry about the small wiggles in the curves, these again are only calculation effects.

    Click image for larger version. 

Name:	ratio2.PNG 
Views:	16 
Size:	23.0 KB 
ID:	16385

    As you see, both motors run synchronized all the time, i.e. the speed ratio stays constant, i.e. the red motor precisely follows the green one with the given ratio. Besides the usual speed override, the code enables you now to change the speed ratio on the fly. It starts with a ratio of 0.6 (green maxSpeed = 15000, red maxSpeed= 9000) At t=6s I changed the ratio to 0.8. I didn't bother to slowly change the ratio from the old value to the new value. I assume that you will only use that to slightly trim the pitch of your winder, so in reality the changes will be small enough to avoid step losses due to the sudden change in speed.

    The current code is quite messy and a proof of principle only. I'll clean it up and post it later today.

  23. #23
    Quote Originally Posted by luni View Post
    I would say your observed effect is simply an effect of discrete mathematics:
    Assume that the second motor runs at say 1/3 of the speed of the first motor. I.e, after 3 steps of the first motor the second motor makes one step (see table below). If you calculate the position ratio out of that you see the effect you observed. For small total step numbers the calculation "error" is large. Of course, the higher the step numbers get the smaller the relative "error" and you approach the expected value 0.333 for the ratio.
    Thanks for clarification!

    Quote Originally Posted by luni View Post
    I also did some work on your original problem. Below you see the resulting motor speeds (red, green, using the left y-axis). The yellow curve is the speed ratio (using the right y-axis). Don't worry about the small wiggles in the curves, these again are only calculation effects.
    This is very promising, I can't wait to test it...

    Quote Originally Posted by luni View Post
    I assume that you will only use that to slightly trim the pitch of your winder, so in reality the changes will be small enough to avoid step losses due to the sudden change in speed.
    Yes exactly, and I use these motors, so I am not too worried about step losses.

    I observed also something else which I did not test until now:

    Code:
    #include "TeensyStep.h"
    
    Stepper motor(22, 41);
    RotateControl controller;    // Use default settings
    
    void setup() {
      pinMode(7, INPUT_PULLUP);
      attachInterrupt(digitalPinToInterrupt(7), ISR, CHANGE);
    
      motor
      .setMaxSpeed(10000)
      .setAcceleration(1000);
      controller.rotateAsync(motor);
    }
    
    bool estop_flag;
    
    void ISR() {
      estop_flag = 1;
    }
    
    void loop() {
      if (estop_flag == 1) {
        controller.emergencyStop();
        estop_flag = 0;
      }
    }
    In this code I can stop the motor only after acceleration is completed, so I can't use pin-interrupts for my limit switches. Is this intended?

  24. #24
    Just a small update: I noticed that the low speed bug is fixed. I implemented speed override and now can change the speed during winding which is really useful for me. Thanks a lot!

    Regarding my limit switch / homing question: as advised I tried to design a homing routine (i.e. push the switches to keep track of the absolute positions). During acceleration/deceleration the limit switches would not fire: I tried that by polling the pin and also with pin interrupts without success. But with the motors driving slowly and without acceleration it was possible.

    After homing is done I can use the motor.setTargetAbs(precalculated) and controller.move() commands safely, but I can't get overrideSpeed() to work in StepControl mode. And in RotateControl mode I could not use the setTarget() commands. I would love to make use of the override commands but I am reluctant to give up on the position tracking...

  25. #25
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    442
    I'm currently traveling and can only answer briefly from my mobile.
    Yes, I fixed the acceleration bug and added an override acceleration feature. Both are only implemented for the rotation controller (currently). Anyway, all controllers keep track of position. You do not need to stick with one controller and can switch to another after a move. Position Will be correct.

    I could reproduce the estop bug, but it is not yet fixed.

    Redid the speed profile experiments with the the override acceleration which works great. Stay tuned...
    BTW: can you add some typical numbers to the speed profile (time and velocities)?

    I don't understand the issue with homing. Can you do a quick sketch showing the problem?

Posting Permissions

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