pwm调光伤眼,都自己做了,何不做纯直流?
背景:
之前虎哥发过一篇文章,关于大幅提高室内照明亮度的设想 - 科创 (XXXXXXXXXXXX)。闲来无事测得书房打开台灯桌面的亮度不过300lux,可以说是昏暗了,看起书来费眼睛,遂萌发出自己搞个台灯,提升下桌面的亮度,使其稳定在一个令人舒适的值。
主要用到的材料:
stm32vct6开发板,电源,led灯带,手机懒人支架(夹持led,当做灯臂),铝散热座(废弃主板拆下),散热风扇,一堆导线,stm32开发板,BH1750光照传感器模块,L298N驱动模块,电源转接板等。
台灯制作:
把led灯带粘到铝散热座上,灯带正负极用导线连好。焊接技术一般般,散热太快了,锡难融化。本来想先粘到塑料膜上焊接完再挪过去的,发现塑料膜会糊掉,只能在散热座上强行焊接了(不知同志们对于这种情况有没有什么好方法?)。最后用手机支架(原计划3d打印个支架的,后来突然想到可以用手机支架做灯臂,够长(30cm-150cm都有),夹得也够稳)把整个灯头夹住。如下图所示(凌乱的线【笑哭】)
L298N驱动模块的接线:
因为驱动电压是24V所以必须使用外部5V供电,否则会烧坏芯片,拔掉跳线帽,5V端口接5V,还要注意要共地,不然可能会出bug。
BH1750接线:
按照模块上面标识的字符接线就行。SCL接PB6,SDA接PB7,ADDR接GND。
PID控制:
在过程控制中,按偏差的比例(P)、积分(I)和微分(D)进行控制的PID控制器(亦称PID调节器)是应用最为广泛的一种自动控制器。它具有原理简单,易于实现,适用面广,控制参数相互独立,参数的选定比较简单等优点;而且在理论上可以证明,对于过程控制的典型对象──“一阶滞后+纯滞后”与“二阶滞后+纯滞后”的控制对象,PID控制器是一种最优控制。PID调节规律是连续系统动态品质校正的一种有效方法,它的参数整定方式简便,结构改变灵活(PI、PD、…)[1]。总而言之,PID控制算法是一种相对简单易用的控制算法。
pid算法的公式:u(k)=Kp*error +∑Ki*error +Kd*[error-last_error]
这个公式我们可以转换成下面的几条式子。
pvalue = Kp*error; //(这里有点奇怪,不知为什么英文字体调不了大小,只能加粗了)
ivalue +=Ki*error; //(这个+=很关键,当时我想了一段时间才想出来)
dvalue = (error-last_error)*Kd;
pwmvalue += (int)(Kpvalue+ivalue+dvalue); //(这里用+=是为了符合实际情况)
error显然就是设定值和当前值之间的差(set_value-now_value)。
我们直接以实际例子来解释这三个参数的作用。设定台灯的亮度为1000lux。下面我用我的理解来分别解释参数P,I,D的作用。
参数P也称为比例常数。下图只有参数p起作用(ki=0,kd=0)时的图(如没有特殊说明,下文图表的纵轴代表亮度(单位:lux),横轴代表时间(单位:20ms),没有对ivalue进行限幅):
在kp=0.005时亮度永远也无法到1000lux,这是因为pwmvalue 是int类型的值,而pvalue 是浮点型的值,当error过小时即pvalue小于1时,于取整为0,pwmvalue就无法再增大。
所以,我们需要把Kp调大,随着kp的增大,亮度变为1000lux的时间越短,但是,如果kp过大,系统便会震荡。
如下图(kp=5,ki=0,kd=0),可以看出系统刚开始的时候震荡很剧烈。
当然,台灯如果亮度变化过快,感觉不舒服,我个人觉得kp=0.1时的体验比较好。这里就有个问题了,明明Kp(取0.05-1之间的值)就能很好解决台灯亮度的问题,还要其他两个参数干嘛。其实在我的这个pid台灯里面确实只用Kp就能解决问题了,系统的稳态误差可以忽略不计(影响很小),毕竟亮度提升太快肉眼也不舒服,亮度提升太慢体验也不好,不需要用(可以不用)到I,D这两个参数。当初申请基金的时候,还没有开始搞STM32,也没有接触PID,导致存在立项失误,这里要道个歉。
下面我们来看看ivalue += Ki*error;ki也称为积分时间常数。当kp过小(如kp=0.005,ki=0,kd=0)时,需要不断积分(ki=0.000001),最终使得对pwmvalue增大,趋于光强为1000lux的pwm值。如下图,蓝色线(Kp=0.005,Ki=0.000001,Kd=0)橙色线(Kp=0.005,Ki=0,Kd=0)。
ivalue会使系统更快达到所需的值,但会使系统震荡。在1000lux附近波动,最终趋于1000lux。Ki越大,波动越剧烈,最后趋于1000lux(稳定)的时间也越久。如图,ki越大,系统震荡越剧烈,稳定所需的时间越长,蓝线(Kp=0.1,Ki=0.1,Kd=0),橙色线(Kp=0.1,Ki=0.01,Kd=0)。
我们有两个办法能使系统震荡减弱,一个是积分限幅,另一个是微分抑制。我们先来说说积分限幅,如下图中橙色线(Kp=0.1,Ki=0.1,Kd=0)震荡很剧烈,在系统开始运行时,ivalue不断变大使得曲线十分陡峭,到达了设定值之后,由于ivalue是累加的,没有办法立刻等于0,所以pwmvalue仍然在不断增加,如下图,增加到1700lux附近才下降,然后就反复震荡,最终趋于设定值下图。我们可以对ivalue进行限幅,让ivalue只能在一个固定的范围内变动,如下图蓝线(Kp=0.1,Ki=0.1,Kd=0,ivalue限幅±100)。
限幅代码:
#define imax 100 //限幅
#define imin -100 //限幅
if(ivalue>imax) ivalue=imax; //如果ivalue>imax,使ivalue=imax
if(ivalue<imin) ivalue=imin; //如果ivalue<imin,使ivalue=imin
在对ivalue限幅之后,系统震荡明显减弱,如下图蓝线。
Kd是时间微分常数,用于减缓pwmvalue的增速(阻尼),当亮度不断增加趋于设定亮度时,error(t-1)>error(t),dvalue = (error-last_error)*Kd,式子中括号里面的项就是负值,乘上Kd微分时间常数,得到dvalue,dvalue能使pwmvalue的变化更平缓。如下图橙色线(kp=0.1,ki=0.1,kd=0)蓝色线(kp=0.1,ki=0.1,kd=1)
但是,当pwmvalue的增速很快(亮度不断增加并趋于设定亮度)时,|error-last_error|会很大导致|dvalue|也很大,如果Kd也偏大,显然在系统刚开始运行时,会震荡(pvalue+ivalue+dvalue<0,使得pwmvalue值变小,以至于亮度突然上升后突然下降,对外表现为闪烁,顿挫感,亮度变化不缓和),如下图(kp=0.1,ki=0,kd=4)。
最后我们应该把这个pid运算放在程序的中断里面(固定周期执行一次就行),假如放在while循环,pwmvalue 的值增速极快(每while一次,只要暂时没有读取到新的光照强度的新值(20ms读取一次)pvalue,dvalue 不变,ivalue快速增大(或许可以通过调小Kp,Ki,Kd(实测不太行,要调的很小,很难调节)来解决这个问题,毕竟while循环也算是一个周期)导致pwmvalue也快速增加,最后导致系统震荡)
蓝牙控制:
使用CH-08蓝牙模块,手机连接上蓝牙模块,发送所需的亮度就能自动调节,不需要每次调整亮度都要重新烧录。也可以做到无线开灯,无线关灯的效果。
整个pid调光台灯的全貌如下图:
程序:
结语:
感谢kc基金的支持,感谢kc论坛。在制作这个台灯的时候,遇到了不少困难,感谢同志们提出的建议,不过我觉得这个项目并没有真正完成(或许这个帖子还存在一些技术性的问题),还能加入更多的功能。希望这个帖子能给后面的同志们一点帮助。今后我还会继续完善这个项目,如果有问题和建议欢迎在下面留言。
[1] 刘教瑜,舒军主编;甘月红,谢长君副主编.单片机原理及应用(第2版):武汉理工大学出版社,2014.08
[修改于 3个月9天前 - 2024/09/14 09:34:03]
请教个有点儿低级的问题,没太看明白。。。。这里用 PID 来调光主要目的是啥?PID 相比于直接按设定光强和实测光强的差值做个线性或非线性的单调调光有啥特别的优点么?
楼主可以用加热台(或者酒精灯)来预热铝基板,注意控制好温度,这样会好焊些。
jlc可以免费打样铝基板PCB,可以试试。这样焊线,看着就累,也比较丑。还有,松香要用洗板水洗掉。
电路里面地的相互连接问题好好注意,我现在是被这个教训乖了,以前在这上面栽好几次。
华为台灯也有亮度反馈控制,哪天拆开看看(不过怕被打)。
请教个有点儿低级的问题,没太看明白。。。。这里用 PID 来调光主要目的是啥?PID 相比于直接按设...
在实际应用中使用设定光强和实测光强的差值做个非线性调光确实是个直接的开环控制方式,但在为了学习PID为驱使的项目中这确实是个很好的项目,两者最直接的就是开环控制和闭环控制的区别,至于评论区说到扫描的方式在该项目的实际应用中完全是一个很方便的控制方法,但使用PID的控制可以在控制过程中达到快速收敛作用,也比扫描方式会更高级
200字以内,仅用于支线交流,主线讨论请采用回复功能。