盗梦陀螺攻略5- PID平衡算法
由 动力老男孩 发表于 2011/02/11 21:47:59刚过完长假,继续发攻略来克服长假综合症。看到galiu同学带着女儿玩乐高,我突然非常高兴,哈哈,也许这就是若干年后的我啊!
进入正题,介绍提了多次的PID平衡算法。先从网上摘抄一段:
这个理论和应用自动控制的关键是,做出正确的测量和比较后,如何才能更好地纠正系统。
在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。它以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。当被控对象的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。即当我们不完全了解一个系统和被控对象,或不能通过有效的测量手段来获得系统参数时,最适合用PID控制技术。PID控制,实际中也有PI和PD控制。PID控制器就是根据系统的误差,利用比例、积分、微分计算出控制量进行控制的。
比例(P)控制
比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差(Steady-state error)。
积分(I)控制
在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的或简称有差系统(System with Steady-state Error)。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到等于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。
微分(D)控制
在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用,其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入 “比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在调节过程中的动态特性。
看概念可能有点晕,举个小小的例子也许能帮助理解。看下面的图:
假设我们想把一个小球稳定在一个光滑的坡顶,这显然是一个不平衡的系统,稍有扰动小球就会滚下来。假设恰好平衡的位置坐标是L,我们可以测量到小球的位置是x,那么怎么给小球施加f(x)的力反馈,让它能够平衡呢?
最直观的想法就是f(x) = Kp*(L-x),简单的说就是你在左边我就向右推,你在右边我就向左推,这就是比例因子P;
现在考虑两种情况,同样是在x位置,小球静止和小球具有速度V这两种情况。很明显,如果V>0,我们只需要施加更小的力,因为小球自身的惯性会让它运动向平衡位置。所以可以修正f(x) = Kp*(L-x) – Kd*V。因为速度一般不容易测量,我们常常用位置的变化Δx除以测量的时间差Δt来计算速度,所以这就是微分因子D;
情况继续发生变化,上面考虑的是斜坡静止的情况,如果这个变态的斜坡是移动的怎么办呢?(例如两轮平衡机器人实际上是可以运动的,对于静止的磁悬浮来说,不需要考虑这个参数)这时候我们需要不断的累加并平均x值,来计算平衡位置的L,这个就是积分因子I;
以上就是PID的简要介绍。说起来容易,真正调试的时候,最恼火的就是这几个参数到底是多少,办法只有一个:试,不断的试!
当然,试验也不要当老黄牛,累死都没人知道。我曾经试其中某个参数,从0.1开始,每次加0.01,差点试到崩溃。后来想了个办法,用串口把Arduino的读数发送到电脑,然后用软件分析结果,看到数据明显发现这个值偏小,发狠改到20,就这样成功了…..
当时的数据找不到了,发一段成功悬浮时的log吧,其中两种颜色分别代表两个方向的传感器读数(相当于x):
从图上可以看出,平衡的位置具体在哪里,我们可能不一定能精确知道,但是通过合适的反馈系统,陀螺能够自动稳定到相应的位置上。参数不正确的情况下,这些点会越振越远,直到失控。
最后附上源代码,没有时间整理,可能有不少问题,有兴趣的同学凑合看吧
//PINs setting int adjust1Pin = 1; //用来调节A的电位器 int adjust2Pin = 2; //用来调节B的电位器 int read1Pin = 4; //用来连接输入A传感器 int read2Pin = 3; //用来连接输入B传感器 int i1Pin = 36; //连接电机驱动板的I1接口 int i2Pin = 37; //连接电机驱动板的I2接口 int i3Pin = 39; //连接电机驱动板的I3接口 int i4Pin = 38; //连接电机驱动板的I4接口 int power1Pin = 5; //连接电机驱动板的EA接口 int power2Pin = 6; //连接电机驱动板的EB接口 int rotatePin = 3; //用来控制磁场旋转的PMW接口 boolean debug = false; boolean writeLog = false; double setKd1 = 0.55; double setKd2 = 0.55; double setKp = 22; int offset = 70; int delayMs = 1; int tick = 0; int myLog[3500]; //PID structure typedef struct { double target; double aver; double Kp; double Kd; int preError; int power; boolean flag; double v; } PID; PID Pid1, Pid2; void setup() { pinMode(i1Pin, OUTPUT); //I1和I2都是数字信号 pinMode(i2Pin, OUTPUT); //通过设置I1和I2来控制电流方向 pinMode(i3Pin, OUTPUT); //I1和I2都是数字信号 pinMode(i4Pin, OUTPUT); //通过设置I1和I2来控制电流方向 pinMode(power1Pin, OUTPUT); //按占空比方式输出的模拟信号 pinMode(power2Pin, OUTPUT); //按占空比方式输出的模拟信号 pinMode(rotatePin, OUTPUT); //按占空比方式输出的模拟信号 //analogWrite(rotatePin, 128); Serial.begin(9600); //设置波特率 TCCR0B = 0x01; // Timer 0: PWM 5 & 6 @ 16 kHz TCCR1B = 0x01; // Timer 1: PWM 9 & 10 @ 32 kHz TCCR2B = 0x01; // Timer 2: PWM 3 & 11 @ 32 kHz Pid1.Kp = setKp; Pid1.preError = 0; Pid1.Kd = setKd1; Pid1.power = 0; Pid1.flag = true; Pid1.target = 300; Pid1.aver = 0; Pid1.v = 0; Pid2.Kp = setKp; Pid2.preError = 0; Pid2.Kd = setKd2; Pid2.power = 0; Pid2.flag = true; Pid2.target = 300; Pid2.aver = 0; Pid2.v = 0; tick = 0; } int tick2 = 0; //boolean rotateFlag = true; void loop() { //digitalWrite(rotatePin, rotateFlag); //rotateFlag = ! rotateFlag; //delay(16000); //return; if(debug) tick = 0; tick++; if(tick==500) { tick2++; if(tick2<50) {tick = 0;return;} tick2 = 0; if(writeLog) { for(int i=0;i<500;i++) { Serial.print(myLog[i*7 + 0]); Serial.print(" "); Serial.print(myLog[i*7 + 1]); Serial.print(" "); Serial.print(myLog[i*7 + 2]); Serial.print(" "); Serial.print(myLog[i*7 + 3]); Serial.print(" "); Serial.print(myLog[i*7 + 4]); Serial.print(" "); Serial.print(myLog[i*7 + 5]); Serial.print(" "); Serial.print(myLog[i*7 + 6]); Serial.println(" "); } Serial.println(Pid1.target); Serial.println(Pid1.preError); Serial.println(Pid2.target); Serial.println(Pid2.preError); } return; } else if(tick>500) { tick = 0; //delay(990000); return; }; //=======第一组电位器和传感器======== int readValue1 = 0; for(int i = 0; i < 4; i++) readValue1 += analogRead(read1Pin); readValue1 >>= 2; //readValue1 += (Pid1.flag ? 1 : -1) * Pid1.power / 17; int adjustValue1 = analogRead(adjust1Pin); //410 analogRead(adjust1Pin); Pid1.aver = Pid1.aver * 0.9995 + readValue1 * 0.0005; Pid1.target = Pid1.target + (Pid1.target - Pid1.aver) / 100.0; Pid1.target = max(0, max(adjustValue1 - offset, Pid1.target)); Pid1.target = min(755, min(adjustValue1 + offset, Pid1.target)); //=======第二组电位器和传感器======= int readValue2 = 0; for(int i = 0; i < 4; i++) readValue2 += analogRead(read2Pin); readValue2 >>= 2; //readValue2 += (Pid2.flag ? 1 : -1) * Pid2.power / 6; int adjustValue2 = analogRead(adjust2Pin); //240 analogRead(adjust2Pin); Pid2.aver = Pid2.aver * 0.9995 + readValue2 * 0.0005; Pid2.target = Pid2.target + (Pid2.target - Pid2.aver) / 1000.0; Pid2.target = max(0, max(adjustValue2 - offset, Pid2.target)); Pid2.target = min(755, min(adjustValue2 + offset, Pid2.target)); if(debug) { Serial.println(adjustValue1); Serial.println(adjustValue2); Serial.println(readValue1); Serial.println(readValue2); Pid1.flag = adjustValue1 > 512; Pid1.power = abs(adjustValue1 - 512) / 2; if(Pid1.power > 255) Pid1.power = 255; digitalWrite(i1Pin, Pid1.flag); digitalWrite(i2Pin, !Pid1.flag); analogWrite(power1Pin, Pid1.power); Pid2.flag = adjustValue2 > 512; Pid2.power = abs(adjustValue2 - 512) / 2; if(Pid2.power > 255) Pid2.power = 255; digitalWrite(i3Pin, Pid2.flag); digitalWrite(i4Pin, !Pid2.flag); analogWrite(power2Pin, Pid2.power); delay(32000); return; } //Calculate power values double v, error; error = readValue1 - Pid1.target; v = error - Pid1.preError; Pid1.v = (Pid1.v * 6 + v) / 7; Pid1.power = (int)error * Pid1.Kd + Pid1.v * Pid1.Kp; Pid1.flag = Pid1.power > 0; Pid1.power = abs(Pid1.power); if(Pid1.power>255) Pid1.power = 255; Pid1.preError = error; error = readValue2 - Pid2.target; v = error - Pid2.preError; Pid2.v = (Pid2.v * 6 + v) / 7; Pid2.power = (int)error * Pid2.Kd + Pid2.v * Pid2.Kp; Pid2.flag = Pid2.power < 0; Pid2.power = abs(Pid2.power); if(Pid2.power>255) Pid2.power = 255; Pid2.preError = error; //Write PMW to control the floa digitalWrite(i1Pin, Pid1.flag); digitalWrite(i2Pin, !Pid1.flag); analogWrite(power1Pin, Pid1.power); digitalWrite(i3Pin, Pid2.flag); digitalWrite(i4Pin, !Pid2.flag); analogWrite(power2Pin, Pid2.power); myLog[tick * 7 + 0] = tick; myLog[tick * 7 + 1] = (int)Pid1.target; myLog[tick * 7 + 2] = readValue1; myLog[tick * 7 + 3] = Pid1.power; myLog[tick * 7 + 4] = (int)Pid2.target; myLog[tick * 7 + 5] = readValue2; myLog[tick * 7 + 6] = Pid2.power; /* for(int i=0;i<8;i++) { digitalWrite(rotatePins[i] , 0); digitalWrite(rotatePins[(i + 1) % 8] ,1); delay(1); } digitalWrite(rotatePins[0] , 0); */ delay(delayMs); }
哇哈~这个赞~都用到PID控制了!学习学习!
玩平衡用PID,价格便宜量又足
是个好东东,我还不太会啊
那个 segway 小车的PID 曾经测试了N^N遍..还是没有成功
哦?改天我也试试看
你可以跟galiu同学探讨一下
我想请问,你加的两个电位器是干嘛用的?
…
用什么软件、分析接收串口发来的数据?
用一个叫Origin的软件,分析数据专用的
虽然不太懂,学习一下。呵呵
大哥!!!佩服的五体投地啊!!!
我是学计算机的,我们那个单片机啊什么的都没学,稍微会点编程,
好后悔以前电子电路打酱油了啊……
对你的这些东西都感到震撼!!!
头一回有这么强烈的想好好学点东西的冲动……
能不能跟我说下,要学习些哪些方面的知识啊……
谢谢,膜拜啊……
哈哈,爱好跟专业是两回事,我的专业是航空发动机
有了想法,在google上查查资料,动起来就没那么难了
需要涉及到的知识点主要包括:电子电路,嵌入式,C或者Java编程
电子电路我也不熟,所以用的是Arduino的开发板,不用做板子了
被点名了哇?呵呵。
带着女儿玩乐高的好处之一是,申请经费非常便利啊…
最近刚借着要遥控乐高为名,把手机换成了G7,努力搞Android中…
cool!我最近也刚入手了G7,嘿嘿,也是准备用来遥控用
blog如果你自己有空间的话,就用wordpress
没有空间的话,用新浪微薄
请教下楼主,blog有哪个比较推荐啊?
老大研究下‘四轴’飞行器吧,那个更爽!看看ar.drone
不是吧,我说自控的都没你用的熟。悲剧,自己已经被无情的就业大军推倒自动控制行业了。电子和机器人竟成业余爱好了。我可怜的IFAN还躺在工具箱里。
工作和爱好确实很难兼顾,不容易阿
好强啊,第一次进入到这个网站,我琢磨到半夜才恋恋不舍的关电脑,太佩服了,作为电子专业的我,深感羞愧,C语言我们才刚刚起步学习,不想您老人家都已经出神入化了。我的好几个同学对你的网站都爱疯了,最近我们几个人组织三人的小队伍,打算将您的陀螺战役再做一遍,以表敬意!中途遇到什问题还望您多多指点,顺便问一下,这样的制作,成本会很高吗?
欢迎欢迎!
这个制作成本不高,少吃几顿饭就出来了
如果用老顽童的电路方案,会更便宜
我的方案用了单片机,那个arduino的板子可能会贵一点,一百多吧
另外,磁铁和线圈也得各几十元
好嘞,说干就干,下周末我们就去上海买材料去~~~
哇,还得去上海买?路费就不便宜了吧?
我那个有个清单,先看看
到时候一次全搞定,省的老跑
实在不够的可以淘宝
没有啊,我学校离那儿近,半个小时的路就OK了,不过说的对,有些东西却是要去淘宝的,但更想去真正的电子市场看看,体验一下…感觉会不错~哈哈
代码好难看懂 能否多加一点注释啊
或者有一个流程图也行 这样看起来会比较方便吧。。。不然那么多 符号数字。。头都大了。。。
动力哥!!!!有米有比较完整的原理图啊 就是你做的这个。。有的话麻烦一下~~~~~发到我邮箱吧 453569822@qq.com 感谢了 !!!!!!!!最近一直在弄这个。。。很悲催啊啊啊
呵呵,看帖不仔细吧,原理图我不是发过了吗?
http://www.diy-robots.com/Resources/meglev/diagram.pdf
我就是照这个做的,原理完全一样
至于流程图和我这个Arduino版本的原理图…..
汗
我要是有时间做早发出来了,况且也不会做,Protel不会用
这个图看了好多遍啊 就是没看多懂。。。。。
主要是对霍尔器件的用法不是很懂
网上搜了没搜到
于是看了半天数据手册 。。。还没看明白
用fritzing做原理图比较快。
多谢指点,呵呵,下载一个看看
这世界还是好人多啊
还有 霍尔元件放在那个地方 是用来监测谁的磁通的变化?想来想去 4个螺线管的磁场方向应该是平行霍尔元件的表面的吧。那霍尔器件就不能监测到了。。
说白了 我还是对这个系统如何反馈。如何控制有点迷惑。。。
好了 虽然这个问题有点白痴。。请表拍我~~~~~~
你说对了,4个线圈的磁场方向是平行霍尔表面的,目的就是线圈电流对霍尔没有影响
注意注意,霍尔元件是用来判断陀螺位置的,跟线圈没有关系
哈哈,你都知道自己问的问题不合适了,自己拍几下吧
哦 soga!那程序呢???有没有详细的注释哈。。不然太难看了。。
我帖程序的时候,显然不会故意把注释删了再贴
你看上面那几行英文就是我的注释了
其实就是PID算法
我建议你也先做一个上拉式的,只有一个线圈
以此了解PID,然后就能看懂代码了
这段代码,你把debug,tick相关的都删掉,然后把所有的Pid1,Pid2这样的删掉一半,就会发现其实没几行了
嗯 好的 上拉式的貌似简单的。。还有一个问题。debug和 tick是做啥的啊???
终于快要看懂了 。这个是用的位置式PID算法吧?(别又错了) 。
关于PID的计算过程那里已经懂了
但还是有几个地方不太明白
1.target = 300 ;为什么是300 300对应的电压应该是300/1024*5 吧
而霍尔传感器的输出(无磁通时)为2.5V啊 这之间应该有运放的作用吧?
2.//=======第一组电位器和传感器======== 这个过程不是太明白在做些什么。。能稍微讲一下么。大概意思就行。。
这个采样用到了什么滤波算法?
这里采用了最先进,快速,高效的算术平均滤波算法…..
好吧,专家们一般都这样用术语吓唬人
其实就是取几个值平均一下嘛,代码看这里:
int readValue1 = 0;
for(int i = 0; i < 4; i++) readValue1 += analogRead(read1Pin);
readValue1 >>= 2;
内个 readValue1 >>=2 这里是什么意思?查了资料说指2进制位移运算,但是,高中狗对介个并不太懂,可以说下它在这里用处么?
>>2表示位向右移两位,二进制所以相当于得到的值除以4(比如十进制1000右移一位表示0100,变成10分之1),即取平均,相当于滤波。
谢过~
没错,就是PID,呵呵
target你没看懂太正常了,因为我刚才看了半天,想了半天才想起来这是干啥用的
大概说说当初加这个参数的原因
我们调节一个平衡位置的时候,需要有个目标值,它表示陀螺正好处于平衡位置时传感器的读数。这个目标值是多少我们其实并不知道,而且它会随着温度,环境磁场而变化,这就是我外接ajustPin的原因,既然你不知道目标值是多少,那么调一调试试,拧电位器让它能平衡为止
所以我最初的程序是这么写的:
Pid1.target = adjustValue1;
请注意,这样写就已经可以实现平衡了!所以你看代码的时候,可以先把Pid1.aver,offset这些东西都删掉,代码就容易看懂了
后来发现一个小问题,比如物理上真正的平衡点位置是300,而我拧到的位置是adjustValue1=350,虽然有点误差,但是依然可以平衡。只是线圈强行把陀螺稳定在一个不平衡的位置,它肯定是要多用电的。所以我想做点优化,让程序自己找到这个300值。上面那个aver就是平均的意思,当我发现施加的电流多次平均以后总是偏向某一边,我就把adjustValue做一点修正,让它反过去接近真正的值。
结果问题又来了,当我刚把陀螺放上去的时候,这个aver是从0突然变大的,最初的一秒钟很不准确,这个算法会误认为陀螺现在位置偏移非常大,就猛加电流,结果真的就不平衡了。所以我又加了一个offset参数,表示修正的范围,超过这个范围,我就不在修正了。
这段代码的结果是,陀螺刚放上去的时候,会稍微抖动一下,然后会慢慢的越来越平稳。
总结:这上面都是浮云,其实我监测的电流值只下降了一点点,至于平稳,你慢慢的调电位器,一样可以调到一个非常平稳的位置。不过我也懒得把程序改回去了,这就是你看到的结果。建议你只留这么一句即可:
Pid1.target = adjustValue1;
这样顺便把第一个问题也回答了,那个target最后是会被adjustValue覆盖的,所以写成多少都可以,写成300完全是个人爱好
请教一下第128行 Pid1.aver = Pid1.aver * 0.9995 + readValue1 * 0.0005;在setup()就已定义Pi1.aver=0,那么*0.9995有什么意义呢?
昨天终于把电路搭好了 看着一堆一堆杂乱的线 放上小磁铁试了试。
当用手托着小磁铁靠近线圈上方时,感觉到有点震动,感觉也快要平衡了(自我安慰一下),但一松开手 小磁铁就被吸到大磁铁上去了。。
有一个问题 这个adjust1Pin 这个电位器的解法是这样的吗??电位器两端分别接地 和 VCC ,中间的接arduino 的1管脚 ???()
然后调平衡用这个来调??
始终感觉不大对劲啊。可以调节与LM358相连的电位器,使得输出运放输出电压在2.5V 那么可以设置target=511啊 。这样不是更方便吗?
你理解的很正确
但是与LM358相连的电位器是被放大几十倍的,太灵敏了,稍微一动就变几十,想把它调到准确的2.5V有点困难(还会温漂,每次读数都变)
而且那个电位器比较小,是焊在板子上的,你做好以后封到盒子里,怎么调节它呢?
所以我再引出来一个大电位器,这个是不放大的,调起来方便,而且可以把它安装在盒子的面板上,看上去比较酷
具体操作的时候,先调板子上的电位器,让它差不多是2.5V,这个以后就不动了。将来再调就调adjustPin1,如果传感器温漂到2.0V,你调节target到400左右也是一样平衡的
与LM358项链的电位器这个调节会改变运放同相端的电压。这个电压是直流的 不会被放大。运放放大的交流信号吧,也是就传感器测得的电压的波动(传感器的输出电压是2.5V基准电压+波动),运放会放大这个由磁场变化所导致的传感器的输出信号的波动吧 。。
昨天我就调节的这两个电位器(全是裸露在外边的。。。。),电压变化连续,也不太灵敏,貌似转了10几圈才从0.8V转到2.5v 。。
还有一个地方不太明白,就是如何根据error来判断通电的顺序,Pid1.flag = Pid1.power > 0; 就是这里了,由于昨天弄得很仓促,线接的一团糟。。。这个地方要考虑线圈的接法 和 线圈与 L298N的接法 吧??如果发现磁铁往左偏,经过程序运算后,我还把磁铁往左推。。。。。。。
没时间了 上课去了。。
感谢动力哥早上的指导!!!
你把线圈两线头对调,就倒相啦.
嗯 是啊!
如果悬浮不起来,有可能是这个原因,可以把线圈两头对调 ,再尝试一下。
是啊,同学,你都已经发现反相了,换个线头,或者在程序里面把变量来个 a=!a 不就搞定了:D
老顽童,,请教一个问题哈
我把LM358 的正相电压调到了2.5V 发现这个芯片的2个输出 1和7脚 电压始终在3.8V。而且调节正相的电位器 几乎是没有变化。。是不是就可以确定这个芯片坏掉了。。
两个正相都在2.5V.
两个负相也要上2.5V.
输出才会是2.5V.
用的负反馈接法 闭环增益50。
但是无论如何电阻 为啥运放的值就不变呢?
正相在2.5V.
负相也要在2.5V. 输入才为零.
输出才不会被50倍把小误差放大到饱和区. 才可能也在2.5V附近.
没错,需要看到你的电路示意图才能分析
不然只能猜测
没见到图,就不具体.
口述的会各说各的,想不到一起去.
变动电阻时,要看电阻处在什么地方.
如能大幅变动电压的. 输出就应该有反应.
如果仅仅只是变动阻值,也许回路阻抗很大. 这点变动没反应也正常.
还有就是要控制好闭环增益.(多级时,尽量小环,不要大环).
在够用的条件下,放大量尽量取低点.比如100倍以下.
要不然,开环增益太高,容易自激,
量到的就是一乱七八糟,和莫明奇妙的信息,会把分析引入岐途.
额 换了一个LM358 莫名奇妙的好了。。
老顽童,问一下哈 ,有没有这样的器件啊。。有两个输出口,当输入电压高于某个值时2个输出均为高,当输入电压低于某个值时输出电压均为低,当输入电压在这两者之间时一个输出高 一个输出低。。。
这种器件组合一下就可以吧,把输入分成两股,然后用两个比较器,一个high,一个low
各自输出各自的不就好了嘛
嗯 是的 谢谢~~~~帮同学问的。
还不知道有没有现成的三电平器件, 有市场需求的话,应该也不难生产.
只知道近些年在DC变换中,开始流行三电平变换器,很巧妙的,适用于高电压,大功率场合.
把一个方波分割成2个,分2次切换,减轻了对开关管的应力. 除了赞叹外,本人还没有实践过. 人类,真的是创意无穷.
嗯 创意无穷,我还在一个网上看到别人用电子元器件做的各种动物造型。。真的很有趣。
运放是放大交流信号啊。?怎么成直流放大器了?
就是特意来纠正你的.
运放是正宗的,专门的直流放大器.
运放是直流放大器.
好像找到一点原因了 我一旦打开实验室的直流稳压电源 霍尔的输出变化很大。难道实验室的直流稳压源对霍尔有影响?
如果是这样的话,可能是你的直流稳压电源容量不够,初始电流太大的时候撑不住
对霍尔的影响可能是“副产品”
进一步实验排查发现 没那么简单。。应该不是直流稳压源的影响 而是线圈们的影响。。因为用一个9V电池接在线圈两端 发现霍尔输出变化了。。。
应该和霍尔的位置有关。
但是洞洞板这个东西,霍尔器件不太好调整位置啊。。要调整就只能调整线圈的位置了。。
对,安装霍尔有注意事项的,平面一定要竖直,另外高度上尽量接近线圈高度的中心
即使这样,也只是尽量减少线圈对霍尔的影响而已,肯定多少有一点磁通量的
嗯 是的啊 最近一直在调试 发现霍尔的安装要很精确。。。
就算感觉调的很竖直了,给线圈通上9V电压,再测一下readvalue 发现还是变话了40多。。。
40多可以接受了,反正可以用adjust调节的
两个电位器当然不是同时调,readValue调到500左右,以后就再也不动了
adjust连到外面,以后用这个调
现在真的发现和每次做实验 就算与运放相连的电位器不变 但是arduino读出来的readvalue变化 每次实验都不一样 而且变化比较大。。有时候是300多 有时候500多。。
另外问一下 调整adjustvalue 怎么调???
您说的是调整到浮子平衡为止,但是调到哪能平衡呢 总不能一个一个值去试吧。。
adjustValue就是一个大电位器,一共就一圈,拧一下就知道了
一般来说,我的那个磁悬浮隔一段时间以后,放上去就不能平衡了
这时候用手大概扶一下,电位器拧一圈,你能明显感觉到手上不吃劲,那就是到平衡位置了
嗯 有两个电位器啊。。同时调???
还有就是 与线圈相连的L298的接线方向要不要特别注意的??万一通电时候产生一个 通电的方向反了 也完蛋了 。。。
线圈一定要同级性对接,不然的话这个悬浮永远也成功不了
跟298n的连接倒是关系不大
嗯 是同极性对接的 连接的时候测过。。
邪恶的眼神啊,我开始扫了一眼,以为是个关于同性恋的垃圾评论
话说北航还是有不少同性恋的。。
看来你是业内人士啊,这都知道
还有。。。
参数应该怎么调 ,,,我现在把浮子放上去能感到很快的抖动了。。是程序的参数出问题了,还是其他的????崩溃了。
小盆友,以我的经验看,浮子抖动就是快成功了!
先恭喜一下,基本上应该就是参数的问题了。
咱们的磁铁,线圈,浮子,霍尔位置都不一样,参数可能会差比较多,多试试吧
浮子还是往下面的那个大磁铁那里飞!!!!
就是我把浮子往旁边推一点,试一试线圈的斥力,看能不能把它推回来。。结果线圈好像对浮子只有抖动似的。。浮子一下就飞到大磁铁上去了。。
我把PWM输出上限调到1023了 才有感觉 。。线圈不给力啊。。
线圈不给力就加电压,我用的20V的,哈哈
震动感很强 但是老震飞 把浮子放到中间地方也给震到旁边去了。。。是不是PID设置参数的问题 。。那这个参数应该咋样设置啊。。
还有,您那个坐标图里边的红点是啥?黑点是target吧?
参数….慢慢试吧,没啥好办法
红点和黑点分别是readValue1和readValue2,它们震荡的中心位置分别是各自的target
当把浮子放上去的时候 你的readvalue好像变化不大啊 我的是直接快要变到两个极限值了。。
你的电源电压是多少?
线圈铜丝直径?线圈电阻多少?
感觉真的是线圈不给力
今天弄好了 电流变大了 3A多。。。线圈的磁力还是蛮大的。。再就是控制上的问题了 。。。
我可不是“业内”,只是看见厕所上有很多XXXX
有一个概念必须明确,运放就是专门的直流放大器.
这一点,可以去找书本核实.也可以剖析内部电原理.
········
整个磁悬浮电路中,就没有交流, 只有被换向的直流. 顶多是被PWM的直流.
如何分辨出是交流,还是被换向的直流呢?
交流总是会表现出有周期的特征.那怕是变周期的.
直流的按需换向就难有周期特征. 那怕是出现了机械振动的表象.
关键是看频率当家,还是位移作主.
哦 是的。。我隐隐约约记起来了老师说的话。。。。看来我得好好补习基础知识了。。
看来确实是专业科班出身 :)
不过我觉得PWM可以认为是一个稳定的直流叠加一个交流分量
老顽童说的周期特征来区分交流直流,我感觉不太合理
PWM的周期性就非常明显
怎么就是不稳定呢不稳定呢。。。调啊调啊 调得我心都碎了。。。。
怎么这磁悬浮就不能给个面子呢。。??
轻易成功的东西就不好玩了,对吧?
PWM是直流脉动,只变占空比不变方向,顶多算脉动周期,
还是直流性质 ,何来交流呢?
霍尔指导换向,不是周期指导换向,
所以,换向了,也不是交流.
比如,交流感应电机是频率主宰旋转.属交流电机.
永磁无刷电机由霍尔指导换向,尽管流向都变了,
却不是交流电机.因为这换向只和位移有关,与频率无关.
我明白你的意思,呵呵,必须是周期性+电流换向才是交流
我以前学力学的时候,做过波的叠加和分解
所以习惯性的把PWM这种直流脉冲分解为一个平均的直流分量,叠加一个交流分量
当然我这种观点在电学专业上看可能太不专业了,主要是术语用的不精确
受教了,多谢:)
不是啊. 咱现在真正计较的是,在黄二的那类电路上,就是无法捉到稳定的波形. 就是因为它根本就没有周期.
不似你那个5V的PWM,尽管只是脉动,总还能见到,对吧.
那么老头他们那时在讨论的频率,应该就只是自激了.
digitalWrite(i1Pin, Pid1.flag);
digitalWrite(i2Pin, !Pid1.flag);
analogWrite(power1Pin, Pid1.power);
这几行是控制线圈电流方向的吗? 我怎么看不没明白呢 就像之前小电机实验里的这几行
boolean buttonPressed = digitalRead(buttonPin);
//设置转动方向,I1和I2值相反时,分别对应两种不同的转向;I1和 I2值相同时停止转动
digitalWrite(i1Pin, buttonPressed);
digitalWrite(i2Pin, !buttonPressed);
我的意思是 比如一组水平放置的线圈 陀螺在旋转过程中水平向左偏移了 那么就应该控制左边的线圈产生斥力 此时右边的是吸引力 把它牵引像平衡位置 这是如何通过这几行代码实现的呢 我弄不明白了 。
另外 是不是说 陀螺偏移的越大 传感器感应电压就越大 放大后传入单片机的电压就大 就应该控制输出pwm增大线圈中的电流? 也就是说除了给线圈供电的20v及其相应的电流外 EA端口收到的pwm信号会增大线圈中的电流?
我有点乱啊。。。
哈,你一点都没乱,最后一段说的全部正确
L298N你可以理解为一个放大器,EA=0的时候,线圈两端电压也是0,可以用万用表量一下检验。
输出PWM的时候,线圈两端的电压是方波,算平均电压的话就是在变化了
拜托你给我讲一下 控制线圈电流方向的那几个代码 我不明白他们是怎么控制的 就像我上面问到的问题 难道线圈中的电流是不断交替变化的吗 这样岂不是很不稳定。。
你把思路搞错了吧?
线圈里的电流就是不断交替变换的,不断变化的磁场才能维持动态平衡。
对 我思路错了 晕。。
这个算法没有看懂啊,囧。没有学过PID算法,不知道有没有参考书籍推荐呢,老男孩大神 T T,先谢谢。
这个好像没有参考书,都是网上的文章一篇一篇的,拿出骗mm的决心,死缠烂打,其实很快就看明白了
诶,我想的MM都不理我了,现在专心搞专业的说
话说
—————————————————————
TCCR0B = 0×01; // Timer 0: PWM 5 & 6 @ 16 kHz
TCCR1B = 0×01; // Timer 1: PWM 9 & 10 @ 32 kHz
TCCR2B = 0×01; // Timer 2: PWM 3 & 11 @ 32 kHz
—————————————————————
这段设置的是什么呢,看不懂……原本板子今天可以拿到的,但是因为某些原因和快递错失了,失望ing
这位同学,mm比专业重要,赶紧回去泡妞!
btw:这段的作用是加快PWM的频率,看这里:http://www.diy-robots.com/?p=852
如果生命中出现过那个人,那别人就只能是将就。一直都是不将就自己走过来的,其他mm什么的一点兴趣都没有啊,和专业比起来她们都弱爆了。还真是很羡慕老男孩和圈圈妈啊。
原来老男孩筒子还有其他关于这个开发板的博文的呀,我还以为都在小爱的那个项目里哩。虽然还是看不懂,但是会努力看懂的。话说在成功弄出来之前我想都会打搅到老男孩筒子诶,由于是菜鸟希望老男孩筒子可以体谅一下哈!
跨越时空的陈年狗粮
跨越时空。现在看来十年前房价还是相对友好啊,大家业余时间还都有心思鼓捣这些娱乐。现在也就在校生还能有闲情逸致搞这些玩,大批人都忙着赚钱养家去了。
那个“Arduino系列教程之 – PWM的秘密(下)”,我猜我大概是看懂了大部分吧,但是还是没有看懂
—————————————————————
TCCR0B = 0×01; // Timer 0: PWM 5 & 6 @ 16 kHz
TCCR1B = 0×01; // Timer 1: PWM 9 & 10 @ 32 kHz
TCCR2B = 0×01; // Timer 2: PWM 3 & 11 @ 32 kHz
—————————————————————
这个诶。教程上说TCCRnB是用来设置时钟的计数位数的,上面的程序上看,难道它们都是8位的吗。
不过貌似加快PWM频率的设置就只有这一段吧?这段设置完后下面的程序都不是关于PWM频率设置的是吧,吧?
今天特意把程序打印了出来一条条研究了,程序方面还是有那么一些多地方不太懂诶,或许要先从整个磁悬浮的是怎么运行入手开始理解吧。
1、看了攻略和上面的评论,整个装置通上电后通过电位器先将接运放的传感器的输出调节为2.5V,然后再放浮子上去。霍尔传感器感应的气势是浮子的磁通吗?然后通过传感器的输出变化反应浮子的倾斜程度?(错了请指正呀,感谢的说。)
今天在图书馆居然被我找到一本关于PID控制器的书,对照了一下上面的符号和程序上的符号,大概理解了一些之前不懂的变量的意义,但是程序上还是有地方不懂,希望老男孩筒子指导一下吧。
2、一开始的端口设置里,int rotatePin=3,rotatePin这个变量貌似一直都没有用过吧(只在上面程序注释里看见出现过)……
3、Kp是比例系数,Kd是微分系数,这个程序采用的是增进式PID?那么setKd,和setKp这些系数都是实验慢慢调试出来的吗?如果我做的有些部件(磁铁的大小之类的)的和老男孩筒子列表里的有出入,那么这些值都要自己找了?
4、程序第82行,if(debug) tick=0;
这里debug不是设定为false吗?后面也貌似没有看见有更改过这个值,那么这一句实质上是永远不会运行的吧?
5、程序第87行,if(tick2>=2;
这个是右移两位的意思吗?就是相当于除以4了,这个的意义何在呢?
7、程序144行,if(debug)下面的括起来的真的会运行吗?
8、程序第162行,delay(32000)
32000这个其实不用纠结的吧?但是总觉得很特殊的样子,为什么是这个设置……
9、程序第131行,Pid1.target = min(755, min(adjustValue1 + offset, Pid1.target));
755这个值是什么样来的呢?不是很明白的样子……
我知道老男孩筒子有工作平时也比较忙的,可能问题有些繁琐,会让人觉得烦,希望老男孩筒子有心情的时候指导一下吧。这里万分感谢了。
又看了遍程序,发现第6个问题的原因是因为上面有一个for语句连续读了4次电位器的值,然后这里右移两位是为了取平均值的原因吧?
我想请问,你加地两个电位器干嘛用的?
我想骂人。。。。
电位器是调节传感器标准电压用的,比如调节到2.5V,那么传感器数据就在2.5V为起点波动
又看了遍程序,发现第6个问题的原因是因为上面有一个for语句连续读了4次传感器的值,然后这里右移两位是为了取平均值的原因吧?
额,之前那个问题也问错了,程序的PID应该是位置型的……
不过按照那个位置型PID的公式,貌似下面的这段就有点不解了
——————————————————
error = readValue1 – Pid1.target;
v = error – Pid1.preError;
Pid1.v = (Pid1.v * 6 + v) / 7;
Pid1.power = (int)error * Pid1.Kd + Pid1.v * Pid1.Kp;
——————————————————
按照公式,这里应该是
Pid1.power =Pid1.Kd*v+Pid1.Kp*(int)error
不是吗?
那个,又有了一个新问题。仔细看了一下程序
第87行
———————————————–
if(tick2<50) {tick = 0;return;}
————————————————
按照我学的C语言的理解(只是入门级别,可能有错),这里有一个return语句,就是执行到这个return的话就会跳出函数体了,而这里正在执行的函数式loop函数,也就是说执行到这里,就跳出loop函数不往下执行了,按照开发板的运作,loop这个函数又会被从头开始执行。而程序的113行和119行也有一个return语句……
其实我想问的是,按我的理解这段if(tick==500)这段程序是用来检测端口的值用的……其实特意弄tick和tick2这两个变量以及return语句这样来检测端口的用途是什么呢……这段有些弄不懂意图……
wlreg 我这几天也在做这个陀螺 我的qq是397133023 如果你在北京就太好了 咱们当面谈谈 动力哥经常不在 我电路搭好了 最严重的是 我怎么测的不带陀螺的时候 传感器输出是2.57v啊 这么大 而通过放大器后的电压竟然不随磁场变化而变化 而且保持3.8v左右。。。。
晕死
传感器输出2.57V很正常,你需要把电位器的输出也调节到2.57V附近,就可以发现放大器后的电压有变化了。不然的话,这东西放大很多倍,稍微差一点就到最大电压了。
我调了一下电位器 现在上电后在不放转子的情况下 从358出来的电压大小是0.05左右,两个都是 我是直接用万用表测的 放上浮子后变化范围是从0.xx到3.xx 总之没超过过4v 然后转子放上面总是飞出去 也有震动 但是线圈没多久就变得很烫 我就得断电 如果再继续 恐怕就着火了 。。。。 各种无语中 我的转子就是四个小钕铁硼 两小块加上两个大一点的薄片形的 上面还粘着个一元硬币。。
这个页面帖子太长了,我早上发了一个集中回答的页面,你们可以在那里讨论,然后我把讨论结果统一添到页面里。
你量过线圈的电阻吗?感觉特别烫的话,可能是铜丝比较粗吧?
我的电路还在搭呢,主要是有些材料还没有到……导线、电位器和电阻什么的本来想在实验室拿的,但是还没有拿到手…………
我是非常新手的新手 主要就是这段代码的有些地方看不懂 还说问问你呢 你赶紧加我qq吧 十万火急啊 呵呵
QQ等我回宿舍才行。
问一下,你20V电源方面是怎样解决的呀?我发现L298N的接20V电源的接口是那个标注VCC的吧。那种接口的20V电源可以买到么
我是塞了一根电线在电源中心的孔里,然后缠了一段在外面的插头上,最后用黑胶布捆好,土法挺管用。
呵呵 我是买的20v 3.25A的电源 本来说把那个接头剪掉劈成两半的 后来看到卖电源的地方都有那样的接头的(就跟arduino开发板那个9v电源一样的接头) 用线接上就可以了 正极vcc 负极接GND 咱们去新开的帖子讨论吧 这个太长。。。
ok 悬浮成功
赞一个,呵呵,你实现的速度真快,年轻人果然战斗力超强
求交流呀。我想和你对一下每一个步骤。估计星期二电路就能搭好了。
請問這PID的原理可應用在四軸飛行器上嗎??
应该可以
origin串口分析具体使用谁会,各位推荐个靠谱的教程也行。
做磁悬浮分析分析,东西都买齐了,连板子选的都是和oldboy一样的,做电机实验L208一不小心烧坏了,现在在路上,你要为我负责啊!!我可被你骗上道了。。
关于积分调节,我的理解是这样的:
还拿小球在光滑坡面上为例,你认为积分项修正在坡面运动时才需要用到,而我觉得是这样的:
物理平衡位置是x=L,如果我现在就像让小球平衡在x=L处。首先,微分调节我们是没有争议的;比例调节这里也没有争议,如果x>L则施加向左的力,如果x<L则施加向右的力,x=L则仅仅根据当前速度进行调节(微分调节);积分调节貌似确实没用。
但如果我想要的平衡位置不是x=L处,那么在静止平衡时显然也是有一个恒力作用在小球上的,这个力不是比例调节带来的(Δx=0),也不是微分调节带来的(v=0),这是一个恒定的偏移量,如果平衡位置是x=L则这个偏移量恰好是0。我感觉这个偏移量是由积分调节积累出来的。
我看你在程序代码中也没有用到积分调节,那么当你想让悬浮物悬浮在非物理平衡位置时,实际平衡位置应该更远离物理平衡位置。因为当物体恰好处于设定的平衡位置时,比例调节为0,如果速度也为0的话线圈就不工作,而此时又不是在物理平衡位置,所以物体要在更远离物理平衡位置处达到平衡。
这是我对积分调节的理解,所谓消除静差(稳态误差)应该指的就是控制量的恒定的偏差吧?
在大神面前说话要小心啊,要是不小心错了也不要笑我啊~嘻嘻
哈,我仔细阅读并理解了这一段文字,确实是正确无误的!
赞,总结的真好!不敢称大神啊,我要多向大家学习
你好,我想问问代码中:
int power1Pin = 5; //连接电机驱动板的EA接口
int power2Pin = 6; //连接电机驱动板的EB接口
int rotatePin = 3; //用来控制磁场旋转的PMW接口
在原理图当中EA和EB不是接了+5V了吗?另外PWM口又是哪个呢?
EA和EB是接得信号端。。
rotate是本来设想的一种方案,让磁场旋转来诱导浮子旋转,后来发现没有效果,这段代码是无效的
你好,我的硬件都做好了,开始调试PID参数。打算从Kp开始调起,Kd为0。我用手放松地拿着磁浮放在正中间感受,请问当Kp接近合适的范围是磁浮应该是什么样地表现?
我从0.1开始试,刚开始的时候磁浮要很靠近电磁铁才会感受到斥力。我就把Kp直接增加到8,磁浮在平衡位置就能感受到两边一定的拉扯力,并且手拿着磁浮开始被吸引的摇晃。然后我以0.1为增量一路加到20,磁铁在平衡位置能感受到比较强的力,但是随之Kp增大,我手拿着磁浮开始越来越大幅度地摇晃,并不像我想象中那样,当Kp接近合适值时磁铁会被控制在平衡位置并比较高频地震动。到目前为止,我的磁浮一放上去立马就飞。
所以你现在只调节了 Kp 对吧?只有Kp的话,就会像你说的那样,左右的抖动,而且幅度会越来越大。这个是对的,你可以开始加上一些Kd,Kd偏小的时候表现就是震荡,Kd偏大的时候表现是无法稳定,从侧面滑走。
震荡的时候就是接近成功了,加油!
那请问调Kp的时候调到什么程度可以着手开始调Kd呢?目前为止我说的抖动都是在我轻轻拿着磁浮的时候才会发生,如果我只是把磁浮往平衡位置一放,磁浮只会一下就飞到边上去了,没有看到有任何先震动然后幅度增大失去平衡的过程。我比较困惑的是不知道现在Kp是太大了还是太小了。有可能是太小了控制不住磁浮一下飞出去,也有可能是太大了一下过激了飞出去了。请问动力哥当时在调试的时候是怎么确定Kp是过大了还是过小了?非常感谢
成功了!原来是我为了调试写的几行serial.print严重拖慢了arduino的频率,删了以后直接就好了!不过感谢动力哥的文章和解答
恭喜恭喜!
9600波特率下,发一个字节好像正好是1ms,果然很慢啊
以后就有经验了
另外,我有个请求,能否把你做的磁悬浮整理一下照片,发到创酷网上? http://www.chuangkoo.com
这是我和几个朋友一起做的创客平台,希望许许多多和咱们一样的爱动手的人,有个交流分享的地方。
我希望做成中国的instructables,同时也是硬科技范儿的果壳
动力老男孩,您好!我最近也在尝试做磁悬浮,遇到了两个问题想跟大师您请教一下,谢谢了!
1)两个方向的hall元件平衡的target值是不是一样的?设置为多少合适呢?
2)要间隔多少时间进行一次PID调整呢?目前我设置的时间是大概5ms读取一次hall元件的值,然后根据当前的偏移方向进行PID调整,这个时间是否合适呢?您当时是多长时间调整一次呢?
如果安装的垂直的话,target应该一样,但是一般手动装不了那么准,会有一点儿误差。至于霍尔值是多少,跟你的磁铁有关,每个人都不一样
5ms测量一次够用的,每秒钟调节200次呢
老男孩,谢谢您及时回复,我目前将两个方向的hall元件输入到mcu的值通过电位器调整到2v左右,然后将target值就设置为2v,这样可以吗?接着去调Kp和Kd的参数。当kd为零时,调整kp,发现当值差不多是4的时候,刚放上浮子就会剧烈摆动,然后为了解决剧烈摆动的问题,我开始从0.1调整Kd,每次步进0.1,发现浮子会慢慢由剧烈摆动变为剧烈抖动,当调整到1.2时,基本上不会抖动了,但是浮子仍然会飞出去。我再加大kd的值,如果直接将其设置为30就会感觉到浮子在剧烈的抖动,然后就会飞出去。我想要知道kd设置到1.2时和30两种情况时,哪一种才是接近悬浮的感觉?再次表示感谢,谢谢!
你试试kd用1.2,把Kp降一点儿,到3左右
老男孩,您好!现在已经可以悬浮2s左右,但是2s后,浮子就会抖动然后被拉飞到环形磁铁上,这种情况下,需要调整Kp还是Kd?另外我发现虽然能悬浮但是电流很大,如何降低电流呢?谢谢了!
这种情况下,两个参数都需要微调。PID是个头疼的事情,最后还是需要费点儿劲尝试。
听说有自动匹配PID的办法,但是我还不会。
电流大的话,把上方的磁铁换大一点儿,也就是说浮子的重力主要由磁铁来承担,就可以减少耗电。
最完美的状态应该是线圈可以支持双向电流(可以吸也可以排斥),浮子的平衡位置基本在磁铁和重力的平衡点,那样的话基本不费电
谢谢动力老男孩的指点,可不可以这样理解,电流比较大主要还是找的平衡点并不是最优的平衡点,如果保持浮子不变,我可以尝试去重新调整平衡目标值,尽量让电磁铁只是去平衡水平位置,而不承担在垂直方向对浮子产生的力,即在垂直方向只让永磁铁产生的力等于浮子的重力。
没错!
用串口我可以把数据传到电脑,但是你那个分析的图片是怎么做的呢
我用的是一个叫 Origin的软件,根据坐标点来生成图片
图里面由黑色的点线和红色的点线得出什么结论?需要定的目标值?不太明白啊~
还有串口输出的数据,你是自己一个一个写进去制图的吗,Origin软件已经下了~
老男孩还在么,我有问题要请教你