OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6029|回复: 10

Destiny小型四旋翼飞行器——PID串级调试

[复制链接]

5

主题

78

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
370
金钱
370
注册时间
2016-5-7
在线时间
63 小时
发表于 2016-8-27 19:21:25 | 显示全部楼层 |阅读模式
   《Destiny小型四旋翼飞行器》是一个连载帖,连载本帖有几个目的,其一是想和大家相互学习、相互交流,得到更快的提升;其二是帮助比本人更新的新手,本人遇到的一些常见的问题都会在这里说明,让大家少走弯路;其三,给自己一点坚持的动力,把发帖当成一种习惯而引导自己学习。不矫情了,进入正题。
             今天的内容是平衡PID的调试,其实这些内容是上个礼拜抽时间搞的,但是这个礼拜一直很忙,进度就停了。首先说明,本人水平有限,能用来搞小四轴的时间也很少,因此没有去深入研究捷联惯导算法,直接用MPU6050的DMP输出欧拉角。

    一开始尝试的是单级角度环PID,如果不去管什么死区,平衡的时候期望角度(roll和pitch)应该是0度,偏差即实际测量角度的负数,微分是两次偏差的差值(没有用陀螺仪的值当微分部分)。刚开始只给了P,从小到大,寻找各种资料里面所说的等幅震荡,然而并没有毛用,P太小了几乎没有效果,P稍微大一点就会越荡越嗨,感觉形成了正反馈。随意的加入D,也是从小到大,所谓的抑制和预测的效果也没有体现出来,然后翻了很多资料,看到有人说只有角度环时,角度为期望,系统调节至角度为0的时候角速度的存在会导致机体继续偏转,产生震荡。然后才有所顿悟,上了串级PID,下文是串级PID的介绍。
    PID公式使用的是位置式的,代码也完全按照公式写的,只是加了角度/角速度限幅和积分限幅(参考了烈火狂龙的PID调节部分)。以下是位置式PID的数学公式:
                  u(k) = Kp * e(k) + Ki * ∑e(i) + Kd * [e(k) - e(k-1)]
以下是PID代码部分:

