Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 14 of 14

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
    378
    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:	16 
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
    378
    ...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
    378
    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
    378
    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:	10 
Size:	11.0 KB 
ID:	15421

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    378
    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
    378
    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
    378
    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.

Posting Permissions

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