赞
踩
小飞机由于飞手的技术和外部环境因素(刮风等)导致飞机飞行不稳定。
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)))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。