电赛练习之旋转倒立摆PID调节[通俗易懂]

电赛练习之旋转倒立摆PID调节[通俗易懂]前言:在家准备电赛控制题,第一个选择的旋转倒立摆,结构和电路相对简单,对于新手比较友好。本人今年大二,自学的STM32和PID算法,本文算是对这个题目练习的记录吧,文章和程序有误的地方还请大家多多指教。一、机械结构考虑到正式比赛时需要自己搭建机械结构,我就没有直接购买现成的机械结构。关于机械结构还是平时接触太少了,随便在淘宝上买的不锈钢打孔支架作摆臂和旋转臂,最后发现传感器没法安放,强行用电机支架和胶带固定住。最困难的是怎么把电机和旋转臂连接得牢靠,最开始用的一个联轴器,发现转的猛了就会松动,想尽各种办

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言:在家准备电赛控制题,第一个选择的旋转倒立摆,结构和电路相对简单,对于新手比较友好。本人今年大二,自学的STM32和PID算法,本文算是对这个题目练习的记录吧,文章和程序有误的地方还请大家多多指教。
一、基本原理(可能有误)
原理这一块没有做的太复杂,只是稍微估计了电机需要的速度值。当摆臂失去平衡后,就需要一个惯性加速度平衡重力加速度,这个惯性加速度就是电机施加的加速度。以竖直方向右偏30度为例,则平衡所需要的惯性加速度大约是5.77m/(s^2)。又根据功能关系,可估算此时摆杆重心处速度为1m/s。设定在0.5s内将摆杆恢复至竖直方向,以gsin(pi/6)来估算重力加速度分量,以asin(pi/6)来估算施加的加速度,最终算得a=6.9m/(s*s),则电机需要的速度是v=3.5m/s。又考虑到实际过程中电机不能始终在满速和停止之间来回运动,且在控制过程中要考虑到干扰的施加,那么摆杆的速度不止1m/s,这样看来至少需要旋转臂25cm情况下满速为10m/s以上的电机比较合适。

二、器件选择
1、电机采用转速530rad/min12v的JGB37-520电机,驱动选择tb6612驱动模块,传感器选择线性误差在0.1%的WDD35D4电位器。
2、这一次的缺陷就是没有加入稳压电路,这个太重要了,因为在调节PID参数的过程中,需要保持整个系统变化的只有参数值。试想一下,当我们在调节PID参数控制PWM输出时,电压不断波动,那么控制效果将随电压波动时好时坏。又比如这次我采用的是12V电池,那么每次充完电后,电压值都会比我上次调节好参数值时有变化,那么我又需要再次调节参数值,所以这个题目花费了很长时间,而且在电压波动的情况下,无论怎么改变参数值,摆臂的震动都比较大,调节效果并不是很理想。

三、机械结构
考虑到正式比赛时需要自己搭建机械结构,我就没有直接购买现成的机械结构。关于机械结构还是平时接触太少了,随便在淘宝上买的不锈钢打孔支架作摆臂和旋转臂,最后发现传感器没法安放,强行用电机支架和胶带固定住。最困难的是怎么把电机和旋转臂连接得牢靠,最开始用的一个联轴器,发现转的猛了就会松动,想尽各种办法,最后是用三个联轴器连接后才能连接得牢靠,为了增加高度,在三个基本的联轴器上又重了三个联轴器。底座用四个直角电机支架连接,这样就算来回摆动也不会引起振动。最后整个结构用钉子钉在书桌上(心疼书桌一秒),这样就算比较稳定的机械结构了。
在这里插入图片描述

四、倒立稳定实现

(一)、PID算法
PID的讲解在网上有很多专业又详细的教程,我就不再说了,这里讲一下这一个月调节PID参数后对PID参数的理解:
P值——快速接近目标值,误差越大,效果越强——容易导致超调;
I值——消除静差——提高准确性(但我没用,容易使响应过慢);
D值——消除震荡,预测误差变化——使系统趋于稳定;

(二)、角度PID
这个PID是主要的控制量,应该作为整个控制过程的主导量。代码并不复杂,我采用的是位置式PID,如下:

