极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 38642|回复: 14

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

[复制链接]
发表于 2013-2-6 17:17:43 | 显示全部楼层 |阅读模式
本帖最后由 大连好人 于 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 (基本上和上一个版本一致)

  1. #ifndef EasyStepper_h
  2. #define EasyStepper_h

  3. #include <stdlib.h>
  4. #if ARDUINO >= 100
  5. #include <Arduino.h>
  6. #else
  7. #include <WProgram.h>
  8. #include <wiring.h>
  9. #endif

  10. /**
  11. * author [email][email protected][/email]
  12. */
  13. class EasyStepper
  14. {
  15.         public:
  16.                
  17.                 /**
  18.                 * to create the EasyStepper
  19.                 * parameters:
  20.                 * stepPin the step pin
  21.                 * directionPin the direction pin
  22.                 * enablePin the enable pin
  23.                 * directionPinsInverted if the value is true then invert HIGH/LOW value for direction pin
  24.                 * enablePinsInverted if the value is true then invert HIGH/LOW value for enable pin
  25.                 */
  26.                 EasyStepper(byte stepPin, byte directionPin, byte enablePin, bool directionPinsInverted, bool enablePinsInverted);
  27.                
  28.                 /**
  29.                 * to startup the EasyStepper
  30.                 */
  31.                 void startup();
  32.                
  33.                 /**
  34.                 * to shutdown the EasyStepper, will release the enable pin to save power
  35.                 */
  36.                 void shutdown();
  37.                
  38.                 /**
  39.                 * to rotate steps from current position with speed, the acceleration = 0
  40.                 * speed the speed for rotation, the unit is steps per second
  41.                 * steps the steps to go
  42.                 */
  43.                 void rotate(float speed, int steps);
  44.                
  45.                 /**
  46.                 * to rotate steps from current position with speed
  47.                 * speed the speed for rotation, the unit is steps per second
  48.                 * steps the steps to go
  49.                 * acceleration the acceleration, if it = 0, means no acceleration
  50.                 */
  51.                 void rotate(float speed, int steps, int acceleration);
  52.                
  53.                 /**
  54.                 * to stop the stepper, the motor will stay at current position
  55.                 */
  56.                 void stop();
  57.    
  58.     /**
  59.     * run, you must call this as frequently as possible, but at least once per minimum step interval,
  60.     * preferably in your main loop.
  61.     */
  62.     void run();
  63.    
  64.     /**
  65.     * if return true means the action is done
  66.     */
  67.     boolean isDone();
  68.    
  69.     /**
  70.     * enable the debug mode?
  71.     */
  72.     void debugMode(boolean enabled);
  73.                
  74.         protected:
  75.                
  76.                 //
  77.                
  78.         private:
  79.                
  80.                 boolean debugModeFlag;
  81.                
  82.                 byte stepPin;
  83.                 byte directionPin;
  84.                 byte enablePin;
  85.                
  86.                 bool directionPinsInverted;
  87.                 bool enablePinsInverted;
  88.                
  89.                 int acceleration;
  90.                 int stage1; // the end step of the stage1
  91.                 int stage2; // the end step of the stage2
  92.                
  93.                 int stepsToGo;
  94.                 int stepsGone;
  95.                
  96.                 float stepTime;
  97.                 float startTime;
  98.                 float stage1StepTime;
  99.                 float stage3StepTime;
  100.                 unsigned long nextTimestamp;
  101.                
  102.                 boolean done;
  103.                
  104.                 void step();
  105.                
  106. };

  107. #endif
