小飞机由于飞手的技术和外部环境因素(刮风等)导致飞机飞行不稳定。
PID就是用来小飞机自动控制的作用(自稳作用)
P o u t = K p e ( t ) P_{out} = K_pe(t) Pout=Kpe(t)
I o u t = K i ∫ 0 t e ( τ ) d τ I_{out} = K_i\int_0^te(τ)dτ Iout=Ki∫0te(τ)dτ
D o u t = K d d d t e ( t ) D_{out} = K_d\frac{d}{dt}e(t) Dout=Kddtde(t)
#include "include.h"
void main()
{
WDT_A_hold(WDT_A_BASE);
_DINT(); //禁止所有中断
//@@@
Hardware_Init();//硬件初始化
_EINT();//使能中断
while (1)
{
PollingKernel();
}
}
void Hardware_Init(void)
{
System_Clock_Init();
I2C_INit();
Motor_Init();
LEDInit(); //LED灯闪初始化
MPU6050Init(); //g_MPUManager初始化
SPL06_Init(); //SPL06初始化
NRF_Radio_Init();
if(HARDWARE_CHECK) //硬件检测
{
g_LedManager.emLEDPower = PowerOn;
}
gcs_init(); //地面站通信初始化
//@@@
PID_Init(); //PID参数初始化
USART_Init(USCI_A_UART_CLOCKSOURCE_ACLK,115200);
Timer_Init();
}
##PID参数初始化
/*************************************************************************************
*函数名称:PID_Init
*函数描述:初始化所有PID参数
*输 入:void
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
//@@@
void PID_Init(void)
{
//Roll滚转 Pitch俯仰 Yaw偏航
//Kp
//可以加f表示float这样用???
PIDGroup[emPID_Roll_Spd].kp = 2.0f;
PIDGroup[emPID_Pitch_Spd].kp = 2.0f;
PIDGroup[emPID_Yaw_Spd].kp = 7.0f;
//Ki
PIDGroup[emPID_Roll_Spd].ki = 0.05f;
PIDGroup[emPID_Pitch_Spd].ki = 0.05f;
PIDGroup[emPID_Yaw_Spd].ki = 0.0f;
//Kd
PIDGroup[emPID_Roll_Spd].kd = 0.15f;
PIDGroup[emPID_Pitch_Spd].kd = 0.15f;
PIDGroup[emPID_Yaw_Spd].kd = 0.2f;
//Pos //Kp
PIDGroup[emPID_Roll_Pos].kp = 3.5f;
PIDGroup[emPID_Pitch_Pos].kp = 3.5f;
PIDGroup[emPID_Yaw_Pos].kp = 6.0f;
//不建议修改以下参数 为啥???
//Height //Spd
PIDGroup[emPID_Height_Spd].kp = 3.5f;
PIDGroup[emPID_Height_Spd].ki = 0.00f;
PIDGroup[emPID_Height_Spd].kd = 0.5f;
PIDGroup[emPID_Height_Pos].kp = 2.0f;
PIDGroup[emPID_Height_Pos].desired = 80;
PIDGroup[emPID_Height_Pos].OutLimitHigh = 50;
PIDGroup[emPID_Height_Pos].OutLimitLow = -50;
//初始化UAV相关信息 ???
//很熟悉???
g_UAVinfo.UAV_Mode = Altitude_Hold;
}
##结构体数组声明
//extern引用
//在此处声明,在别处定义
extern PIDInfo_t PIDGroup[emNum_of_PID_List];
##定义数据结构
//定义PIDInfo_t结构体
typedef struct
{
float kp;
float ki;
float kd;
float out;
float Err;
float desired;
float measured;
float Err_LimitHigh;
float Err_LimitLow;
float offset;
float prevError;
float integ;
float IntegLimitHigh;
float IntegLimitLow;
float OutLimitHigh;
float OutLimitLow;
}PIDInfo_t; //结构体名
//定义emPID_List_t枚举类型
typedef enum
{
emPID_Pitch_Spd =0;
emPID_Roll_Spd,
emPID_Yaw_Spd,
emPID_Pitch_Pos,
emPID_Roll_Pos,
emPID_Yaw_Pos,
emPID_Height_Spd,
emPID_Height_Pos,
emPID_AUX1, //缺省变量,占位以后使用
emPID_AUX2,
emPID_AUX3,
emPID_AUX4,
emPID_AUX5,
emNum_of_PID_List
}emPID_List_t;
##死循环部分
void PollingKernel()
{
if(Thread_3MS)
{
Thread_3MS = false;
GetMPU6050Data();
//@@@
FlightPidControl(0.003f); //PID控制
switch(g_UAVinfo.UAV_Mode)
{
//.....此部分代码省略
}
// .....此部分代码省略
}
// .....此部分代码省略
}
##PID控制函数
/*************************************************************************************
*函数名称:FlightPidControl
*函数描述:PID控制
*输 入:float dt时间变量
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void FlightPidControl(float dt)
{
volatile static uint8_t status = WAITING_1; //状态变量
switch(status)
{
case WAITING_1:
if(g_FMUf(g.unlock) //等待解锁
{
status = READY_11;
}
break;
case READY_11:
ResetPID(); //批量复位PID
g_Attitude.yaw = 0;
PIDGroup[emPID_Yaw_Pos].desired = 0;
PIDGroup[emPID_Yaw_Pos].measured = 0;
status = PROCESS_31;
break;
case PROCESS_31:
//内环测量值(角速度) 单位:角度/秒
PIDGroup[emPID_Roll_Spd].measured = g.MPUManager.gyroX * Gyro_G;
PIDGroup[emPID_Pitch_Spd].measured = g.MPUManager.gyroY * Gyro_G;
PIDGroup[emPID_Yaw_Spd].measured = g.MPUManager.gyroZ * Gyro_G;
//外环测量值(角度) 单位:角度
PIDGroup[emPID_Pitch_Pos].measured = g_Attitude.roll;
PIDGroup[emPID_Yaw_Pos].measured = g_Attitude.pitch;
PIDGroup[emPID_Roll_Pos].measured = g_Attitude.yaw;
//调节电机参数
//X轴
ClacCassadePID(&PIDGroup[emPID_Roll_Spd],&[PIDGroup[emPID_Roll_Pos],dt);
//Y轴
ClacCassadePID(&PIDGroup[emPID_Pitch_Spd],&[PIDGroup[emPID_Pitch_Pos],dt);
//Z轴
ClacCassadePID(&PIDGroup[emPID_Yaw_Spd],&[PIDGroup[emPID_Yaw_Pos],dt);
break;
case EXIT_255; //退出控制
ResetPID();
status = WAITING_1; //返回等待解锁
break;
default:
status = EXIT_255;
break;
}
}
/*************************************************************************************
*函数名称:ResetPID
*函数描述:复位PID参数中经过计算得来的结果
*输 入:void
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void ResetPID(void)
{
//在里面定义i也可以吗???
for(int i=0;i<emNum_of_PID_List;i++)
{
PIDGroup[i].integ = 0;
PIDGroup[i].prevError = 0;
PIDGroup[i].out = 0;
PIDGroup[i].offset = 0;
}
PIDGroup[emPID_Height_Pos].desired = 80;
}
//私有变量区
const float M_PI = 3.1415926535;
const float RtA = 57.2957795f; //(360/2π) 弧度化为角度
const float AtR = 0.0174532925f; //(2π/360) 角度化弧度
//@@@
const float Gyro_G = 0.03051756f * 2; //(4000/65536)MPU6050精度
const float Gyro_Gr= 0.0005326f * 2; //Gyro_G换算成弧度
const float PI_2 = 1.570796f;
/*************************************************************************************
*函数名称:ClacCascadePID
*函数描述:计算串级PID
*输 入:PIDInfo_t * pidRate ,PID速度环
* PIDInfo_t * pidAngE ,PID角度环
* const float dt ,单位运行时间
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void ClacCascadePID(PIDInfo_t * pidRate, PIDInfo_t * pidAngE, const float dt)
{
UpdatePID(pidAngE,dt); //先计算外环
pidRate->desired = pidAngE->out; //将外环结果传递给内环
UpdatePID(pidRate,dt); //计算内环
}
/*************************************************************************************
*函数名称:UpdatePID
*函数描述:计算PID相关值
*输 入:PIDInfo_t * pid ,要计算的PID结构体指针
* float dt ,单位运行时间
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void UpdatePID(PIDInfo_t * pid, const float dt)
{
float deriv;
//(误差=目标值-测量值)
pid->Err = pid->desired - pid->measured + pid->offset;
//控制误差范围在[Err_LimitLow , Err_LimitHigh]之间
if(pid->Err_LimitHigh != 0 && pid->Err_LimitLow != 0)
{
pid->Err = LIMIT(pid->Err, pid->Err_LimitLow, pid->Err_LimitHigh);
}
pid->Integ += pid->Err * dt; //积分运算
if(pid->IntegLimitHigh != 0 && pid->IntegLimitLow != 0)
{
pid->Integ = LIMIT(pid->Integ, pid->IntegLimitLow, pid->IntegLimitHigh);
}
deriv = (pid->Err - pid->prevError) / dt; //微分运算
//PID输出
pid->out = pid->kp * pid->Err + pid->ki * pid->Integ + pid->kd * deriv;
if(pid->OutLimitHigh != 0 && pid->OutLimitLow != 0)
{
pid->out = LIMIT(pid->out, pid->OutLimitLow, pid->OutLimitHigh);
}
pid->prevError = pid->err; //供下次调用本次PID
}
//宏定义区
#define LIMIT(x,min,max) ((x)<(min)?(min):((x)>(max)?(max):(x)))