AVR446步进电机算法推导及应用
声明:如有任何侵权问题请给我留言,本博客文章均由我个人辑写!
在学习步进电机控制过程中可谓困难重重,资料零散,或者说资料很难找,所以我决定在这个博客这里整理目前网络上的步进电机算法,并重新推导、理解他们,且能够真正的应用起来,并希望能够帮助大家,学习还是自己的,依靠自己的努力才能够学到手,不要照搬即用,应该去理解其中的奥秘。
这一章主要介绍AVR446的推导过程,在很多资料里,很少注重一个资料里的基础知识,大部分人可能像我一样基础知识薄弱,在推导过程中存在很多疑惑和难点,无疑增加了学习的难度,在我写的博客里,对这个算法的推导之前会列出需要掌握的一些基础知识,方便各位进行查阅推导,当然我个人能力有限,有些地方可能含糊不清,希望各位大佬给予指正和指导。
简介
AVR446文档是一篇关于如何通过实时计算实现步进电机梯形曲线加减速在低端MCU实现控制的一篇资料,文档是英文的,幸好大部分内容都比较简单,而且有源码辅助理解。主要思想是加速运动曲线 S = 1/2 * at² ,但实际计算时它引入了开方计算,这在低端MCU上是不允许的,所以通过对开方计算使用泰勒公式的一种特殊形式-麦克劳林展开式,来逼近开方计算,使公式中不包含开方。控制方式上使用了状态机。
基础知识及理论推导
在学习之前先回顾一下基础知识
1.加速度公式及其相关公式
S = 1/2 *at²、v=at等
2.步进电机速度与定时器计数频率、定时器比较匹配值、步距角的关系
我在博文“步进电机S(Sigmoid)型曲线加减速控制【查表法】”中已经推导了一次,详情请各位去查阅。下面列出一些与AVR446文档要求的公式。
时间关系:
ft : 定时器计数频率
c : 比较匹配的计数值(带下标c0、c1、cn.....代表每一步的比较匹配数值)
tt : 定时器计数周期 tt = 1/ft
δt: 脉冲时间间隔
其中 :δt = c*tt = c/ft
步距角、角位移关系:
spr : 步进电机旋转一圈的总步数 如1.8°步距角下,旋转一圈需要200步(脉冲)
α:弧度制的步距角 -> α = 2π / spr [rad]
n: 步数(脉冲数)
θ:角位移,转过了多少弧度? -> θ = n * α [rad]
ω:角速度 -> ω = α / δt
ω':角加速度
其中:1rad ≈ 9.55r/min
由上面的关系我们就可以轻易推导出
θ = n*α = 1/2 * ω' * t²
则 n 个脉冲的角位移 需要的 时间为:
tn = sqrt(2nα/ω') 注意:tn的n是下标;
那么第n个脉冲的时间间隔就为:cn*tt = tn+1 - tn = sqrt(2α/ω') * (sqrt(n+1)-sqrt(n)):自己算一下,cn的n是下标;
则 第n个脉冲的时候 比较匹配值cn = ft * sqrt(2α/ω') * (sqrt(n+1)-sqrt(n))
特别的,当n = 0 时 c0 = ft * sqrt(2α/ω')
∴ cn = c0 * (sqrt(n+1)-sqrt(n))
这样我们就能计算出每一个脉冲的时间间隔和定时器比较匹配的值了。
为了消除开方计算,我们使用泰勒展开式的一个特殊公式来逼近开方计算,(X四次方被认为是无穷小)公式如下:
我们应该认识到,本次得Cn值应该由上一次Cn值求出,所以我们令cn / cn-1 得(突然发现word可以编辑公式2333...........)
然后将 根号n 提出来得,值得注意的是,在文档中认为(1/n³)已经算是高阶无穷小了,因此将其省略掉,其次是不引入更复杂的计算。
得出:
即:
到此,AVR446笔记中的加减速算法已经推导完毕,接下来介绍如何应用到单片机中。
应用
在应用之前我们先想一想,我控制一个步进电机加减速需要输入什么参数?,有以下输入参数:
加速度、减速度、最大速度、运行的步数
第二,电机将会工作在哪几种状态?状态如下:
加速状态、加速到最大速度的匀速状态、减速状态、停止状态
同时,我们应该注意到,在我们输入的参数中,是否能使电机加速到想要的速度呢?所以实际上电机运行的情况还会存在以下几种情况:1.电机能够加速到最大速度、2.电机不能够达到最大速度就应该减速 3.还有一种就是,减速度输入过小导致的第二种情况。
所以我们需要预先计算出几个必须的点,1. 第一个加速的点c0 2. 最大速度对应的比较匹配值 3.设定的加速度到达最大速度所需要的步数 4.当前设定加速度减速度下 必须减速的步数 5.根据以上求出来的步数,求出减速步数。
根据前面的知识我们可以很简单的计算出C0 ,这里原文说是将会引入一个错误,这个错误我没发现,解决办法是将C0再乘以0.676..。我估计是如果直接使用C0可能导致启动不平滑,贴出原文,大家帮忙论证一下。以便日后修改这篇文章,在此先感谢各位。(问题的原因已找到:即在n = 1,时,级数逼近的误差高达0.44,为了减少这个误差,并且使曲线上升平滑,需要补偿此 误差,解决办法就是C0*0.6776)
所以,C0 = ft * sqrt(2*α/ω')*0.676
最大速度是的匹配值 Cmaxspeed = α * ft / ω (由公式: ω = α / δt, δt = cn * tt)
达到最大速度需要的加速步数 Nmax = ω² / 2*α*ω' (由公式:tn = ωn/ω' 、2*n*α = ω'tn² 导出,其中t、ω字母后的n是下标)
计算加速步数 ,在计算之前先看看加速减速步数与总步数之间的关系,由达到最大速度需要步数的推导公式很容易求得
nω' = ω² / 2*α,其中角速度和步距角都是已知的,所以得出两个不同加速度之间的关系n1ω'1 = n2ω'2 ,这说明了加速度和步数所对应的关系,为了能够得到加速步数与总步数的关系,我们在等式两边各加上n1ω'2,由此可以导出以下公式:
n1 = (n1+n2)*ω'2/(ω'1 +ω'12) 这个结果将用于与达到最大速度的Nmax进行比较,检查是否能够满足电机达到最大速度,否则将减速。
若Nmax < n1 则表明可以达到最大速度 ,则对应的加速步数为Nmax,减速步数可以通过上面求出的关系式轻易得出
减速步数 Ndecel = Nmax *(ω'1/ω'2)
若Nmax > n1 则表明无法达到最大速度,并且在必须减速的点开始减速,则对应的加速步数为n1,减速步数使用总步数减去n1即可,即 Ndecel = Steps - n1.
这样,将初始化参数全部求出后,将C0赋值给比较匹配寄存器,进入到对应的状态即可,在加速减速状态中调用公式
即可完成加速减速过程,并且值得注意的是,这里边含有除法,在MCU计算中意味着存在余数的误差,为了提高计算精度,文档中对程序中每一次除法都将余数求出来,并且加到下一次计算之中。详情请看相关代码。
程序实现
本设计还是采用Arduino Uno(ATmega328) + 步进电机驱动器 + 42步进电机实现
其中 步进电机为细分,意味着spr是1600。定时器计数频率为250Khz
需要注意的是,AVR446例程中所使用的单位是弧度制,并且为了便于单片机计算都将数据放大了100倍处理,相当于输入的参数也需要放大100倍,比如输入加速度为1000,则实际为10rad/s²。
/*电机参数结构体*/
typedef struct {unsigned char run_state : 3; //运行状态unsigned char dir : 1; //方向unsigned int step_delay; //每一步的时间间隔(匹配值) unsigned int decel_start; //必须开始减速的步数signed int decel_val; //减速步数signed int min_delay; //最大速度时比较匹配值signed int accel_count; //加速计数器
} speedRampData;
speedRampData srd; //定义#define T1_FREQ 250000 //定时器频率250khz//! 一圈的步数 4 细分
#define SPR 800#define ALPHA (2*3.14159/SPR) // 步距角
#define A_T_x100 ((long)(ALPHA*T1_FREQ*100)) // 用于计算最大速度时的匹配值 步距角*脉冲数*100
#define T1_FREQ_148 ((int)((T1_FREQ*0.676)/100)) // 用于计算首脉冲 C0
#define A_SQ (long)(ALPHA*2*10000000000) // 用于计算首脉冲 C0
#define A_x20000 (int)(ALPHA*20000) // 用于计算最大步数需要的加速步数Nmax// 电机状态
#define STOP 0
#define ACCEL 1
#define DECEL 2
#define RUN 3void speed_cntr_Move(int steps, unsigned int accel, unsigned int decel, unsigned int speeds);//电机参数设置,并运动
void speed_cntr_Init_Timer1(void);//定时器初始化
void OneStep(uint8_t dir);//电机根据方向运行一步
/*初始化*/
void setup() {pinMode(2,OUTPUT); //此引脚输出方向pinMode(3,OUTPUT); //此引脚输出脉冲speed_cntr_Init_Timer1();Serial.begin(115200);speed_cntr_Move(-20000,9000,9000,9000);
}
/*主循环*/
void loop() {}
/*定时器1 OCR1A 比较匹配中断 CTC模式*/
ISR(TIMER1_COMPA_vect)
{unsigned int new_step_delay; //新的匹配值static int last_accel_delay; //static unsigned int step_count = 0;//步数计数static unsigned int rest = 0; //余数OCR1A = srd.step_delay; //OCR1A 重新赋值switch(srd.run_state) {case STOP:step_count = 0;rest = 0;TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10));break;case ACCEL:OneStep(srd.dir); //运行一步step_count++;srd.accel_count++;new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算出新的匹配值rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1); //求出余数if(step_count >= srd.decel_start) { //判断是否进入减速srd.accel_count = srd.decel_val;srd.run_state = DECEL;}else if(new_step_delay <= srd.min_delay) { //判断是否能进入最大速度last_accel_delay = new_step_delay;new_step_delay = srd.min_delay;rest = 0;srd.run_state = RUN;}//Serial.println("ACC");break;case RUN:OneStep(srd.dir); //运行一步step_count++;new_step_delay = srd.min_delay;if(step_count >= srd.decel_start) { //判断是否要减速了srd.accel_count = srd.decel_val;new_step_delay = last_accel_delay;srd.run_state = DECEL;}break;case DECEL:OneStep(srd.dir);step_count++;srd.accel_count++;new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/(4 * srd.accel_count + 1));rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);if(srd.accel_count >= 0){ //步数走完了吗?srd.run_state = STOP;}break;}srd.step_delay = new_step_delay; //获取新的一次的匹配值
}
void OneStep(uint8_t dir)
{digitalWrite(2,dir);digitalWrite(3,1); //输出一个脉冲digitalWrite(3,0);
}
void speed_cntr_Move(int steps, unsigned int accel, unsigned int decel, unsigned int speeds)
{unsigned long max_s_lim;unsigned int accel_lim;if(steps < 0){srd.dir = 0;// 获取步数信息steps = -steps;}else{srd.dir = 1;//设置方向}if(steps == 1){ //只有1步时如何处理?srd.accel_count = -1;srd.run_state = DECEL;srd.step_delay = 1000;OCR1A = 10; //使其进入中断TCCR1B |= ((0<<CS12)|(1<<CS11)|(1<<CS10));}else if(steps != 0){srd.min_delay = A_T_x100 / speeds;//计算最大速度 ,脉冲的时间间隔 srd.step_delay = (T1_FREQ_148 * sqrt(A_SQ / accel))/100;//计算C0 加速开始的第一段 脉冲时间间隔max_s_lim = (long)speeds*speeds/(long)(((long)A_x20000*accel)/100);//根据给定速度和加速度,需要多少步才能达到/*0的情况*/if(max_s_lim == 0){max_s_lim = 1;}accel_lim = ((long)steps*decel) / (accel+decel);//加速度段n1if(accel_lim == 0){accel_lim = 1;}// 可以达到最大速度if(accel_lim <= max_s_lim){srd.decel_val = accel_lim - steps;//无法达到最大速度的减速步数}else{srd.decel_val = -((long)max_s_lim*accel)/decel;//能达到最大速度的减速步数}//0的情况 必须从减速到停止if(srd.decel_val == 0){srd.decel_val = -1;}// 找到何时开始减速的步数srd.decel_start = steps + srd.decel_val;//速度太低了,直接运行if(srd.step_delay <= srd.min_delay){srd.step_delay = srd.min_delay;srd.run_state = RUN;}else{srd.run_state = ACCEL; //否则从加速开始运行}// 复位计数器srd.accel_count = 0;OCR1A = 10;// 设定定时器分频TCCR1B |= ((0<<CS12)|(1<<CS11)|(1<<CS10));}
}
/*250Khz 并开启比较匹配中断*/
void speed_cntr_Init_Timer1(void)
{TCCR1A = 0;TCCR1B = (1<<WGM12)|(0<<CS12)|(1<<CS11)|(1<<CS10);TIMSK1 = (1<<OCIE1A);OCR1A = 15;sei();srd.run_state = STOP;delay(1);
}
经过测试,电机能够时间T型加减速,并且不会产生速度突变,运用得当简直是居家必备之良品啊!哈哈。
至此,AVR446的学习就告一段落了,如有疑问请给我留言,我会及时处理。
20190125更新:在几个月前,我已把AVR446更进一步改进了,新的算法包含速度模式和位置模式,位置模式与AVR446本身一致,只是单位变成了rpm,速度模式是我个人新增的,包含速度模式启动,速度模式中任意变速,以及任意时刻减速到停止的功能,有时间也更新一下吧。
AVR446资料地址:https://download.csdn.net/download/renjiankun/10455475
aa
a aasas
AVR446步进电机算法推导及应用相关推荐
- 人人都能看懂的EM算法推导
作者丨August@知乎(已授权) 来源丨https://zhuanlan.zhihu.com/p/36331115 编辑丨极市平台 估计有很多入门机器学习的同学在看到EM算法的时候会有种种疑惑:EM ...
- 第八课.EM算法的合理性与算法推导
目录 EM算法背景 EM算法迭代的合理性 EM算法推导 EM算法的E步和M步 分析EM算法的由来 EM算法背景 在硬币投掷和班级身高问题中,引入了隐变量问题,模型变成了混合模型,我们不能直接利用极大似 ...
- BP神经网络算法推导
一:算法推导 神经网络通过模拟人的神经元活动,来构造分类器.它的基本组成单元称为"神经元",离线情况下如果输入大于某值时,设定神经元处于兴奋状态,产生输出,否则不响应.而这个输入来 ...
- 收藏 | 人人都能看懂的LSTM介绍及反向传播算法推导
点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者:陈楠 来源:知乎 链接:https://zhuanla ...
- em算法 实例 正态分布_人人都能看懂的EM算法推导
↑ 点击蓝字 关注极市平台作者丨August@知乎(已授权)来源丨https://zhuanlan.zhihu.com/p/36331115编辑丨极市平台 极市导读 EM算法到底是什么,公式推导怎么去 ...
- 反向传播算法推导、激活函数、梯度消失与爆炸
目录 反向传播算法 定义 推导过程 激活函数 定义 性质 常用的激活函数 Sigmoid Tanh ReLU softmax 梯度消失与梯度爆炸 起因 出现的原因 表现 解决方案 参考文档 反向传播算 ...
- HashMap扩容时的rehash方法中(e.hash oldCap) == 0算法推导
PS:由于文档是我在本地编写好之后再复制过来的,有些文本格式没能完整的体现,故提供下述图片,供大家阅览,以便有更好的阅读体验: HashMap在扩容时,需要先创建一个新数组,然后再将旧数组中的数据转移 ...
- 支持向量机 SVM 算法推导优缺点 代码实现 in Python
1.基本思想 前面讲到的Logistic Regression在拟合过程,实际上关注所有样本点的贡献,即寻找这么一个超平面,使得正例的特征远大于0,负例的特征远小于0,强调在全部训练数据上达到这一目标 ...
- 周志华《机器学习》西瓜书新出算法推导视频!(超级详细)
[文末重金招募讲师]不是每个人都适合2万小时定律,努力的方向不对,就是白努力. 如果你对人工智能跃跃欲试,第一步该怎么办?我通常的做法是,先收集人工智能有关的信息,或者问问身边正在学习的师兄师姐,寻求 ...
- CSK与KCF算法推导(二)
本文是CSK与KCF算法推导的第二篇,主要介绍标量对向量求导.核函数.岭回归问题求解等内容. CSK与KCF算法推导(一)--DFT.相关运算和循环卷积 (本文)CSK与KCF算法推导(二)--带 ...
最新文章
- 关于jHipster框架在构建中的出现的error修复
- C# list删除 另外list里面的元素_C#并发实战Parallel.ForEach使用
- gridview合并单元格
- codeforces C. Inna and Huge Candy Matrix 解题报告
- SPT20 协议_过户协议书模板五篇
- Cordova WP8 插件开发
- mysql php 时间比较大小_MySql中时间比较的实现
- 复盘!12 小时清掉 3500 份生财日历
- 拓端tecdat|R语言使用混合模型进行聚类
- Tableau零基础教程
- 新手村-数组-P2141 珠心算测验
- 实现当输入框为空时,按backspace键后执行相应操作(明确按键监听事件和文本框内容变化的内在逻辑)
- 鼠标键盘长时间无动作、电脑空闲超过一定时间自动关机、自动睡眠软件 —— 定时执行专家
- Jmeter性能测试云平台搭建
- 是用JDBC从数据库中获取数据并以java对象返回
- 思科德Exynos4412(2G内存)四核平板电脑方案
- (转)百万年薪的人才泡沫与人工智能的虚假繁荣
- Web端-缓存数据及user_agent修改
- 12.权重衰退+QA
- 《GitHub入门与实践》读书笔记