[mw_shl_code=c,true]void Angle_PID()
{
        //Roll
        ANGLE_ERROR.Roll = 0 - Angle_Euler.Roll;//
        if(ANGLE_ERROR.Roll >  Angle_Max)        //ROLL
                ANGLE_ERROR_INTE.Roll +=  Angle_Max;
        if(ANGLE_ERROR.Roll < -Angle_Max)
                ANGLE_ERROR_INTE.Roll += -Angle_Max;
        else
                ANGLE_ERROR_INTE.Roll += ANGLE_ERROR.Roll;
        if(ANGLE_ERROR_INTE.Roll >  Angle_Inte_Max)//积分限幅
           ANGLE_ERROR_INTE.Roll =  Angle_Inte_Max;
        if(ANGLE_ERROR_INTE.Roll < -Angle_Inte_Max)
           ANGLE_ERROR_INTE.Roll = -Angle_Inte_Max;
        ANGLE_ERROR_DIFF.Roll = ANGLE_ERROR.Roll - ANGLE_ERROR_LAST.Roll;//e(k-1)
        Roll_PID.Pout = Roll_PID.P * ANGLE_ERROR.Roll;      //roll PID
        Roll_PID.Iout = Roll_PID.I * ANGLE_ERROR_INTE.Roll;
        Roll_PID.Dout = Roll_PID.D * ANGLE_ERROR_DIFF.Roll;        
        Roll_PID.ALLout = Roll_PID.Pout + Roll_PID.Iout + Roll_PID.Dout;      //roll OUT
        ANGLE_ERROR_LAST.Roll = ANGLE_ERROR.Roll;//
        
        //Pitch
        ANGLE_ERROR.Pitch = 0 - Angle_Euler.Pitch;//
        if(ANGLE_ERROR.Pitch >  Angle_Max)        //Pitch
                ANGLE_ERROR_INTE.Pitch +=  Angle_Max;
        if(ANGLE_ERROR.Pitch < -Angle_Max)
                ANGLE_ERROR_INTE.Pitch += -Angle_Max;
        else
                ANGLE_ERROR_INTE.Pitch += ANGLE_ERROR.Pitch;
        if(ANGLE_ERROR_INTE.Pitch >  Angle_Inte_Max)//积分限幅
           ANGLE_ERROR_INTE.Pitch =  Angle_Inte_Max;
        if(ANGLE_ERROR_INTE.Pitch < -Angle_Inte_Max)
           ANGLE_ERROR_INTE.Pitch = -Angle_Inte_Max;
        ANGLE_ERROR_DIFF.Pitch = ANGLE_ERROR.Pitch - ANGLE_ERROR_LAST.Pitch;//e(k-1)
        Pitch_PID.Pout = Pitch_PID.P * ANGLE_ERROR.Pitch;      //pitch PID
        Pitch_PID.Iout = Pitch_PID.I * ANGLE_ERROR_INTE.Pitch;
        Pitch_PID.Dout = Pitch_PID.D * ANGLE_ERROR_DIFF.Pitch;        
        Pitch_PID.ALLout = Pitch_PID.Pout + Pitch_PID.Iout + Pitch_PID.Dout;      //pitch OUT
        ANGLE_ERROR_LAST.Pitch = ANGLE_ERROR.Pitch;//
}[/mw_shl_code]
[mw_shl_code=c,true]void Gyro_PID()
{
        //Roll
        GYRO_ERROR.X = Roll_PID.ALLout - GYRO_XYZ.X * Radian_to_Angle;        
        if(GYRO_ERROR.X >  Gyro_Max)        //ROLL
                GYRO_ERROR_INTE.X +=  Gyro_Max;
        if(GYRO_ERROR.X < -Gyro_Max)
                GYRO_ERROR_INTE.X += -Gyro_Max;
        else
                GYRO_ERROR_INTE.X += GYRO_ERROR.X;
        if(GYRO_ERROR_INTE.X >  Gyro_Inte_Max)//积分限幅
           GYRO_ERROR_INTE.X =  Gyro_Inte_Max;
        if(GYRO_ERROR_INTE.X < -Gyro_Inte_Max)
           GYRO_ERROR_INTE.X = -Gyro_Inte_Max;        
        GYRO_ERROR_DIFF.X = GYRO_ERROR.X - GYRO_ERROR_LAST.X;//e(k-1)        
        Gyro_X_PID.Pout = Gyro_X_PID.P * GYRO_ERROR.X;      //PID
        Gyro_X_PID.Iout = Gyro_X_PID.I * GYRO_ERROR_INTE.X;
        Gyro_X_PID.Dout = Gyro_X_PID.D * GYRO_ERROR_DIFF.X;        
        Gyro_X_PID.ALLout = Gyro_X_PID.Pout + Gyro_X_PID.Iout + Gyro_X_PID.Dout;      //OUT        
        GYRO_ERROR_LAST.X = GYRO_ERROR.X;//
        
        //Pitch
        GYRO_ERROR.Y = Pitch_PID.ALLout - GYRO_XYZ.Y * Radian_to_Angle;        
        if(GYRO_ERROR.Y >  Gyro_Max)        //ROLL
                GYRO_ERROR_INTE.Y +=  Gyro_Max;
        if(GYRO_ERROR.Y < -Gyro_Max)
                GYRO_ERROR_INTE.Y += -Gyro_Max;
        else
                GYRO_ERROR_INTE.Y += GYRO_ERROR.Y;
        if(GYRO_ERROR_INTE.Y >  Gyro_Inte_Max)//积分限幅
           GYRO_ERROR_INTE.Y =  Gyro_Inte_Max;
        if(GYRO_ERROR_INTE.Y < -Gyro_Inte_Max)
           GYRO_ERROR_INTE.Y = -Gyro_Inte_Max;        
        GYRO_ERROR_DIFF.Y = GYRO_ERROR.Y - GYRO_ERROR_LAST.Y;//e(k-1)        
        Gyro_Y_PID.Pout = Gyro_Y_PID.P * GYRO_ERROR.Y;      //PID
        Gyro_Y_PID.Iout = Gyro_Y_PID.I * GYRO_ERROR_INTE.Y;
        Gyro_Y_PID.Dout = Gyro_Y_PID.D * GYRO_ERROR_DIFF.Y;        
        Gyro_Y_PID.ALLout = Gyro_Y_PID.Pout + Gyro_Y_PID.Iout + Gyro_Y_PID.Dout;      //OUT        
        GYRO_ERROR_LAST.Y = GYRO_ERROR.Y;//
}[/mw_shl_code]
以下是GYRO滑动滤波:
[mw_shl_code=c,true]void Gyro_Filter(S16_XYZ *Gyro_in,S16_XYZ *Gyro_out)
{
        static int16_t Filter_x[Filter_Num],Filter_y[Filter_Num],Filter_z[Filter_Num];
        static uint8_t Filter_count;
        int32_t Filter_sum_x=0,Filter_sum_y=0,Filter_sum_z=0;
        uint8_t i=0;
        
        Filter_x[Filter_count] = Gyro_in->X;
        Filter_y[Filter_count] = Gyro_in->Y;
        Filter_z[Filter_count] = Gyro_in->Z;

        for(i=0;i<Filter_Num;i++)
        {
                Filter_sum_x += Filter_x;
               
Filter_sum_y += Filter_y;
               
Filter_sum_z += Filter_z;
        }        
        
        Gyro_out->X = Filter_sum_x / Filter_Num;
        Gyro_out->Y = Filter_sum_y / Filter_Num;
        Gyro_out->Z = Filter_sum_z / Filter_Num;
        
        Filter_count++;
        if(Filter_count == Filter_Num)
                Filter_count=0;
}[/mw_shl_code]

    看了很多帖子,按照别人成功的思路开始,先调角速度内环,给了P参数之后,晃动机体有抑制力,不过不强,然后逐渐增大到一定值,感觉抑制力足够强的时候,发现角速度环并不能调整角度在某个值,此时角度外环参数均为0,由于重力的原因,机体会不断倾斜。于是开始加入内环的D,从小开始加,并没有看到别人调试的时候遇到的波形,但是机体是有一些变化,可是看不出规律。于是继续增大。。。在增加到某个值的时候,机体瞬间就平稳多了,这种突然来临的效果还是不由得有些小兴奋。继续增大D,发现效果会变差,又换回了状态最好的那组参数,然后去晃动机体,发现每次都能回中,可惜回复速度很慢,感觉应该受限于外环的P,于是开始调整角度环的P,发现这个参数的确能加快回中的速度,调整了几个之后感觉恢复速度够快了,就没有继续增大,怕超调了再次引起震荡。但是机体总感觉不想别人调试的那么连续,感觉是陀螺仪数据不稳的结果,因此加入了滑动滤波,对陀螺仪的输出值进行平滑处理,发现略有效果。目前暂时就干了这些,遥控器的代码还没有开始码,最近很忙,估计会拖到9月10号以后了。以下是“烤四轴”的效果,调试杆是用竹筷子削的,没有用万向节,因为生锈了(阻力有些大)!

    在测试的过程中出现了一个奇怪的问题,机体加入roll和pitch之后相对比较稳定,但是会突然180°翻转,出现这种问题这是加速自杀啊!DMP输出的角度(roll和Pitch)范围是±180°,暂时没有找到突然侧翻的原因,也没去监测DMP输出的角度是否有异常,如果有调过的小伙伴遇到同样的问题请给个解决方法,也请路过的大神指点一下。
    如果有进度,会在论坛里更新或发帖,但是由于个人原因,能用来做这个的时间很少,所以更新时间不定!有问题大家可以联系我,会在晚上(一般会很晚)回复,以下是个人的联系方式。