float angle_pid(float adc_value)
{ 
   
  static float error,pwm,error_1;
  error=middle_value-adc_value;
  pwm=error*a_p+(error-error_1)*a_d;
  error_1=error;
  return pwm;
}

如何调节PID参数,我记录一下自己调节的过程:
1、首先将D值和I值置0,单独调节P值,最开始可以设置得大一点,例如在4999为上限的PWM值下,我一般先设置P值为55~60,这时大概率系统响应过度,会造成摆臂在中值处来回剧烈震荡,这时就可以按照每次减1的速度来调节P值,直到调节到电机能快速做出反应的情况下不会造成过度的震动。我没有去具体分析P值调节下角度变化的波形,因为我的电压不稳定,不可能调节得很合适。

2、P值调节好后,摆臂应该能在中值处稳定一小段时间,之后会左右做小幅度摆动,或者朝一个方向运动,最后落下。这时需要加入D值,提前预测角度变化,消除震荡。同样,D值可以预设得很大,这时摆臂会出现低频震动,但是比单独P值调节要稳定,依次减少D值,直到摆臂能稳定在中值附件,最终朝一个方向加速运动下去并落下。这时角度环的PID参数就调好了。

(三)、位置PID
最开始很不理解这个位置环是怎么工作的,查网上资料说是串级PID,但都没有很清楚讲诉为什么需要位置环PID,这个位置环又是怎样和角度环配合的。这里结合搜集到的资料,记录一下自己的理解:
1、位置环作用本质
首先角度环PID已经能让摆臂稳定在中值附近,但是还是会朝一个方向转动下去,这是因为角度环控制的PWM值不能再纠正最后和中值的一点差值。有人会说那就加大PID参数啊,但是这样会导致超调,一点点的变化都会让摆臂剧烈摆动,最后还是落下。
解决这个问题的办法就是定期根据电机旋转的方向和距离加大PWM调节量,纠正最后一点误差。比如以电机编码器的值作为判断数据,编码器输出正值代表正转,在角度环调节的情况下,如果摆臂引导旋转臂向正方向一直转动,编码器累计值超过预设值时,就可以判断角度环没有及时纠正最后一点误差,这时就让PWM值增大速率更大,电机加速度更大,那么最后一点差值就纠正了。
而这个定期加大PWM值的作用就是所谓的位置环,有了位置环,就能把旋转臂的调节范围控制在一定范围内
2、位置环如何配合角度环
其实理解了位置环是如何作用的之后,就知道怎样去设置位置环了。至于网上说的什么角度环输出作为位置环输入我硬是没搞懂。我就按自己的想法来弄,根据定时器定时开启位置控制,比如每50ms开启一次,每次持续25ms,这样就能和角度环配合起来用了。
以上就是我的理解,代码如下:

float position_pid(void)
{ 
   
 static float bian_value,bian_error,last_bian_error,pwm,bian_last_value;
 static float bian_basic,bian_weifen;
 if(position_pd==1)//当起摆成功后刷新位置信息
 { 
   
  bian_basic=0;
  position_pd=0;
 }
 //位置环需要编码器累计值作判断
 bian_value=bian_read();//读取当前编码器值 
 bian_basic=bian_basic*0.5+bian_value;
 bian_error=bian_basic-position_value;
 bian_weifen=bian_error-last_bian_error;
 pwm=bian_basic*p_p+bian_weifen*p_d;
 last_bian_error=bian_basic;
 bian_last_value=bian_value;
 return pwm;
 
}

五、关于自动起摆
(一)、基本思路
自动起摆的过程主要分为三步。
第一步,先定时来回震荡,增大摆臂摆动幅度,直到摆臂超过水平线;
第二步,继续定时震荡,这时摆臂将有机会达到倒立稳定控制的角度范围内,一旦达到这个范围,立即单独开启角度环PID控制,由于考虑到摆臂此时速度较大,角度变化较快,应该增大D值控制,能比较好的稳定摆臂。经过对比实验,确实增大D值利于对摆臂的稳定。角度PID将持续300ms左右;
第三步,恢复预设PID参数值,开启角度环和位置环配合的PID控制,持续稳定摆臂。
(二)、中途异常掉落处理
为了能及时检测摆臂异常掉落,但是UCOSIII还没学会,我想到可以将延时控制过程分成很多次循环,每次循环延时5ms,那么每5ms就能检测一次角度值,如果出现异常,就退出循环,重新起摆。
程序如下:

void move_auto()
{ 

static int i=0,time=5,flag=0,open_contrl=0,open_angle_control=0,n=0;
static float adc_value=0,pwm;
adc_value=Get_Adc_Average(ADC_Channel_10,5);
//flag==0 未达到预定角度 不开启稳定控制 
//定时器起摆
if(flag==0) 
{ 

adc_value=Get_Adc_Average(ADC_Channel_10,5);
while((adc_value>xia_xian&&adc_value<shang_xian)!=1)
{ 

//400ms定时
for(i=0;i<80;i++)
{ 

motor(4048);
delay_ms(time);
adc_value=Get_Adc_Average(ADC_Channel_10,5);
//每5ms检测一次角度值
//如果达到预定角度
//立即开启稳定控制
if(adc_value>xia_xian&&adc_value<shang_xian) 
{ 

open_contrl=1;
open_angle_control=1;
while(open_contrl)
{ 

adc_value=Get_Adc_Average(ADC_Channel_10,5);
//判断稳定成功否 未成功则退出 继续定时起摆
if((adc_value>pan_xia_xian&&adc_value<pan_shang_xian)!=1) open_contrl=0;
//首先单独使用角度环控制
//此时需要的PID参数中 D值将要更大一些
//因为考虑到速度影响大
if(open_angle_control==1)
{ 

for(n=0;n<50;n++)
{ 

a_p=73;  
a_i=0; 
a_d=380; 
p_p=0;
p_d=0;
//同样判断摆臂是否异常落下
adc_value=Get_Adc_Average(ADC_Channel_10,5);
if((adc_value>pan_xia_xian&&adc_value<pan_shang_xian)!=1) n=100;
pwm=banlance_pid(adc_value);
motor(pwm);
delay_ms(5);
}
n=0;
open_angle_control=0;
//更改参数位稳定控制参数
a_p=56;  
a_i=0; 
a_d=100; 
p_p=2000;
p_d=500;
position_pd=1;
}
//稳定控制开启
pwm=banlance_pid(adc_value);
motor(pwm);
}
}
}
//反向定时起摆 和上一段配合摆动
for(i=0;i<80;i++)
{ 

motor(-4048);
delay_ms(time);
adc_value=Get_Adc_Average(ADC_Channel_10,5);
if(adc_value>xia_xian&&adc_value<shang_xian) 
{ 

open_contrl=1;
open_angle_control=1;
while(open_contrl)
{ 

adc_value=Get_Adc_Average(ADC_Channel_10,5);
if((adc_value>pan_xia_xian&&adc_value<pan_shang_xian)!=1) open_contrl=0;
if(open_angle_control==1)
{ 

for(n=0;n<50;n++)
{ 

a_p=73;  
a_i=0; 
a_d=380; 
p_p=0;
p_d=0;
adc_value=Get_Adc_Average(ADC_Channel_10,5);
if((adc_value>pan_xia_xian&&adc_value<pan_shang_xian)!=1) n=100;
pwm=banlance_pid(adc_value);
motor(pwm);
delay_ms(5);
}
n=0;
open_angle_control=0;
a_p=56;  
a_i=0; 
a_d=100; 
p_p=2000;
p_d=500;
position_pd=1;
}
pwm=banlance_pid(adc_value);
motor(pwm);
}
}
}
adc_value=Get_Adc_Average(ADC_Channel_10,5);
}
flag=1;
}
//当flag==1时开启稳定控制
while(flag==1)
{ 

open_angle_control=1;
adc_value=Get_Adc_Average(ADC_Channel_10,5);
if((adc_value>pan_xia_xian&&adc_value<pan_shang_xian)!=1) flag=0;
if(open_angle_control==1)
{ 

for(n=0;n<50;n++)
{ 

a_p=73;  
a_i=0; 
a_d=330; 
p_p=0;
p_d=0;
adc_value=Get_Adc_Average(ADC_Channel_10,5);
if((adc_value>pan_xia_xian&&adc_value<pan_shang_xian)!=1) n=100;
pwm=banlance_pid(adc_value);
motor(pwm);
delay_ms(5);
}
n=0;
open_angle_control=0;
a_p=56;  
a_i=0; 
a_d=100;
p_p=2000;
p_d=500;
position_pd=1;
}
pwm=banlance_pid(adc_value);
motor(pwm);
}
} 