复制代码


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

  1. #include "EasyStepper.h"

  2. EasyStepper::EasyStepper(byte stepPin, byte directionPin, byte enablePin, bool directionPinsInverted, bool enablePinsInverted)
  3. {
  4.         // save the parameters
  5.         this->stepPin = stepPin;
  6.         this->directionPin = directionPin;
  7.         this->enablePin = enablePin;
  8.         this->directionPinsInverted = directionPinsInverted;
  9.         this->enablePinsInverted = enablePinsInverted;
  10. }

  11. void EasyStepper::startup()
  12. {
  13.         // set the pin mode
  14.         pinMode(this->stepPin, OUTPUT);
  15.         pinMode(this->directionPin, OUTPUT);
  16.         pinMode(this->enablePin, OUTPUT);
  17.         // enable the stepper
  18.         digitalWrite(enablePin, HIGH ^ this->enablePinsInverted);
  19.         // initialize the done to true
  20.         this->done = true;
  21. }

  22. void EasyStepper::shutdown()
  23. {
  24.         // disable the stepper
  25.         digitalWrite(enablePin, LOW ^ this->enablePinsInverted);
  26. }

  27. void EasyStepper::debugMode(boolean enabled)
  28. {
  29.         this->debugModeFlag = enabled;
  30. }

  31. void EasyStepper::rotate(float speed, int steps)
  32. {
  33.         this->rotate(speed, steps, 0);
  34. }

  35. void EasyStepper::rotate(float speed, int steps, int acceleration)
  36. {
  37.         // ignore the zero value
  38.         if (speed != 0 && steps != 0)
  39.         {
  40.                 if (steps > 0)
  41.                 {
  42.                         // CW
  43.                         digitalWrite(directionPin, HIGH ^ this->directionPinsInverted);
  44.                 }
  45.                 else if (steps < 0)
  46.                 {
  47.                         // CCW
  48.                         digitalWrite(directionPin, LOW ^ this->directionPinsInverted);
  49.                 }
  50.                 // done flag
  51.                 this->done = false;
  52.                 // the steps to go
  53.                 this->stepsToGo = abs(steps);
  54.                 // the acceleration
  55.                 this->acceleration = abs(acceleration);
  56.                 if (this->stepsToGo <= 4)
  57.                 {
  58.                         this->acceleration = 0;
  59.                 }
  60.                 // change the speed to stepTime, micro seconds per step
  61.                 this->stepTime = 1000.0 * 1000.0 / abs(speed);
  62.                 // start time
  63.                 this->startTime = this->stepTime * (this->acceleration + 1);
  64.                 // stage1
  65.                 this->stage1 = this->stepsToGo / 4;
  66.                 this->stage1StepTime = (float) this->acceleration * this->stepTime / this->stage1;
  67.                 // stage2
  68.                 this->stage2 = this->stepsToGo / 4 * 3;
  69.                 this->stage3StepTime = (float) this->acceleration * this->stepTime / (this->stepsToGo - this->stage2);
  70.                 // the steps gone
  71.                 this->stepsGone = 0;
  72.                 // current timestamp
  73.                 unsigned long time = micros();
  74.                 if (this->debugModeFlag)
  75.                 {
  76.                         Serial.print("rotate: direction=");
  77.                         Serial.print(steps > 0 ? "CW" : "CCW");
  78.                         Serial.print(", stepsToGo=");
  79.                         Serial.print(this->stepsToGo);
  80.                         Serial.print(", acceleration=");
  81.                         Serial.print(this->acceleration);
  82.                         Serial.print(", startTime=");
  83.                         Serial.print(this->startTime);
  84.                         Serial.print(", stage1=");
  85.                         Serial.print(this->stage1);
  86.                         Serial.print(", stage1StepTime=");
  87.                         Serial.print(this->stage1StepTime);
  88.                         Serial.print(", stage2=");
  89.                         Serial.print(this->stage2);
  90.                         Serial.print(", stage3StepTime=");
  91.                         Serial.print(this->stage3StepTime);
  92.                         Serial.print(", stepTime=");
  93.                         Serial.print(this->stepTime);
  94.                         Serial.print(", currentTimestamp=");
  95.                         Serial.println(time);
  96.                 }
  97.                 // call the step method to rotate the motor
  98.                 this->step();
  99.         }
  100. }

  101. void EasyStepper::stop()
  102. {
  103.         this->stepsToGo = 0;
  104.         this->done = true;
  105. }

  106. void EasyStepper::run()
  107. {
  108.         // the current timestamp
  109.         unsigned long time = micros();
  110.         if (!this->done && time >= this->nextTimestamp)
  111.         {
  112.                 this->step();
  113.         }
  114.         if (this->debugModeFlag)
  115.         {
  116.                 Serial.print("currentTimeStamp=");
  117.                 Serial.println(time);
  118.         }
  119. }

  120. void EasyStepper::step()
  121. {
  122.         // are there some steps to rotate?
  123.         if (this->stepsToGo > this->stepsGone)
  124.         {
  125.                 // HIGH value
  126.                 digitalWrite(stepPin, HIGH);
  127.                 // delay
  128.                 delayMicroseconds(2);
  129.                 // LOW value
  130.                 digitalWrite(stepPin, LOW);
  131.                 // increase the stepsGone
  132.                 this->stepsGone++;
  133.                 // default: stage2
  134.                 float nextStepTime = this->stepTime;
  135.                 if (this->acceleration != 0)
  136.                 {
  137.                         if (this->stepsGone < this->stage1)
  138.                         {
  139.                                 // stage1: down to stepTime from startTime
  140.                                 nextStepTime = this->startTime - this->stage1StepTime * this->stepsGone;
  141.                         }
  142.                         else if (this->stepsGone >= this->stage2)
  143.                         {
  144.                                 // stage3: up to startTime from stepTime
  145.                                 nextStepTime = this->stepTime + this->stage3StepTime * (this->stepsGone - this->stage2 + 1);
  146.                         }
  147.                 }
  148.                 // current timestamp
  149.                 unsigned long time = micros();
  150.                 this->nextTimestamp = time + nextStepTime;
  151.                 if (this->debugModeFlag)
  152.                 {
  153.                         Serial.print("step: stepsGone=");
  154.                         Serial.print(this->stepsGone);
  155.                         Serial.print(", currentTimestamp=");
  156.                         Serial.print(time);
  157.                         Serial.print(", nextTimestamp=");
  158.                         Serial.print(this->nextTimestamp);
  159.                         Serial.print(", nextStepTime=");
  160.                         Serial.println(nextStepTime);
  161.                 }
  162.         }
  163.         else
  164.         {
  165.                 this->done = true;
  166.         }
  167. }
  168.    
  169. boolean EasyStepper::isDone()
  170. {
  171.         return this->done;
  172. }
