大连好人 发表于 2013-2-6 17:17:43

分享好人经验:改进EasyStepper,让步进电机的控制支持加速度

本帖最后由 大连好人 于 2013-2-6 17:41 编辑

我之前分享了一个 EasyStepper: http://www.geek-workshop.com/thread-3266-1-1.html

有同学提出,步进电机的控制最好带有加速度功能,所以呢,改进一下 EasyStepper,咱也支持加速度吧。

先说一下总体思路:

1、将整个转动按照百分比分为 stage1(0-25%)、stage2(26-75%)、stage3(75-100%) 三个阶段:
    stage1 = steps / 4; // 第一阶段的结束步
    stage2 = steps / 4 * 3; // 第二阶段的结束步
2、用指定的速度计算出每步的延时时长(stepTime),该时长作为第二阶段的延时使用;
3、用 stepTime * (acceleration + 1) 计算出起始延时时长(startTime);
4、计算出第一阶段的时间递减步长:stage1StepTime = acceleration * stepTime / stage1;
5、计算出第三阶段的时间递增步长:stage3StepTime = acceleration * stepTime / (steps - stage2);
6、在运行每步时,利用如下公式计算出每个阶段的延时时长:

    stage1:nextStepTime = startTime - stage1StepTime * stepsGone
    stage2:nextStepTime = stepTime
    stage3:nextStepTime = stepTime + stage3StepTime * (stepsGone - stage2 + 1)

    然后通过每次在当前时间上加 nextStepTime 获得下个步的执行时间。

来看 EasyStepper.h (基本上和上一个版本一致)

#ifndef EasyStepper_h
#define EasyStepper_h

#include <stdlib.h>
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#include <wiring.h>
#endif

/**
* author [email protected]
*/
class EasyStepper
{
        public:
               
                /**
                * to create the EasyStepper
                * parameters:
                * stepPin the step pin
                * directionPin the direction pin
                * enablePin the enable pin
                * directionPinsInverted if the value is true then invert HIGH/LOW value for direction pin
                * enablePinsInverted if the value is true then invert HIGH/LOW value for enable pin
                */
                EasyStepper(byte stepPin, byte directionPin, byte enablePin, bool directionPinsInverted, bool enablePinsInverted);
               
                /**
                * to startup the EasyStepper
                */
                void startup();
               
                /**
                * to shutdown the EasyStepper, will release the enable pin to save power
                */
                void shutdown();
               
                /**
                * to rotate steps from current position with speed, the acceleration = 0
                * speed the speed for rotation, the unit is steps per second
                * steps the steps to go
                */
                void rotate(float speed, int steps);
               
                /**
                * to rotate steps from current position with speed
                * speed the speed for rotation, the unit is steps per second
                * steps the steps to go
                * acceleration the acceleration, if it = 0, means no acceleration
                */
                void rotate(float speed, int steps, int acceleration);
               
                /**
                * to stop the stepper, the motor will stay at current position
                */
                void stop();
   
    /**
    * run, you must call this as frequently as possible, but at least once per minimum step interval,
    * preferably in your main loop.
    */
    void run();
   
    /**
    * if return true means the action is done
    */
    boolean isDone();
   
    /**
    * enable the debug mode?
    */
    void debugMode(boolean enabled);
               
        protected:
               
                //
               
        private:
               
                boolean debugModeFlag;
               
                byte stepPin;
                byte directionPin;
                byte enablePin;
               
                bool directionPinsInverted;
                bool enablePinsInverted;
               
                int acceleration;
                int stage1; // the end step of the stage1
                int stage2; // the end step of the stage2
               
                int stepsToGo;
                int stepsGone;
               
                float stepTime;
                float startTime;
                float stage1StepTime;
                float stage3StepTime;
                unsigned long nextTimestamp;
               
                boolean done;
               
                void step();
               
};

#endif

再来看 EasyStepper.cpp (代码里面有注释)

#include "EasyStepper.h"

EasyStepper::EasyStepper(byte stepPin, byte directionPin, byte enablePin, bool directionPinsInverted, bool enablePinsInverted)
{
        // save the parameters
        this->stepPin = stepPin;
        this->directionPin = directionPin;
        this->enablePin = enablePin;
        this->directionPinsInverted = directionPinsInverted;
        this->enablePinsInverted = enablePinsInverted;
}

