Tuesday, October 3, 2023

stepperCon library for controlling stepper motor drivers using timer interrupt on AVR devices

The stepperCon library allows you to control multiple stepper motors at the same time. It can interface with any stepper motor driver that can take inputs such as step and direction. The library also has some extra useful functionalities such as motor coordination using Bresenham line algorithm - useful for controlling 3 axis motors for example, free spin - where the motor keeps spinning, and positioning the motor at a certain degree from 1 to 360 by finding the shortest path.

The maximum speed (step rate) on a 16MHz microcontroller is 25kHz, however the maximum practical speed is 6.25kHz or 8.33kHz depending on the motor, load, supply voltage and micro-step resolution. A higher voltage can yield higher RPM and with 1/32 micro-step resolution the step rate can be 25kHz as oppose to 6.25kHz when using 1/8 micro-step resolution.

Even with multiple motors running at the same time, the speed can be maintained and that is because the speed profile is segmented and calculated while the interrupt routine (ISR) is not executing steps. So the time spent inside the ISR is low since the calculations for acceleration and deceleration are not done there. Only the stepping is done inside the ISR. Having an interrupt to generate the steps is preferred over a function in the main loop where other code could delay the stepping function thus causing motor stuttering.

The stepper library includes the micros library that is used to trigger a timer interrupt every 40us and as a perk you also have a way to keep track of time in your project with a 40us time resolution.

 