QQ:1170513392








正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

20

帖子

0

精华

初级会员

Rank: 2

积分
119
金钱
119
注册时间
2016-7-5
在线时间
24 小时
发表于 2016-8-27 20:31:46 | 显示全部楼层
楼主,能不能做一期关于6050的?关于它的数据分析,处理
回复 支持 反对

使用道具 举报

13

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
399
金钱
399
注册时间
2016-5-25
在线时间
101 小时
发表于 2016-9-10 13:20:20 | 显示全部楼层
你用的DMP,你的控制周期是多久?
回复 支持 反对

使用道具 举报

5

主题

78

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
370
金钱
370
注册时间
2016-5-7
在线时间
63 小时
 楼主| 发表于 2016-9-10 14:15:20 | 显示全部楼层
小爱1314 发表于 2016-8-27 20:31
楼主,能不能做一期关于6050的?关于它的数据分析,处理

个人水平有限,6050分析的就不搞了,最近忙着换工作,都没时间玩四轴了
回复 支持 反对

使用道具 举报

5

主题

78

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
370
金钱
370
注册时间
2016-5-7
在线时间
63 小时
 楼主| 发表于 2016-9-10 14:16:36 | 显示全部楼层
王轩 发表于 2016-9-10 13:20
你用的DMP,你的控制周期是多久?

好像是4ms,回去确认一下回复你,最近事多,记不住了
回复 支持 反对

使用道具 举报

13

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
399
金钱
399
注册时间
2016-5-25
在线时间
101 小时
发表于 2016-9-10 16:50:03 | 显示全部楼层
destiny、 发表于 2016-9-10 14:16
好像是4ms,回去确认一下回复你,最近事多,记不住了

没事儿    我也是用的DMP   周期是5ms
回复 支持 反对

使用道具 举报

3

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2016-6-17
在线时间
23 小时
发表于 2016-10-12 11:42:26 | 显示全部楼层
有点不太了解
GYRO_ERROR.X = Roll_PID.ALLout - GYRO_XYZ.X * Radian_to_Angle;&#160;
外环输出减去角速度吗?
Radian_to_Angle这里是什么变量
回复 支持 反对

使用道具 举报

0

主题

13

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2016-10-16
在线时间
7 小时
发表于 2016-10-29 23:08:46 | 显示全部楼层
pitch的角度范围是+-90吧?
是不是?
回复 支持 反对

使用道具 举报

23

主题

54

帖子

0

精华

初级会员

Rank: 2

积分
179
金钱
179
注册时间
2015-5-25
在线时间
7 小时
发表于 2016-12-4 14:59:12 | 显示全部楼层
楼主,我问一下,你只加内环pd能不能让它保持在一个角度?
回复 支持 反对

使用道具 举报

7

主题

61

帖子

0

精华

高级会员

Rank: 4

积分
577
金钱
577
注册时间
2016-3-1
在线时间
76 小时
发表于 2016-12-15 23:28:05 | 显示全部楼层
楼主,你这个Roll_PID.ALLout 和 Gyro_X_PID.ALLout是直接就施加到电机上吗?
回复 支持 反对

使用道具 举报

0

主题

6

帖子

0

精华

新手上路

积分
36
金钱
36
注册时间
2017-7-3
在线时间
11 小时
发表于 2017-7-10 17:44:00 | 显示全部楼层
一起讨论下怎么查看匿名上位机的波形来调节PID
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 04:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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