void EasyStepper::startup()
{
        // set the pin mode
        pinMode(this->stepPin, OUTPUT);
        pinMode(this->directionPin, OUTPUT);
        pinMode(this->enablePin, OUTPUT);
        // enable the stepper
        digitalWrite(enablePin, HIGH ^ this->enablePinsInverted);
        // initialize the done to true
        this->done = true;
}

void EasyStepper::shutdown()
{
        // disable the stepper
        digitalWrite(enablePin, LOW ^ this->enablePinsInverted);
}

void EasyStepper::debugMode(boolean enabled)
{
        this->debugModeFlag = enabled;
}

void EasyStepper::rotate(float speed, int steps)
{
        this->rotate(speed, steps, 0);
}

void EasyStepper::rotate(float speed, int steps, int acceleration)
{
        // ignore the zero value
        if (speed != 0 && steps != 0)
        {
                if (steps > 0)
                {
                        // CW
                        digitalWrite(directionPin, HIGH ^ this->directionPinsInverted);
                }
                else if (steps < 0)
                {
                        // CCW
                        digitalWrite(directionPin, LOW ^ this->directionPinsInverted);
                }
                // done flag
                this->done = false;
                // the steps to go
                this->stepsToGo = abs(steps);
                // the acceleration
                this->acceleration = abs(acceleration);
                if (this->stepsToGo <= 4)
                {
                        this->acceleration = 0;
                }
                // change the speed to stepTime, micro seconds per step
                this->stepTime = 1000.0 * 1000.0 / abs(speed);
                // start time
                this->startTime = this->stepTime * (this->acceleration + 1);
                // stage1
                this->stage1 = this->stepsToGo / 4;
                this->stage1StepTime = (float) this->acceleration * this->stepTime / this->stage1;
                // stage2
                this->stage2 = this->stepsToGo / 4 * 3;
                this->stage3StepTime = (float) this->acceleration * this->stepTime / (this->stepsToGo - this->stage2);
                // the steps gone
                this->stepsGone = 0;
                // current timestamp
                unsigned long time = micros();
                if (this->debugModeFlag)
                {
                        Serial.print("rotate: direction=");
                        Serial.print(steps > 0 ? "CW" : "CCW");
                        Serial.print(", stepsToGo=");
                        Serial.print(this->stepsToGo);
                        Serial.print(", acceleration=");
                        Serial.print(this->acceleration);
                        Serial.print(", startTime=");
                        Serial.print(this->startTime);
                        Serial.print(", stage1=");
                        Serial.print(this->stage1);
                        Serial.print(", stage1StepTime=");
                        Serial.print(this->stage1StepTime);
                        Serial.print(", stage2=");
                        Serial.print(this->stage2);
                        Serial.print(", stage3StepTime=");
                        Serial.print(this->stage3StepTime);
                        Serial.print(", stepTime=");
                        Serial.print(this->stepTime);
                        Serial.print(", currentTimestamp=");
                        Serial.println(time);
                }
                // call the step method to rotate the motor
                this->step();
        }
}

void EasyStepper::stop()
{
        this->stepsToGo = 0;
        this->done = true;
}

void EasyStepper::run()
{
        // the current timestamp
        unsigned long time = micros();
        if (!this->done && time >= this->nextTimestamp)
        {
                this->step();
        }
        if (this->debugModeFlag)
        {
                Serial.print("currentTimeStamp=");
                Serial.println(time);
        }
}

void EasyStepper::step()
{
        // are there some steps to rotate?
        if (this->stepsToGo > this->stepsGone)
        {
                // HIGH value
                digitalWrite(stepPin, HIGH);
                // delay
                delayMicroseconds(2);
                // LOW value
                digitalWrite(stepPin, LOW);
                // increase the stepsGone
                this->stepsGone++;
                // default: stage2
                float nextStepTime = this->stepTime;
                if (this->acceleration != 0)
                {
                        if (this->stepsGone < this->stage1)
                        {
                                // stage1: down to stepTime from startTime
                                nextStepTime = this->startTime - this->stage1StepTime * this->stepsGone;
                        }
                        else if (this->stepsGone >= this->stage2)
                        {
                                // stage3: up to startTime from stepTime
                                nextStepTime = this->stepTime + this->stage3StepTime * (this->stepsGone - this->stage2 + 1);
                        }
                }
                // current timestamp
                unsigned long time = micros();
                this->nextTimestamp = time + nextStepTime;
                if (this->debugModeFlag)
                {
                        Serial.print("step: stepsGone=");
                        Serial.print(this->stepsGone);
                        Serial.print(", currentTimestamp=");
                        Serial.print(time);
                        Serial.print(", nextTimestamp=");
                        Serial.print(this->nextTimestamp);
                        Serial.print(", nextStepTime=");
                        Serial.println(nextStepTime);
                }
        }
        else
        {
                this->done = true;
        }
}
   