复制代码


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

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

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

评分

参与人数 1 +5 收起 理由
幻生幻灭 + 5 好人出品,必属精品!

查看全部评分

回复

使用道具 举报

发表于 2013-2-6 23:16:58 | 显示全部楼层
好帖,这个很实用,算法不错
回复 支持 反对

使用道具 举报

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

使用道具 举报

发表于 2013-4-17 15:38:36 | 显示全部楼层
请问好人,对于arduino来说 TB6560上的 EN+/- CW+/- 和CLK+/-这六根线应该怎么接,急求?谢谢!
回复 支持 反对

使用道具 举报

发表于 2013-4-24 09:22:43 | 显示全部楼层
请教大侠这个程序可以驱动多个步进电机么?
回复 支持 反对

使用道具 举报

发表于 2013-4-24 19:02:50 | 显示全部楼层
deepsky 发表于 2013-4-24 09:22
请教大侠这个程序可以驱动多个步进电机么?

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

使用道具 举报

发表于 2013-4-25 11:33:11 | 显示全部楼层
Malc 发表于 2013-2-19 09:22
这个算法看的不是很明白,分成三个阶段的作用是?
加速度不断减小使速度曲线更光滑?
步进加减速要考虑两 ...

请问avr运用笔记446在哪
回复 支持 反对

使用道具 举报

发表于 2013-4-25 11:34:25 | 显示全部楼层
Cola_DOG 发表于 2013-4-17 15:38
请问好人,对于arduino来说 TB6560上的 EN+/- CW+/- 和CLK+/-这六根线应该怎么接,急求?谢谢!

这个淘宝上有的
回复 支持 反对

使用道具 举报

发表于 2013-6-13 23:22:10 | 显示全部楼层
Cola_DOG 发表于 2013-4-17 15:38
请问好人,对于arduino来说 TB6560上的 EN+/- CW+/- 和CLK+/-这六根线应该怎么接,急求?谢谢!

好人在另一贴有说明,负极都接地
回复 支持 反对

使用道具 举报

发表于 2013-6-27 23:04:19 | 显示全部楼层
chqiyi 发表于 2013-6-13 23:22
好人在另一贴有说明,负极都接地

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

使用道具 举报

发表于 2013-9-10 08:31:55 | 显示全部楼层
请问,这个速度最高能达到多大啊?
回复 支持 反对

使用道具 举报

发表于 2013-9-28 00:03:37 | 显示全部楼层
请问楼主:EasyStepper.h这个库怎么下载?
回复 支持 反对

使用道具 举报

发表于 2014-8-6 13:35:56 | 显示全部楼层
赞一个 谢谢楼主!
回复 支持 反对

使用道具 举报

发表于 2015-5-20 14:45:15 | 显示全部楼层
谢谢楼主了,,,可是不会添加.h和.c的
回复 支持 反对

使用道具 举报

发表于 2015-7-25 09:01:38 | 显示全部楼层
楼主啊 怎么把你这个库添加到arduino里是
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-28 15:25 , Processed in 0.050567 second(s), 33 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表