stepperCon library characteristics

  • interface with multiple stepper motor drivers
  • up to 3 coordinated motors for X, Y and Z (can be extended for more)
  • maximum stepping rate speed of 6.25kHz (or 8.33kHz if the motor can have high acceleration). Speeds are given for a 16MHz CPU. With higher CPU clock the stepping rate will also be higher.
  • angular positioning function that finds the shortest path from current angle to target angle
  • perpetual motion
  • timer interrupt driven
  • individual settings for acceleration and deceleration

    Contents

     

    Code example 1:

    // See https://www.programming-electronics-diy.xyz/2024/01/defining-fcpu.html
    #ifndef F_CPU
        #warning	"F_CPU not defined. Define it in project properties."
    
    #elif F_CPU != 16000000
        #warning	"Wrong F_CPU frequency!"
    #endif
    
    #include "stepperCon.h"
    
    int main(void){
    	
        // Configure stepper motor pins
        stepperSetupIO();
    	
        // Initiate and start micros timer interrupt (every 40us)
        // used for stepping the motors
        micros_init(16000000, 40);
    	
        // Create a structure object for each driver
        stepperCon* motorx = stepperAdd(200);
    	
        // Assign functions for each driver
        motorx->EN_f = motorX_EN;
        motorx->STEP_f = motorX_STEP;
        motorx->DIR_f = motorX_DIR;
    	
        // Micro stepping factor
        stepperSetStepDivision(motorx, 16);
    	
        // Set to true if the coils should remain energized
        // after the movement has been completed
        stepperHoldTorque(motorx, false);
    
        // Set speed and acceleration
        stepperSetSpeed(motorx, 12000);
        stepperSetAcceleration(motorx, 150);
    	
        // Move n steps
        stepperMove(motorx, 10000);
    	
        while(1){
            // This only moves the motor(s) after a move function is used. 
    	// Used to create segments executed by the ISR.
    	stepperRun();
    		
    	// Check when movement is complete
    	// and execute another one
    	if(stepperIsIdle(motorx)){
    	    _delay_ms(2000);
    	    stepperMove(motorx, -2048); // move in the opposite direction
    	}
        }
    }
    
     

    Code example 2: coordinating two motors

    #include "stepperCon.h"
    
    int main(void){
    
        // Configure stepper motor pins
        stepperSetupIO();
    	
        // Initiate and start micros timer interrupt (every 40us)
        // used for stepping the motors
        micros_init(16000000, 40);
    	
        // Create structure objects for each driver
        stepperCon* motorx = stepperAdd(200);
        stepperCon* motory = stepperAdd(200);
    	
        // Assign functions for each driver
        motorx->EN_f = motorX_EN;
        motorx->STEP_f = motorX_STEP;
        motorx->DIR_f = motorX_DIR;
    	
        motory->EN_f = motorY_EN;
        motory->STEP_f = motorY_STEP;
        motory->DIR_f = motorY_DIR;
    	
        // Micro stepping factor
        stepperSetStepDivision(motorx, 8);
        stepperSetStepDivision(motory, 8);
    	
        // Set to true if the coils should remain energized
        // after the movement has been completed
        stepperHoldTorque(motorx, false);
        stepperHoldTorque(motory, true);
    
        // Set speed and acceleration
        stepperSetSpeed(motorx, 2000);
        stepperSetAcceleration(motorx, 150);
    	
        stepperSetSpeed(motory, 2000);
        stepperSetAcceleration(motory, 150);
    	
        // Define coordinated motors
        stepperDefineXYZ(motorx, motory, NULL);
    	
        // Draw a 1500 x 2000 steps rectangle
        const uint8_t array_size = 4;
        uint8_t i = 0;
        bool draw = true;
    	
        int32_t xy[array_size][2] = {
            {1500, 0},
            {1500, 2000},
            {0, 2000},
            {0, 0}
        };
    	
        while(1){
            // This only moves the motor(s) after a move function is used. 
    	// Used to create segments executed by the ISR.
            stepperRun();
    		
            // Move to an absolute position in step units
            if(draw && stepperIsIdleXYZ()){
                stepperMoveToXYZ(xy[i]);
                i++;
                if(i == array_size) draw = false;
            }
        }
    }
    
     

    Library structure

    Custom functions and output pins

    Because the number of motors can vary and the control pins can be on any port and pin, the library needs a way to know which set of pins belongs to which stepper motor driver. Thus, the pin definitions and a group of 3 functions must be implemented by the user. This is easy to achieve using the stepperConfig .h and .c files that include some template-like code that can be modified accordingly.

    stepperConfig.h

    Each stepper driver needs a group of 3 pins: enable (EN), direction (DIR) and stepping (STEP). They are defined like this:

    /* X AXIS */
    // Enable pin
    #define X_AXIS_EN_DDR		DDRD
    #define X_AXIS_EN_PORT		PORTD
    #define X_AXIS_EN_PIN		4
    
    // Step pin
    #define X_AXIS_STEP_DDR		DDRD
    #define X_AXIS_STEP_PORT	PORTD
    #define X_AXIS_STEP_PIN		5
    
    // Direction pin
    #define X_AXIS_DIR_DDR		DDRD
    #define X_AXIS_DIR_PORT		PORTD
    #define X_AXIS_DIR_PIN		6
    

    Port letter and pin number must be replaced according to your setup. If EN or DIR is not needed it can be commented out.

    Next, each stepper driver needs a group of 3 functions:

    void motorX_EN(bool enable);
    void motorX_STEP(void);
    void motorX_DIR(int8_t dir);
    

    The function names can be changed, but it is recommended to keep the indicators after "_".

    stepperConfig.c

    Here is where the defines in the header file are used. The function stepperSetupIO is used to set the state of control pins. Inside this function the state of the pins are set for each motor driver like so:

    // ENABLE pin set as output high 
    // to disable the stepper driver module
    X_AXIS_EN_PORT |= (1 << X_AXIS_EN_PIN);
    X_AXIS_EN_DDR |= (1 << X_AXIS_EN_PIN);
    // STEP pin as output
    X_AXIS_STEP_DDR |= (1 << X_AXIS_STEP_PIN);
    // DIR pin as output
    X_AXIS_DIR_DDR |= (1 << X_AXIS_DIR_PIN);
    

    Next we define the functions declared in the header file. This must be done for each stepper driver.

    /*-----------------------------------------------------------------------------
    	ENABLE pin
    -------------------------------------------------------------------------------*/
    void motorX_EN(bool enable){
        // Replace the pin and/or name according to your project
    	
        if(enable){
            X_AXIS_EN_PORT &= ~(1 << X_AXIS_EN_PIN); // pin low - enable module
        }else{
            X_AXIS_EN_PORT |= (1 << X_AXIS_EN_PIN); // pin high - disable module
        }
    }
    
    /*-----------------------------------------------------------------------------
    	STEP pin
    	// On a 16MHz device, setting a pin HIGH then LOW takes 188ns.
    	// If a higher CPU frequency is used or the stepper driver expects
    	// a longer pulse time, add a delay when changing the pin state.
    -------------------------------------------------------------------------------*/
    void motorX_STEP(void){
        // Replace the pin and/or name according to your project
    	
        X_AXIS_STEP_PORT |= (1 << X_AXIS_STEP_PIN); // pin high
    	
        // This delay can be commented out or it's duration modified.
        // The delay depends on the CPU clock and stepper driver module.
        // Some drivers such as A4988 need some time delay between pin
        // transition from high to low.
        // Some drivers like TMC2209 do not require them (at least on 16MHz clocks).
        // When using higher CPU speeds, consider adding a delay according to
        // the driver's datasheet.
        _delay_us(1);
    	
        X_AXIS_STEP_PORT &= ~(1 << X_AXIS_STEP_PIN); // pin low
    }
    
    /*-----------------------------------------------------------------------------
    	DIR pin
    -------------------------------------------------------------------------------*/
    void motorX_DIR(int8_t dir){
        // Replace the pin and/or name according to your project
        // DIRECTION_CCW an DIRECTION_CW are part of DIRECTION enum and should not be changed
    	
        if(dir == DIRECTION_CCW){
            X_AXIS_DIR_PORT |= (1 << X_AXIS_DIR_PIN); // pin high
        }else{
            X_AXIS_DIR_PORT &= ~(1 << X_AXIS_DIR_PIN); // pin low
        }
    }
    

    Tip: to replace a name, for example X_AXIS_DIR_PORT with MOTOR1_DIR_PORT in Microchip Studio, click on the constant or variable to place the cursor somewhere on it, then press Shift + Alt + R to rename. Search all project field must be selected in order to replace it in all files.

    Assigning custom functions to motor drivers

    After a driver object has been created, we assign the custom functions to each stepper driver like so:

    // Create structure instances for each driver
    stepperCon* motorx = stepperAdd(200);
    stepperCon* motory = stepperAdd(200);
    	
    // Assign functions for each driver
    motorx->EN_f = motorX_EN;
    motorx->STEP_f = motorX_STEP;
    motorx->DIR_f = motorX_DIR;
    	
    motory->EN_f = motorY_EN;
    motory->STEP_f = motorY_STEP;
    motory->DIR_f = motorY_DIR;
    

    motorx and motory are the name of the driver objects and can have an arbitrary name. EN_f, STEP_f, and DIR_f are the names of the function pointers located inside the stepperCon structure and shouldn't be changed. Having a pointer to each custom function, allows the library to control the necessary pins. Apart from direct port access - which is not feasible in this case - the fastest way to pulse the stepping pin inside the ISR is motor->STEP_f().

    Important: if fore some reason you don't need library control over the enable or direction pin, you still need to assign a valid function to the function pointers. Make an empty function in that case like this:

    void motorX_EN(bool enable){}

    Leaving a function pointer unassigned will crash the code.

    User settings

    A few user settings can be found in the stepperConfig.h file.

    // Number of stepper motor drivers to control. 
    // Increasing this will increase code size.
    #define MAX_NR_OF_STEPPER_DRIVERS		2
    
    // Number of maximum coordinated steppers.
    // Usually 3 for X, Y and Z axis.
    #define NR_OF_SYNC_STPPERS			3
    
    // Number of segments of speed profile to hold in a buffer.
    // Normally this should not be modified. Increasing this number will
    // increase memory usage and also the controlled motor stop 
    // will have a delay since there will be more segments in the buffer
    // at cruising speed before replaced with deceleration segments.
    #define SEGMENT_BUFFER_SIZE			6 // [default: 6]
    

    MAX_NR_OF_STEPPER_DRIVERS - how many motors do you plan to control

    NR_OF_SYNC_STPPERS - maximum number of coordinated motors [default 3]. This shouldn't be modified unless the code is modified to support extra drivers.

    SEGMENT_BUFFER_SIZE - the size of the array holding generated segments. Not recommended to be modified. Size of this array will be multiplied by the number of added drivers. The purpose of this array will be described later.

    Settings inside the stepperCon.h file:

    // The temporal resolution of the acceleration management subsystem. A higher number gives smoother
    // acceleration, particularly noticeable on machines that run at very high feed rates, but may negatively
    // impact performance. The correct value for this parameter is machine dependent, so it's advised to
    // set this only as high as needed.
    // NOTE: Changing this value also changes the execution time of a segment in the step segment buffer.
    // When increasing this value, this stores less overall time in the segment buffer and vice versa. Make
    // certain the step segment buffer is increased/decreased to account for these changes.
    // Set to 1000 or lower when using more than 3 motors.
    #define ACCELERATION_TICKS_PER_SECOND		4000.0 // [default: 4000]
    

    ACCELERATION_TICKS_PER_SECOND - default 4000. When using more than 3 or 4 motors, this value needs to be lowered to say... 2000 or 1000 which will result in each segment having more steps, thus spending less time calculating duration for next step, since more steps will have the same duration. Too low of a value could make acceleration less smooth.

    Settings inside micros.h file:

    #define F_CPU 			16000000
    

    Default value for CPU frequency is 16MHz. F_CPU is best to be defined inside project properties in Microchip Studio or a Makefile if custom Makefiles are used. Please see https://www.programming-electronics-diy.xyz/2024/01/defining-fcpu.html for more details.

    #define MICROS_TIMER 		MICROS_TIMER2
    

    Which timer to use: 0, 1, 2, 3 or 4. Only applies to non-UPDI devices.

    /*--------------------------------------------------------------
    TIMING_USING_RTC - use internal RTC
    TIMING_USING_TCA - use timer TCA channel 0
    ----------------------------------------------------------------*/
    #define MICROS_TIMING_MODULE		TIMING_USING_RTC
    

    Only available for UPDI devices (newer AVR microcontrollers). Instead of consuming a timer, on UPDI devices the internal RTC module can be used for timing.

    Timer Setup

    Function used to configure and start a timer interrupt.

    void micros_init(uint32_t f_cpu, uint16_t resolution)
    

    f_cpu

    CPU clock frequency in Hertz used to calculate the prescaler for the timer. When RTC is used, the clock is always 32768 Hz.

    resolution

    This value sets how often the timer interrupt will trigger. On a 16MHz CPU 40 microseconds is the lowest value recommended. The smaller this value is the higher the speed resolution will be thus increasing the maximum stepping rate frequency supported. Let's assume the code inside the ISR takes 30us then 10us will remain for the CPU to execute the rest of the code. If more drivers are added and the total time is over 40us then increase this value. Use a logic analyzer to find the proper value when using a lower or higher CPU frequency. Simply set a pin high at the start of the ISR and set it low at the end, then in a logic analyzer software you can measure the length of the high pulse giving a good indication of how much time the ISR takes.

    Functions and how to use them

    Initializing the pins

    Runs once when the program starts. Sets the state of the control pins: enable, direction and step.

    void stepperSetupIO(void)

    Adding a stepper driver

    Creates an object of structure stepperCon.

    stepperCon* stepperAdd(uint16_t steps_per_revolution)
    

    steps_per_revolution:

    One characteristic of stepper motors is how many steps has to make for one rotation. Usually 200. For 1.8 degree motor (360 / 1.8 = 200). Used to calculate RPM and angle position. This must not be confused with micro-stepping. Used together with stepperSetStepDivision().

    Return: returns a pointer to a stepperCon structure object.

    Step division

    Stores the division factor applied by the stepper driver module and is only used for calculating RPM and angle position. Used by stepperToDegree().

    void stepperSetStepDivision(stepperCon* self, uint8_t div)
    

    self:

    Pointer to a stepperCon structure object.

    div:

    Microstepping division factor. E.g: 8, 16, 32, 64. Default 1.

    Hold torque

    Sets a configuration flag that tells the library whether or not the coils should remain energized after a motion is completed using the enable (EN) pin. Disabling the driver while the motor is idle helps in power saving and also keeps the driver and motor cooler.

    void stepperHoldTorque(stepperCon* self, bool hold_torque)
    

    self:

    Pointer to a stepperCon structure object.

    hold_torque:

    If set to true the enable pin will be used to keep the coils energized while the motor is idle.

    Setting the speed

    Sets the desired speed in steps per second. The set speed can only be reached if there is enough steps (distance). Increasing the acceleration can also help in reaching the target speed with a lower distance. The maximum speed can be reached when the speed profile is trapezoid.

    When the speed is changed, segments already in buffer will still run at previous speed, so a bigger buffer will lead to a greater delay in applying the new speed to the motor.

    void stepperSetSpeed(stepperCon* self, float speed)
    

    self:

    Pointer to a stepperCon structure object.

    speed:

    Speed in steps/second.

    Setting acceleration and deceleration

    Set acceleration and deceleration rate in steps/second^2. The given values will be multiplied by ACCEL_SCALING_FACTOR (100) so the user can use a lower number for readability. So instead of using 15000 use 150. 

    The deceleration will also be set here with the acceleration value, so in case that they have the same value, running stepperSetDeceleration() is not necessary.

    The value depends on the motor type and the load. A heavy load needs a lower acceleration to reach a certain speed.

    void stepperSetAcceleration(stepperCon* self, uint32_t acceleration)
    void stepperSetDeceleration(stepperCon* self, uint32_t deceleration)
    

    self:

    Pointer to a stepperCon structure object.

    acceleration, deceleration:

    Acceleration and deceleration rate in steps/second^2.

    Set current position

    Used to offset the current position. Usually used to reset the position to 0. The motor must be idle. This will not move the motor, instead, any subsequent movements will be related to this position.

    void stepperSetCurrentPosition(stepperCon* self, int32_t position)
    

    self:

    Pointer to a stepperCon structure object.

    position:

    New position value in step units.

    Define a group of coordinated stepper motors

    Defines a group of up to three coordinated motors. Each parameter is a pointer to a motor that should be in the group. Use NULL instead of a pointer when a slot in the group is not used.

    void stepperDefineXYZ(stepperCon* x, stepperCon* y, stepperCon* z)
    

    x, y, z:

    Pointers to a stepperCon structure object.

    Get current speed

    Returns the current motor speed in steps per second.

    uint32_t stepperGetCurrentSpeed(stepperCon* self)
    

    self:

    Pointer to a stepperCon structure object.

    Return: current speed in steps/second.

    Get current position

    Returns the current absolute motor position in steps. The returned value can be positive or negative.

    int32_t stepperGetCurrentPosition(stepperCon* self)
    

    self:

    Pointer to a stepperCon structure object.

    Return: absolute motor position in step unit.

    Check if motor is stopped

    Returns true if the motor is currently stopped or false if is running. Useful to trigger another movement after one ends.

    bool stepperIsIdle(stepperCon* self)
    

    self:

    Pointer to a stepperCon structure object.

    Return: true if motor is idle.

    Check if a coordinated group is stopped

    Returns true if the main motor in the coordinated group is currently stopped or false if is running. Useful to trigger another movement after one ends.

    bool stepperIsIdleXYZ(void)
    

    Return: true if the synchronized motors are idle.

    Move to absolute position

    Move the motor using absolute positioning. The stepping is not done here. The function sets the pin direction and calculates the number of steps necessary to reach the target position then sets a flag that triggers the segment generation function that in turn triggers the ISR where the stepping is done.

    This function will not do anything if:

    • the motor is still running
    • the current position and target position are the same
    • the set speed is 0
    void stepperMoveTo(stepperCon* self, int32_t absolute)
    

    self:

    Pointer to a stepperCon structure object.

    absolute:

    Absolute position in steps.

    Move to relative position

    Move the motor using relative positioning. Wrapper of stepperMoveTo().

    void stepperMove(stepperCon* self, int32_t relative)
    

    self:

    Pointer to a stepperCon structure object.

    relative:

    Relative position in steps.

    Move a group of coordinated steppers

    Move the group of coordinated motors using absolute positioning. The coordination is done using Bresenham line algorithm. Direction pin is also set here. Each driver is activated using the enable pin.

    This function will not do anything if:

    • the main motor in the group is still running (main motor is the one that has to travel the longest distance)
    • the current position and target position are the same
    void stepperMoveToXYZ(const int32_t xyz[])
    

    xyz:

    xyz coordinate, or only xy coordinate in steps.

    Safe stop

    Stops the motor by triggering the deceleration. Segments already in the buffer will still be executed and only after that the deceleration will start. The segment buffer shouldn't be too large as to affect deceleration distance/time. 

    This function can be used inside an ISR, triggered by a limit switch for example, since it is only used to set up a flag. The actual deceleration is done by stepperRun().

    void stepperSafeStop(stepperCon* self)
    

    self:

    Pointer to a stepperCon structure object.

    Emergency stop

    This function stops the motor instantly without deceleration by setting the enable pin to false, so use it with caution. Useful in emergency situations as the name suggests. Care should be taken at higher speeds or when the moved mass is heavy and a sudden stop could have a detrimental effect.

    void stepperEmergencyStop(stepperCon* self)
    

    self:

    Pointer to a stepperCon structure object.

    Free spin

    Starts the motor and keeps it spinning for 2147483647 steps. Depending on the step rate this means a long time (days). The speed is set by the appropriate function.

    void stepperFreeSpin(stepperCon* self, Direction dir)
    

    self:

    Pointer to a stepperCon structure object.

    dir:

    Direction of spin (DIRECTION_CW or DIRECTION_CCW).

    Angular positioning

    Useful to position the motor at a certain degree by finding the shortest path.

    void stepperToDegree(stepperCon* self, float degree)
    

    self:

    Pointer to a stepperCon structure object.

    degree:

    Angle from 0 to 360.

    Segment generator

    This is the main function that keeps the motors spinning, together with the ISR. The algorithm segments the speed profile and stores the segments inside the segment buffer. Each segment includes the number of steps and step duration. Lower speeds have a lower number of steps for each segment and higher speeds a higher number of steps per each segment. 

    Even if at higher speeds the step duration is lower (higher frequency) the number of steps is     also higher so the CPU has time to generate new segments for the ISR. If that is not the case, decrease ACCELERATION_TICKS_PER_SECOND to increase the number of steps per segment at higher speeds.

    The function should be placed inside the main loop and ideally run as often as possible without much delay because as soon as the ISR finishes executing segments, this function should be able to generate new ones until the desired position is reached. When the motor is idle the function will exit quicker. A new movement is triggered after a move function is used.

    The state of the segment generation (acceleration, cruising, deceleration) is out of phase (ahead) of the actual state of the motor and are independent. So for example during segment generation the state could be deceleration but the actual state of the motor could be acceleration or cruising. 

    The motor is stopped after the current step (incremented by the ISR) is equal or greater than the number of steps to travel. Drivers are disabled using the enable pin if holding torque is false.

    void stepperRun(void)
    

    About the stepperCon library

    The algorithm

    Initially, I started designing the library based on the formulas that can be found at this link: https://www.embedded.com/generate-stepper-motor-speed-profiles-in-real-time/. This method is elegant and it worked well but since it had to calculate the step duration after every single step it was too slow especially when more motors were added. Then when I was searching for a way to coordinate the motors I have found that Grbl (a CNC controller) uses a different approach. Instead of calculating the step duration for each step, one duration is used for several steps since the time difference between them is negligible.

    The speed profile segments are generated by stepperRun function. Here is a simple illustration of the concept.

    stepperCon segmentation of the speed profile

    As the speed increases, the number of steps in a segment with the same duration also increases. If you wish to experiment with the algorithm and see the generated values you can do so by using this LibreOffice file stepper motor speed profile calculator.ods. In the first tab is the first algorithm used. In the second tab is the one that uses segments. Acceleration and number of steps used for calculation are set is in the first tab only.

    Speed resolution

    Although the library is fast enough to output pulses at 25kHz, after a certain speed it becomes impractical to drive stepper motors and the reason is the speed resolution that is too low to provide a smooth acceleration at higher speeds.

    stepperCon speed resolution
    Plotted for 40us timer interrupt @ 16MHz CPU

    In the figure above the blue line shows that as the speed increases so is the difference between current speed and the next one. Why is that?

    On a 16MHz CPU the fastest the interrupt can trigger is 40us. Lets say we want the speed to be 2000 steps/second. Step duration = 1000000 / 2000 is 500us. So every 500us the interrupt will generate one step. 40us resolution is relatively small comparing to step duration so if the interrupt triggers 40us sooner or later, the speed error will not be very significant. Now if we compare this with a step rate of 12000 the step duration is now 1000000 / 12000 = 83us. Now +- 40us interrupt resolution will result in around 50% error. In order to reduce the speed error at higher speeds, the interrupt should trigger faster (5us) but this is only possible on microcontrollers that run on higher CPU clocks.

    Here is the file used to generate the above graphic nominal step rate vs actual step rate.ods. The file is useful if you would like to see how changing the interrupt interval affects the speed.

    Triangular vs trapezoidal speed profiles

    There are two main speed profiles: triangular and trapezoidal. 

    Triangular profile is when there is not enough steps (distance) to reach the desired speed and the acceleration is followed by deceleration.

    Triangular speed profile

    Trapezoidal profile allows a specified time (or distance) to be spent at a constant velocity named cruising. Unlike the triangle profile, the trapezoidal profile includes acceleration, cruising followed by deceleration.

    Trapezoidal speed profile

    More on how to calculate accel and decel distance and how to determine the type of profile based on accel and total distance can be found on AVR446: Linear speed control of stepper motor pdf.



    Download

    v1.1 stepperCon library Folder including all files that can be downloaded as a zip file
    Other links
    micros library project page Project page for the micros library used to trigger the timer interrupt. This stepperCon project uses a slightly, modified version of this.
    Changelog
    v1.1 2-2-2024:
    - added support for UPDI devices
    v1.0 stepperCon release date 3, October, 2023
     

    Library for TMC2209 driver - AVR

    How to use A4988 stepper motor driver module

    No comments:

    Post a Comment