boolean EasyStepper::isDone()
{
        return this->done;
}


测试程序就不写了,和上一个版本差不多,在 rotate 方法增加一个加速度参数即可,如:

    float speed = 400.0;
    int steps = 200;
    int acceleration = 10;
    stepper1.rotate(speed, steps, acceleration);

有任何意见或建议,请随时与我联系,多谢。。。。

wasdpkj 发表于 2013-2-6 23:16:58

;P好帖,这个很实用,算法不错

Malc 发表于 2013-2-19 09:22:01

这个算法看的不是很明白,分成三个阶段的作用是?
加速度不断减小使速度曲线更光滑?
步进加减速要考虑两种情况,一是在给定距离内能达到指定速度,速度曲线是个梯形,
二是在给定距离内不能达到指定速度就要减速,否则会丢步,速度曲线是个三角形
不过一般的步进都会有个起步速度,这个速度是最大不丢步的启动速度,减速到这个速度可以直接刹车
实时加减速最大的问题单片机处理速度跟不上,因为要做大量浮点除法、开根号
推荐你看avr运用笔记446,这个是很经典的算法,实时计算的,accelStepper也是基于它的
最后,用上avr内部定时器和中断性能会提高很多,不然白浪费了这么好的资源 呵呵

Cola_DOG 发表于 2013-4-17 15:38:36

请问好人,对于arduino来说 TB6560上的 EN+/- CW+/- 和CLK+/-这六根线应该怎么接,急求?谢谢!

deepsky 发表于 2013-4-24 09:22:43

请教大侠这个程序可以驱动多个步进电机么?

JasmineL 发表于 2013-4-24 19:02:50

deepsky 发表于 2013-4-24 09:22 static/image/common/back.gif
请教大侠这个程序可以驱动多个步进电机么?

http://www.geek-workshop.com/thread-4319-1-1.html
这是我很多天研究以来的结果...

xiaojuren 发表于 2013-4-25 11:33:11

Malc 发表于 2013-2-19 09:22 static/image/common/back.gif
这个算法看的不是很明白,分成三个阶段的作用是?
加速度不断减小使速度曲线更光滑?
步进加减速要考虑两 ...

请问avr运用笔记446在哪

xiaojuren 发表于 2013-4-25 11:34:25

Cola_DOG 发表于 2013-4-17 15:38 static/image/common/back.gif
请问好人,对于arduino来说 TB6560上的 EN+/- CW+/- 和CLK+/-这六根线应该怎么接,急求?谢谢!

这个淘宝上有的

chqiyi 发表于 2013-6-13 23:22:10

Cola_DOG 发表于 2013-4-17 15:38 static/image/common/back.gif
请问好人,对于arduino来说 TB6560上的 EN+/- CW+/- 和CLK+/-这六根线应该怎么接,急求?谢谢!

好人在另一贴有说明,负极都接地

rick_hou 发表于 2013-6-27 23:04:19

chqiyi 发表于 2013-6-13 23:22 static/image/common/back.gif
好人在另一贴有说明,负极都接地

类似共阴或者共阳的解法吧。要么所有+都接5v,然后 - 接到管脚,或者反过来,我接驱动器的接法就是负极接管脚

Roger_Gao 发表于 2013-9-10 08:31:55

请问,这个速度最高能达到多大啊?

yaoze权 发表于 2013-9-28 00:03:37

请问楼主:EasyStepper.h这个库怎么下载?

阴霾の微笑 发表于 2014-8-6 13:35:56

赞一个 谢谢楼主!

22881916 发表于 2015-5-20 14:45:15

谢谢楼主了,,,可是不会添加.h和.c的

echo51u 发表于 2015-7-25 09:01:38

楼主啊 怎么把你这个库添加到arduino里是 :'(
页: [1]
查看完整版本: 分享好人经验:改进EasyStepper,让步进电机的控制支持加速度