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

Thread: New Stepper Motor Library

  1. #1
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306

    New Stepper Motor Library

    Since I didn't find a stepper motor library meeting my needs I rolled my own and finally published it
    on gitHub https://github.com/luni64/TeensyStep. You'll find a detailed description there.

    Here the key specification of the library

    Motor speed / pulse rate 1 - 300'000 stp/s
    Acceleration 0 - 500'000 stp/s^2
    Pull in speed (speed up to which no acceleration is required) 50-10'000 stp/s
    Synchronous movement of motors up to 10
    Asynchronous movement of motors 4 groups of 1 to 10 motors
    Settable step pulse polarity Active high or low
    Settable step pulse width 1-100Ás
    Settable direction signal polarity cw/ccw

    The library is compatible to T3.0 T3.1 T3.2, T3.5 and T3.6. As always, it's amazing what can be done
    with those boards. Handling 3 synchronously running motors at a pulse rate of 50kHz-including
    Bresenham and acceleration calculations- generates a load of only 6.5% for a T3.6 (@240MHz)
    and about 17% for a T3.2 (@96MHz). The generated load is linear in motor speed, i.e. half the step rate
    generates half the load.

    The picture below shows some additional performance information.

    Click image for larger version. 

Name:	load_calculation.PNG 
Views:	135 
Size:	67.4 KB 
ID:	10354

    Hope the library is of use for somebody. As always: any feedback welcome
    Have fun

  2. #2
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    Just fixed a strange compatibility issue with GCC 5.4 / Teensyduino 1.36. (Thanks to Per Magnusson for that). TeensyStep should work now with all recent versions of Teensyduino.

  3. #3
    Junior Member
    Join Date
    Nov 2015
    Posts
    14
    This is a great library! I can see why Paul featured it! Really beautiful code; you have a great grasp of the language and very solid coding practices.

    My experience using it has been good so far. Examples compiled fine with Teensyduino 1.4.0 and Arduino 1.8.5. I couldn't get it to compile with Sublime Text 3 with the latest Stino (it's upset about trying to find WProgram.h for the optimized math functions, but that's not an issue with your library really).

    One note that I have is that you can't really change speed in real time. Obviously the most common hobbyist application is for CNC machines which just coast at a constant top speed, so that might not be an issue for many users. I'm trying to add some basic feedback with an encoder, and when I see that the encoder position lags behind the stepper position, I know I've missed steps (or stalled), so I want to reduce the speed, update the position target and continue, but the library won't decelerate down to a lower speed if the motor's maxspeed is changed while the motor is running. If you change the speed while running and call the controller start function again, the motor slams to a stop and accelerates up to the new top speed. I currently have to fully safely stop, change the speed and start again. I'll dig into the code and see if there's something I'm missing or an elegant way to add that in.

    Do you have any thoughts on adding true closed loop functionality? I'd like to take N steps, read an encoder (or get some other position feedback), feed that into the controller/motor object, and have it adjust while staying synchronized.

    Also, what is the acceleration algorithm called? I'd like to learn more about that.

    Thanks for putting all this work in and publishing it!
    Last edited by TMcGahee; 09-28-2018 at 07:22 PM.

  4. #4
    Junior Member
    Join Date
    Nov 2015
    Posts
    14
    Alright, after spending the day with this, there are some unexpected behaviors and room for improvement, but otherwise a solid library.

    Here's a sketch that uses an encoder connected to the output of the stepper motor. The stepper accelerates to some high speed, and if/when it stalls, it is detected, the motor is stopped, top speed is reduced by 10%, correct position calculated, and then the motor continues onto its target.

    This has been useful to me as a sort of quick-and-dirty way of finding a reasonable top speed under varying mechanical loads.
    Code:
    #include "StepControl.h"
    Stepper motor(2,3);
    StepControl<> controller;
    uint32_t maxSpeed = 10000;
    int32_t stepStartingPos = 0;
    
    #include "Encoder.h"
    Encoder myEnc(17, 18);
    const float encCountsPerStep = 0.24; // Based on the settings from my motor driver and encoder properties, every stepper step = 0.24 encoder counts
    int32_t encStartingPos = 0;
    
    int state = 0;
    bool lastMoveWasUp = true;
    int32_t setPosition = 0;
    
    elapsedMillis errorCheckTimer = 0;
    const unsigned int errorCheckTime = 100;
    const int maximumPositionLag = 2400; // 0.24rev*(2400counts/rev)/0.24encCountsPerStep
    
    void setup(){
    	// set up motor
    	motor.setMaxSpeed(maxSpeed);
    	motor.setAcceleration(800);`
    
    	Serial.begin(115200); // Talk over USB
    	while(!Serial);
    	delay(100);
    }
    
    void loop(){
    	switch(state) {
    		case 0: // idle
    			// calculate and start next move
    			setPosition = lastMoveWasUp?-500000:0;
    			lastMoveWasUp = !lastMoveWasUp;
    	 
    			// motor.setTargetRel(setPosition);
    			motor.setTargetAbs(setPosition);
    			Serial.print("Going to position ");
    			Serial.println(setPosition);
    
    			state = 1;
    			errorCheckTimer = 0;
    			// get starting motor position reading
    			// get starting encoder reading
    			encStartingPos = myEnc.read();
    			stepStartingPos = motor.getPosition();
    
    			controller.moveAsync(motor);
    			break;
    		case 1: // moving
    			// check that we haven't fallen too far behind
    			if(errorCheckTimer > errorCheckTime){
    				errorCheckTimer = 0;
    				// else stop, reduce max speed and add steps to the setPosition
    
    				// calculate position lag
    				int32_t encPosDelta = round((myEnc.read() - encStartingPos)/encCountsPerStep);
    				int32_t stepPosDelta = motor.getPosition() - stepStartingPos;
    				int32_t positionLag = stepPosDelta - encPosDelta;
    
    				// if greater than threshold
    				if(abs(positionLag) > maximumPositionLag){
    					// reduce the top speed and report
    					maxSpeed = 0.9*maxSpeed;
    					motor.setMaxSpeed(maxSpeed);
    					Serial.print("At motor position ");
    					Serial.print(motor.getPosition());
    					Serial.print(", Max Speed reduced to: ");
    					Serial.println(maxSpeed);
    
    					// stop the motor safely
    					// would love to stop quickly, but changing motor.accel() has no effect
    					controller.stop();
    					delay(250);
    
    					// recalculate the position lag after the motor deceleration phase
    					Serial.print("Motor position changed from ");
    					Serial.print(motor.getPosition());
    
    					// include a recalculation of the encoder delta because sometimes the motor will exit stall during decel
    					encPosDelta = round((myEnc.read() - encStartingPos)/encCountsPerStep);
    					stepPosDelta = motor.getPosition() - stepStartingPos;
    					positionLag = stepPosDelta - encPosDelta;
    
    					// update motor position
    					motor.setPosition(motor.getPosition()-positionLag);
    
    					Serial.print(" to ");
    					Serial.println(motor.getPosition());
    
    					// have to set target again, or else motor will stop at a random location
    					motor.setTargetAbs(setPosition);
    
    					// get motor moving again
    					controller.moveAsync(motor);
    				}
    			}
    
    			// if motor was sent the correct number of steps, motion is done
    			if(!controller.isRunning()){
    				state = 0;
    				Serial.print("Stopped at motor position ");
    				Serial.print(motor.getPosition());
    				Serial.println();
    			}
    
    			break;
    		default:
    			state = 0;
    	}
    }
    Here's an example of the serial output data:
    Click image for larger version. 

Name:	Capture.JPG 
Views:	18 
Size:	51.7 KB 
ID:	14852


    Some of the unexpected behavior:
    • As with the speed, changing the acceleration value while the motor is running has no effect
    • If you stop the motor while moving, and then start moving again without setting the target position again, the motor will stop at the incorrect location.
    • emergency stop does not reset the motor into a useful state. A lot of reconfiguration is needed to have it be useful again. I've opted to use the motor.stop() function here, which has its own issues: stopping a stalled motor from a high set speed takes a long time, and the motor will reengage the load again while decelerating, shifting the position by an unpredictable amount.


    I hope this information is helpful to you or others who'd like to use the library. I know it's very difficult to document every behavior and design decision in complex code.

    Thanks again for releasing the library

  5. #5
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    Glad that you like TeensyStep. Let me try to answer your questions.

    Quote Originally Posted by TMcGahee View Post
    ... One note that I have is that you can't really change speed in real time [...] If you change the speed while running and call the controller start function again, the motor slams to a stop and accelerates up to the new top speed. I currently have to fully safely stop, change the speed and start again.
    That's true, the design goal was to generate an accelerated and synchronized move of a bunch of steppers from A to B at very high step rates (or equivalently, with low processor load). Thus, the library pre calculates as much as possible before the movement starts. During the movement it just uses the precalculated values. If you set new parameters and start a new movement while the motors run that will generate a mess. I'll try to safeguard this in a new version.

    Anyway, you are not the first asking for a possibility to change the motor speed during a movement. I have that on the improvement list and hope to find some time soon to implement it.

    Do you have any thoughts on adding true closed loop functionality?
    No, closed loop movement would be a completely different story. To be honest, I never understood why people try to use steppers for a closed loop movement. The beauty of steppers is that you do not need any position feedback and simply move them to the target position. In applications where a feedback is required (safety?, varying loads?) I'd think of using a servo, they are made for closed loop movments. But that is my personal opinion only... If you look at DIY CNC forums you will find flaming discussions about this topic. Much like the good old Windows / Linux flame wars :-)

    Also, what is the acceleration algorithm called?
    It basically uses the standard constant acceleration, i.e. s(t) = 0.5a*t^2, with s=position, a= acceleration, t=time. Of course we need speed (v) and don't want time as parameter so you insert v=a*t to get: v(s)=sqrt(2a*s). All you need to do now is regularely calculating a new v and set the timer reload value accordingly.

    Some of the unexpected behavior:
    As with the speed, changing the acceleration value while the motor is running has no effect
    Yes, see above.

    If you stop the motor while moving, and then start moving again without setting the target position again, the motor will stop at the incorrect location.
    Yes, currently you need to always set a target position before moving. But I understand your point and put it on the wish list.

    emergency stop does not reset the motor into a useful state. A lot of reconfiguration is needed to have it be useful again.
    Can you explain what you need to reconfigure after an emergency stop? It should not change any configuration, if it does, that would be a bug...

    I've opted to use the motor.stop() function here, which has its own issues: stopping a stalled motor from a high set speed takes a long time, and the motor will reengage the load again while decelerating, shifting the position by an unpredictable amount.
    Yes, but this is exactly how "stop" it is supposed to work, isn't it? It decellerates the motor to a stop. This will take exactly as long as it took to accelerate it. The fact that the load engages again at a low frequency is physics. In case of a stalled motor (which should never happen during normal operation) I would simply do an emergency stop.

  6. #6
    Junior Member
    Join Date
    Jun 2017
    Posts
    14
    I also agree this is a great library, and I can see that they commands that are exposed have been well thought out.

    In my case I am using it to position the azimuth and elevation of a tracking antenna for fast moving things like UAVs. The azimuth motor can be commanded to any position via a command that accepts 0 to 360 degrees, and the elevation motor from 0 to 90 degrees. However one shortfall in this situation is that I need to be able to update the target position while the motor is still moving to the previous target position. The library doesn't seem to support that, so I have to queue the latest position request and wait for the motor to stop moving, then move it to the new position, but then of course there could be a new updated position before the motor has stopped. The system needs to be able to track relatively fast.

    Any thoughts on the ability to update the target position while the motor(s) are still moving? I realize it could be a can of worms in some respects if for example deceleration is underway and the new target position is before the existing target position. I've considered rolling my own library but the existing one is too nice.

  7. #7
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    Changing the target position of one motor during the move is not a principle problem, but the main design goal of TeensyStep was to move a couple of motors in sync. If you change the target of one of the synced motors what should happen with the others? I'm afraid that would require a recalculation / resetting of the bresenham and the acceleration paramters. This can hardly be done in between two steps. So the movement would most probably be disturbed or the maximum step rate would need to be limited.

    Alternatively I could imagine a solution for a single motor movement. I could add a new, specialized controller object for those cases. You could then switch on the fly between the current synced movment and a "variable" movement of one motor by using different controllers. Would that solve your problem?

  8. #8
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306

    Call back function on completion of async move

    As requested recently I uploaded a version with callback functionality (https://github.com/luni64/TeensyStep/issues/18). The callback function is called whenever a move is finished. If you want to give it a try you find it in the development branch of the github repo. Use carefully, the callback is called from within an interupt context. So avoid fancy things and return as quickly as possible.

    Here a quick example of the usage. It moves a motor in the background to a set of predefined target positions.

    Code:
    #include "Arduino.h"
    #include "StepControl.h"
    
    Stepper motor(0, 1);
    StepControl<> controller;
    
    constexpr int targetPositions[]{500, -50, 50, 0};
    constexpr int nrOfPositions = sizeof(targetPositions) / sizeof(targetPositions[0]);
    
    void newMotorTarget()
    {
      static int posNr = 0;
    
      motor.setTargetAbs(targetPositions[posNr]);
      controller.moveAsync(motor);
    
      posNr = (posNr + 1) % nrOfPositions;
    }
    
    void setup()
    {
      pinMode(LED_BUILTIN, OUTPUT);
    
      motor
       .setAcceleration(500)
       .setMaxSpeed(10000);
    
      controller.setCallback(newMotorTarget);
      newMotorTarget();  // start the movment sequence
    }
    
    // motor runs completely in the background. Nothing to do in loop
    void loop()
    {
      digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
      delay(500);
    }

  9. #9
    Junior Member
    Join Date
    Jun 2017
    Posts
    14
    Luni, I didn't initially realize that I could create multiple controllers that could operate motors independently of each other. My system is very different from a CNC application, and the motors need to operate completely independently of each other. This seems to be working now that I have created two controllers. I'm now even more impressed with this library, as I was considering having a separate Teensy for each motor so that I could use this library.

    Regarding the modified library that provides the callback.... do I understand correctly that the change essentially allows the motor to move to several different target positions sequentially, and between each move it stops and then starts the move to the next target?

    Regarding your comment "If you change the target of one of the synced motors what should happen with the others?"...... As you can see in my application the motors aren't synced, so it would have no effect. They operate completely independently of each other..... e.g. one may be stopped while the other is moving, or they could be both moving with no correlation between them.

    It would be a really cool feature if they could be re-targeted while moving. Probably would make the library quite attractive to the robotics community as well.

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    Regarding the modified library that provides the callback.... do I understand correctly that the change essentially allows the motor to move to several different target positions sequentially, and between each move it stops and then starts the move to the next target?
    The change allows the user to attach a callback function to the controllers. This callback wil be called whenever a controller finished a movement which can be useful for lot of things. You could simply switch an LED on when you start a movment and the callback would switch it off again when the movment is done. Or, as shown in the example, when a movment is finished you can start the next one in the background without having to run a polling loop somewhere. I'm sure there are a lot of other use cases for this feature.

    Regarding your comment "If you change the target of one of the synced motors what should happen with the others?"...... As you can see in my application the motors aren't synced, so it would have no effect. They operate completely independently of each other..... e.g. one may be stopped while the other is moving, or they could be both moving with no correlation between them.
    It would be a really cool feature if they could be re-targeted while moving. Probably would make the library quite attractive to the robotics community as well.
    I put the re-target feature on my list of required enhancements. Hope to find some time soon.

  11. #11
    Junior Member
    Join Date
    Jan 2016
    Posts
    19

    Synchronizing callback

    I would like to run one motor alternating directions and one running in one direction only. Each needs to start and end at the time. The following sort of works, but the motors don't stop at the same time:
    Code:
    constexpr int targetPositions[]{ 2500, 0, 2500, 0 };
    constexpr int nrOfPositions = sizeof(targetPositions) / sizeof(targetPositions[0])
    
    void newMotorTarget()
    {
    	static int posNr = 0;
    
    	motor_Spindle.setTargetAbs(targetPositions[posNr]);
    	controller.moveAsync(motor_Spindle);
    
    	posNr = (posNr + 1);// % nrOfPositions;
    
    }
    
    void WaveSpindle_Z()
    {
    	motor_Axis_Z
    		.setAcceleration(50000)
    		.setMaxSpeed(40000)
    		.setTargetRel(10000);
    
    	motor_Spindle
    		.setAcceleration(50000)
    		.setMaxSpeed(40000);
    	controller_2.moveAsync(motor_Axis_Z);
    	controller.setCallback(newMotorTarget);
    	newMotorTarget();  // start the movment sequence
    }
    Is this type of synchronization possible?

  12. #12
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    Looks like a winder application? Maybe this thread https://forum.pjrc.com/threads/50148...l=1#post180627 post #32 to #40 can help?

  13. #13
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    The two controller routine didn't stop at the same time. I suspect that's caused by the acceleration and deceleration of the linear motor.

    The pin changing routine will be useful, but I would also like to accelerate and decelerate the linear motor in order to generate sine(like) waves. The callback method looked promising as it accelerates and decelerates at each set point, but adding the rotation motor to the same controller didn't work.

  14. #14
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    So, if I understand correctly, you want to start both motors together. While the axis motor keeps running you want the spindle motor moving back anf forth. After some cycles of the spindle motor you want to have both motors stop at the same time? Can you confirm?

  15. #15
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    Yes, that is correct.

  16. #16
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    The problem with this is that the motors can not be run synced since during the acceleration / deceleration phases of the spindle motor they are necessarily out of sync. You can however use two controllers and sync them manually. But honestly, TeensyStep is probably not the best solution for this problem. Anyway, here a quick idea:

    1) Start both motors in async rotation mode
    2a) If the spindle motor reaches a given position and you want to do further cycles send a stop command to the spindle motor
    2b) If you want to stop the complete movement send a stop command to both of the motors and leave.
    3) Wait until the motor is stopped and start the rotation in the oposite direction
    4) continue with 2

    This is not elegant at all but it works. Here a quick video: https://youtu.be/yaiGFk7nBaM
    Left linear axis simulates the spindle motor, the motor with the blue arrow on the right side simulates the axis motor. Spindle motor moves up/down for 5 cycles, both motors stop at the same time.

    And here the code from the video which implements the algorithm in a small state machine. Please note: this is only a very quick proof of principle and needs a lot of improvment if you really want to use it.

    Code:
    #include "Arduino.h"
    #include "StepControl.h"
    
    int cycleWidth, direction, cycleCounter, nuberOfCycles, maxSpeed;
    
    enum class state
    {
      waiting,
      starting,
      startingCycle,
      runningCycle,
      stoppingCycle,
      stopping,
    } currentstate;
    
    Stepper spindleMotor(0, 1);
    Stepper axisMotor(2, 3);
    
    StepControl<> spindleController;
    StepControl<> axisController;
    
    void tick()
    {
      int position = spindleMotor.getPosition();
    
      switch (currentstate)
      {
      case state::waiting:
        break;
    
      case state::starting:   
        direction = 1;
        axisMotor.setMaxSpeed(maxSpeed);
        axisController.rotateAsync(axisMotor); 
        // fallthrough intended
    
      case state::startingCycle:    
        direction *= -1;
        spindleMotor.setMaxSpeed(direction * maxSpeed);
        spindleController.rotateAsync(spindleMotor); // start spindle motor, as long as maxSpeed and acceleration of both motors are the same the will run in sync
        currentstate = state::runningCycle;
        break;
    
      case state::runningCycle:   
        if (direction * position >= cycleWidth) // did the spindle motor reach the cycleWidth
        {
          if (cycleCounter < nuberOfCycles) // cycles left? -> initiate new cycle
          {
            cycleCounter++;
            spindleController.stopAsync();
            currentstate = state::stoppingCycle;
          }
          else // all cycles done, stopping both motors
          {      
            spindleController.stopAsync();
            axisController.stopAsync();
            currentstate = state::stopping;     
          }
        }
        break;
    
      case state::stoppingCycle:
        if (!spindleController.isRunning())
          currentstate = state::startingCycle;
        break;
    
      case state::stopping:
        if (!spindleController.isRunning() && !axisController.isRunning())
        {
          currentstate = state::waiting;
          Serial.println("done");     
        }
        break;
      }
    }
    
    void setup()
    {
      pinMode(LED_BUILTIN, OUTPUT);
     
      spindleMotor.setAcceleration(60000);     
      axisMotor.setAcceleration(60000);
          
      cycleWidth = 500; // steps
      maxSpeed = 10000;
      nuberOfCycles = 5;
    
      currentstate = state::starting;
    }
    
    elapsedMillis stopwatch = 0;
    void loop()
    {
      tick();
    
      // do other things here but make sure to call tick() often enough. Alternatively you can call tick in an IntervallTimer....
    
      if (stopwatch > 100)
      {
        stopwatch = 0;
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
      }
    }

  17. #17
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    When acceleration is set to the max, 500000, how many steps are used in the stop command? Does it behave the same as an emergency stop?

  18. #18
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    That obviously depends on the speed from which you want to decellerate. Acceleration of 500000 means that you would ramp up/down from 0 stp/sec to 500000stp/sec in one sec. For any practical applications this is very close to an emergency stop.

  19. #19
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    I did get the callback method working, but it doesn't return control to the main program after completing the cycles. The only changes are the names of the motors and controllers plus changing posNr so it would only run through the cycle once. The Teensy appears to be hung after newMotorTarget() runs.

    Code:
    void newMotorTarget()
    {
    	static int posNr = 0;
    
    	motor_Spindle.setTargetAbs(targetPositions[posNr]);
    	controller_Spindle.moveAsync(motor_Spindle);
    
    	posNr = (posNr + 1);// % nrOfPositions;
    	if (posNr == nrOfPositions + 1)
    	{
    		controller_Axis.stop();
    	}
    }

    Instead of using the callback method, I changed to a simple for loop to iterate through the array of positions. It is working well.


    I couldn't get your last example to create consistent sized cycles. Each cycle was longer than the previous. In addition .setPosition(0) doesn't seem to have any effect. Here's the code. Again just variable name changes.

    Code:
    void xDoWaveZ(int wavDir)
    {
    	
    	motor_Axis_X.setPosition(0);
    	motor_Spindle.setPosition(0);
    	delay(10);
    	int32_t startPosition_Z = motor_Axis_Z.getPosition();
    	cycleCounter = 1;
    	motor_Spindle.setAcceleration(configSteppers.acceleration_WaveZ_Spindle);
    	motor_Axis_Z.setAcceleration(configSteppers.acceleration_WaveZ_Axis);
    
    	cycleWidth = 20000; // steps
    	//cycleWidth = (configSteppers.distance_WaveZ / configSteppers.distancePerRev_AxisZ) * configSteppers.microsteps_Axis_Z * configSteppers.steps360_Axis_Z;
    	//maxSpeed = 30000;
    	//numberOfCycles = 3;
    
    	currentstate = state::starting;
    
    
    	//for (int i = 0; i <= numberOfCycles; i++)
    	while (cycleCounter <= configSteppers.repeats_WaveZ)
    	{
    		if (stopwatch > 300)
    		{
    			stopwatch = 0;
    			digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    
    		}
    		tick();
    	}
    	int32_t endPosition_Z = motor_Axis_Z.getPosition();
    
    	Serial1.print("pageWaveZ.t9.txt=");
    	Serial1.write(0x22);
    	Serial1.print(startPosition_Z);
    	Serial1.write(0x22);
    	Serial1.write(0xff);
    	Serial1.write(0xff);
    	Serial1.write(0xff);
    	Serial1.print("pageWaveZ.t9.txt=");
    	Serial1.write(0x22);
    	Serial1.print(startPosition_Z);
    	Serial1.write(0x22);
    	Serial1.write(0xff);
    	Serial1.write(0xff);
    	Serial1.write(0xff);
    	Serial1.print("pageWaveZ.t12.txt=");
    	Serial1.write(0x22);
    	Serial1.print(endPosition_Z);
    	Serial1.write(0x22);
    	Serial1.write(0xff);
    	Serial1.write(0xff);
    	Serial1.write(0xff);
    
    
    }
    
    void tick()
    {
    	int position = motor_Spindle.getPosition();
    
    	switch (currentstate)
    	{
    	case state::waiting:
    		break;
    
    	case state::starting:
    		direction = 1;
    		motor_Axis_Z.setMaxSpeed(configSteppers.maxSpeed_WaveZ_Axis);
    		controller_Axis.rotateAsync(motor_Axis_Z);
    		// fallthrough intended
    
    	case state::startingCycle:
    		direction *= -1;
    		motor_Spindle.setMaxSpeed(direction * configSteppers.maxSpeed_WaveZ_Spindle);
    		controller_Spindle.rotateAsync(motor_Spindle); // start spindle motor, as long as maxSpeed and acceleration of both motors are the same the will run in sync
    		currentstate = state::runningCycle;
    		break;
    
    	case state::runningCycle:
    		if (direction * position >= cycleWidth) // did the spindle motor reach the cycleWidth
    		{
    			Serial1.print("pageWaveZ.t10.txt=");
    			Serial1.write(0x22);
    			Serial1.print(position);
    			Serial1.write(0x22);
    			Serial1.write(0xff);
    			Serial1.write(0xff);
    			Serial1.write(0xff);
    			Serial1.print("pageWaveZ.t10.txt=");
    			Serial1.write(0x22);
    			Serial1.print(position);
    			Serial1.write(0x22);
    			Serial1.write(0xff);
    			Serial1.write(0xff);
    			Serial1.write(0xff);
    			if (cycleCounter < configSteppers.repeats_WaveZ) // cycles left? -> initiate new cycle
    			{
    				cycleCounter++;
    				controller_Spindle.stopAsync();
    				currentstate = state::stoppingCycle;
    			}
    			else // all cycles done, stopping both motors
    			{
    				controller_Spindle.stop();
    				controller_Axis.stop();
    				
    				currentstate = state::stopping;
    				cycleCounter = configSteppers.repeats_WaveZ + 2;
    			}
    		}
    		break;
    
    	case state::stoppingCycle:
    		if (!controller_Spindle.isRunning())
    			currentstate = state::startingCycle;
    		break;
    
    	case state::stopping:
    		if (!controller_Spindle.isRunning() && !controller_Axis.isRunning())
    		{
    			currentstate = state::waiting;
    			Serial.println("done");
    		}
    		break;
    	}
    }
    Thanks for all of the help.

  20. #20
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    Looks like you are reading beyond the array limits. Shouldnd't your condition for stopping be "if (posNr == nrOfPositions)"? The number stored at "targetPositions[nrOfPositions]" might be huge, so that the last move takes quite long and it looks like it the motor never stops.

    Code:
    void newMotorTarget()
    {
    	static int posNr = 0;
    
    	motor_Spindle.setTargetAbs(targetPositions[posNr]);
    	controller_Spindle.moveAsync(motor_Spindle);
    
    	posNr = (posNr + 1);// % nrOfPositions;
    	if (posNr == nrOfPositions + 1) // <-- Shouldn't that be nrOfPositions? 
    	{
    		controller_Axis.stop();
    	}
    }

  21. #21
    Junior Member
    Join Date
    Jan 2016
    Posts
    19
    When posNr = nrOfPositions, .moveAsync has just started, but the axis motor needs to keep running until it completes. Reading past the array limits explains why the Teensy is blocked.

  22. #22
    Junior Member
    Join Date
    Jul 2015
    Posts
    8
    I have a question about this library.

    How do i set pulse duration and polarity, cause I didn't find it in the documentation, it just tells you can set it but not how.

    thanks
    gueee

  23. #23
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    StepControl has two template parameters to set the pulse width and the acceleration update interval (both in microseconds), The pulse width defaults to 5Ás, the acceleration update interval to 5000Ás.
    If you want to use a pulsewidth of 10Ás and an acceleration update every 8ms you can simply write
    Code:
    StepControl<10, 8000> controller  // pulsewidth 10Ás, acceleration update 8ms
    The step pulse polarity can be set with
    Code:
    myStepper.setStepPinPolarity(LOW/*'or HIGH*/)

  24. #24
    Junior Member
    Join Date
    Jul 2015
    Posts
    8
    thanks luni,

    for some reason I get ~1.7Ás pulses measured with an oszilloscope on a teensy 3.1, allthough I set StepControll<10, 5000> and just 1 Volt amplitude. Do you have any clue what I've done wrong?

  25. #25
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    306
    That looks like some electronics problem. Can you measure the pulses without anything connected to the pin?

Posting Permissions

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