六、抗干扰性测试
根据题目要求需要抗干扰测试。在5g砝码拉起90度后向下释放撞击摆臂上方1——2cm处时,摆臂能迅速调整,并在2s内恢复正常,在极端情况下会出现摆臂落下的情况,但都能再次自动起摆并稳定。
七、稳定时旋转一周
基本思路是定时该变位置控制的目标位置值。虽然有一点控制效果,能稳定旋转几周,最后还是变得不稳定,摆臂落下,算时勉强有点效果吧。在网上很少找到这方面的资料,还望路过的大神能赐教。
八、总结
1、控制题首先需要建立物理模型,做出运动分析,这一点我做的不够好,导致这次电机选型一开始选的转速过小,不能满足加速度需求,后来被迫重新购买电机。网上有大佬用拉格朗日方程建立物理模型,需要好好学习一下(大概率看不懂)。
2、PID参数调节一定要在其他变量都基本不变的情况下进行,尤其时电压。机械结构底盘必须够稳,不然摆臂还没稳定,就被底座的摆动摇乱了。理论分析和机械结构搭建在前期可以多花一些时间,不然后期改机械结构和重新理论分析真的太花费时间了。
3、这次加深了PID的理解,各类模块的配置过程和程序都掌握的不错,也算是为电赛打下基础了。
最后还是贴一个程序吧,供大家探讨和赐教:
链接:https://pan.baidu.com/s/1q_LFi_9Xzfan7bUUh4foRw
提取码:6804

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/171011.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • socat 使用「建议收藏」

    转原文链接:http://www.wenquan.name/?p=1158用socat试几个netcat常用的用法,对比如下:1.听tcp12345端口#nc-l127.0.0.112345#socattcp-listen:12345-2.向远处tcp12345端口发点字#echo“test”|nc127.0.0.112345#echo“t…

  • idea快捷键汇总mac_mac版本IDEA快捷键「建议收藏」

    idea快捷键汇总mac_mac版本IDEA快捷键「建议收藏」本文中的快捷键均为系统默认配置。一、mac系统键盘和符号对应关系1.Control(或Ctrl)⌃2.CapsLock⇪3.Command(或Cmd)⌘4.Option(或Alt)⌥5.Shift⇧二、mac系统自有快捷键1.command系列1).command+space切换输入法2).command+M最小化当前窗口3).command+Q关闭当前程序(…

  • JetBrick 入门详解

    JetBrick 入门详解JetBrick的简单使用方法,仅作为简单的入门,不做内部详细的探讨。

  • css3 翻转和旋转的区别

    我以前一直以为旋转跟翻转一样,今日自己旋转了好久都发觉跟翻转差一点点,纠结了十几分钟才明白,只能怪自己的立体感太差了。css3中的transform中有旋转,放缩,倾斜,平移的功能,分别对应的属性是

    2021年12月23日
  • 单片机视频教程转让

    单片机视频教程转让单片机的C语言视频教程转让,本套光盘购于天祥电子,花了我200大元,如今我以60元(包快递)的价格转让。有意者请与我联系。QQ:247964971 电话:13982129248讲座从最基本电路知识开始讲起,非常详细的讲解KEIL编译器的使用,课程全部用单片机的C语言讲解,从C语言的第一个主函数MAIN讲起,一步步讲解每一个语法,每条指令的意思,即使对单片机一巧不能,对C语言一无所知,通过

  • hdu 4964 Emmet()模拟

    hdu 4964 Emmet()模拟

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号