首先可以去看正点原子给的
这里面对他的飞控的基本原理如控制算法等做了介绍。
感觉他们就弄了个最基本的姿态环加上一个高度环,就完了,其实也没什么复杂的对吧,都没什么速度环,位置环,不过加了光流模块应该是有位置环的我觉得。
不过我看1.3版本的飞控代码里面是有位置控制和速度控制的,位置控制包含XYZ三个方向的位置控制
在position_pid.c这个文件里
#include <math.h>
#include "pid.h"
#include "commander.h"
#include "config_param.h"
#include "position_pid.h"
#include "remoter_ctrl.h"
#include "maths.h"
/********************************************************************************
* 本程序只供学习使用,未经作者许可,不得用于其它任何用途
* ALIENTEK MiniFly
* 位置PID控制代码
* 正点原子@ALIENTEK
* 技术论坛:www.openedv.com
* 创建日期:2017/5/12
* 版本:V1.3
* 版权所有,盗版必究。
* Copyright(C) 广州市星翼电子科技有限公司 2014-2024
* All rights reserved
*
* 修改说明:
* 版本V1.3 水平定点PID输出较大,所以在位置环输出设置0.1的系数,
速率环输出设置0.15系数,从而增加PID的可调性。
********************************************************************************/
#define THRUST_BASE (20000) /*基础油门值*/
#define PIDVX_OUTPUT_LIMIT 120.0f //ROLL限幅 (单位°带0.15的系数)
#define PIDVY_OUTPUT_LIMIT 120.0f //PITCH限幅 (单位°带0.15的系数)
#define PIDVZ_OUTPUT_LIMIT (40000) /*PID VZ限幅*/
#define PIDX_OUTPUT_LIMIT 1200.0f //X轴速度限幅(单位cm/s 带0.1的系数)
#define PIDY_OUTPUT_LIMIT 1200.0f //Y轴速度限幅(单位cm/s 带0.1的系数)
#define PIDZ_OUTPUT_LIMIT 120.0f //Z轴速度限幅(单位cm/s)
static float thrustLpf = THRUST_BASE; /*油门低通*/
PidObject pidVX;
PidObject pidVY;
PidObject pidVZ;
PidObject pidX;
PidObject pidY;
PidObject pidZ;
void positionControlInit(float velocityPidDt, float posPidDt)
{
pidInit(&pidVX, 0, configParam.pidPos.vx, velocityPidDt); /*vx PID初始化*/
pidInit(&pidVY, 0, configParam.pidPos.vy, velocityPidDt); /*vy PID初始化*/
pidInit(&pidVZ, 0, configParam.pidPos.vz, velocityPidDt); /*vz PID初始化*/
pidSetOutputLimit(&pidVX, PIDVX_OUTPUT_LIMIT); /* 输出限幅 */
pidSetOutputLimit(&pidVY, PIDVY_OUTPUT_LIMIT); /* 输出限幅 */
pidSetOutputLimit(&pidVZ, PIDVZ_OUTPUT_LIMIT); /* 输出限幅 */
pidInit(&pidX, 0, configParam.pidPos.x, posPidDt); /*x PID初始化*/
pidInit(&pidY, 0, configParam.pidPos.y, posPidDt); /*y PID初始化*/
pidInit(&pidZ, 0, configParam.pidPos.z, posPidDt); /*z PID初始化*/
pidSetOutputLimit(&pidX, PIDX_OUTPUT_LIMIT); /* 输出限幅 */
pidSetOutputLimit(&pidY, PIDY_OUTPUT_LIMIT); /* 输出限幅 */
pidSetOutputLimit(&pidZ, PIDZ_OUTPUT_LIMIT); /* 输出限幅 */
}
static void velocityController(float* thrust, attitude_t *attitude, setpoint_t *setpoint, const state_t *state) //maxi:这就是速度控制,说明有速度环
{
static u16 altholdCount = 0;
// Roll and Pitch
attitude->pitch = 0.15f * pidUpdate(&pidVX, setpoint->velocity.x - state->velocity.x); //maxi:说明速度环的输出给了角度环,等号右边很明显就是期望值减去测量值嘛!!!
attitude->roll = 0.15f * pidUpdate(&pidVY, setpoint->velocity.y - state->velocity.y);
// Thrust
float thrustRaw = pidUpdate(&pidVZ, setpoint->velocity.z - state->velocity.z);
*thrust = constrainf(thrustRaw + THRUST_BASE, 1000, 60000); /*油门限幅*/
thrustLpf += (*thrust - thrustLpf) * 0.003f;
if(getCommanderKeyFlight()) /*定高飞行状态*/
{
if(fabs(state->acc.z) < 35.f)
{
altholdCount++;
if(altholdCount > 1000)
{
altholdCount = 0;
if(fabs(configParam.thrustBase - thrustLpf) > 1000.f) /*更新基础油门值*/
configParam.thrustBase = thrustLpf;
}
}else
{
altholdCount = 0;
}
}else if(getCommanderKeyland() == false) /*降落完成,油门清零*/
{
*thrust = 0;
}
}
void positionController(float* thrust, attitude_t *attitude, setpoint_t *setpoint, const state_t *state, float dt)
{
if (setpoint->mode.x == modeAbs || setpoint->mode.y == modeAbs)
{
setpoint->velocity.x = 0.1f * pidUpdate(&pidX, setpoint->position.x - state->position.x); // maxi:说明位置环的输出给了速度环
setpoint->velocity.y = 0.1f * pidUpdate(&pidY, setpoint->position.y - state->position.y);
}
if (setpoint->mode.z == modeAbs)
{
setpoint->velocity.z = pidUpdate(&pidZ, setpoint->position.z - state->position.z);
}
velocityController(thrust, attitude, setpoint, state);
}
/*获取定高油门值*/
float getAltholdThrust(void)
{
return thrustLpf;
}
void positionResetAllPID(void)
{
pidReset(&pidVX);
pidReset(&pidVY);
pidReset(&pidVZ);
pidReset(&pidX);
pidReset(&pidY);
pidReset(&pidZ);
}
void positionPIDwriteToConfigParam(void)
{
configParam.pidPos.vx.kp = pidVX.kp;
configParam.pidPos.vx.ki = pidVX.ki;
configParam.pidPos.vx.kd = pidVX.kd;
configParam.pidPos.vy.kp = pidVY.kp;
configParam.pidPos.vy.ki = pidVY.ki;
configParam.pidPos.vy.kd = pidVY.kd;
configParam.pidPos.vz.kp = pidVZ.kp;
configParam.pidPos.vz.ki = pidVZ.ki;
configParam.pidPos.vz.kd = pidVZ.kd;
configParam.pidPos.x.kp = pidX.kp;
configParam.pidPos.x.ki = pidX.ki;
configParam.pidPos.x.kd = pidX.kd;
configParam.pidPos.y.kp = pidY.kp;
configParam.pidPos.y.ki = pidY.ki;
configParam.pidPos.y.kd = pidY.kd;
configParam.pidPos.z.kp = pidZ.kp;
configParam.pidPos.z.ki = pidZ.ki;
configParam.pidPos.z.kd = pidZ.kd;
}
下面是attitude_pid.c
#include <stdbool.h>
#include "pid.h"
#include "sensors.h"
#include "attitude_pid.h"
/********************************************************************************
* 本程序只供学习使用,未经作者许可,不得用于其它任何用途
* ALIENTEK MiniFly
* 姿态PID控制代码
* 正点原子@ALIENTEK
* 技术论坛:www.openedv.com
* 创建日期:2017/5/12
* 版本:V1.3
* 版权所有,盗版必究。
* Copyright(C) 广州市星翼电子科技有限公司 2014-2024
* All rights reserved
*
* 修改说明:
* 版本V1.3 纠正角度环和角速度环积分时间参数错误的bug。
********************************************************************************/
/*角度环积分限幅*/
#define PID_ANGLE_ROLL_INTEGRATION_LIMIT 30.0
#define PID_ANGLE_PITCH_INTEGRATION_LIMIT 30.0
#define PID_ANGLE_YAW_INTEGRATION_LIMIT 180.0
/*角速度环积分限幅*/
#define PID_RATE_ROLL_INTEGRATION_LIMIT 500.0
#define PID_RATE_PITCH_INTEGRATION_LIMIT 500.0
#define PID_RATE_YAW_INTEGRATION_LIMIT 50.0
PidObject pidAngleRoll;
PidObject pidAnglePitch;
PidObject pidAngleYaw;
PidObject pidRateRoll;
PidObject pidRatePitch;
PidObject pidRateYaw;
static inline int16_t pidOutLimit(float in)
{
if (in > INT16_MAX)
return INT16_MAX;
else if (in < -INT16_MAX)
return -INT16_MAX;
else
return (int16_t)in;
}
void attitudeControlInit(float ratePidDt, float anglePidDt)
{
pidInit(&pidAngleRoll, 0, configParam.pidAngle.roll, anglePidDt); /*roll 角度PID初始化*/
pidInit(&pidAnglePitch, 0, configParam.pidAngle.pitch, anglePidDt); /*pitch 角度PID初始化*/
pidInit(&pidAngleYaw, 0, configParam.pidAngle.yaw, anglePidDt); /*yaw 角度PID初始化*/
pidSetIntegralLimit(&pidAngleRoll, PID_ANGLE_ROLL_INTEGRATION_LIMIT); /*roll 角度积分限幅设置*/
pidSetIntegralLimit(&pidAnglePitch, PID_ANGLE_PITCH_INTEGRATION_LIMIT); /*pitch 角度积分限幅设置*/
pidSetIntegralLimit(&pidAngleYaw, PID_ANGLE_YAW_INTEGRATION_LIMIT); /*yaw 角度积分限幅设置*/
pidInit(&pidRateRoll, 0, configParam.pidRate.roll, ratePidDt); /*roll 角速度PID初始化*/
pidInit(&pidRatePitch, 0, configParam.pidRate.pitch, ratePidDt); /*pitch 角速度PID初始化*/
pidInit(&pidRateYaw, 0, configParam.pidRate.yaw, ratePidDt); /*yaw 角速度PID初始化*/
pidSetIntegralLimit(&pidRateRoll, PID_RATE_ROLL_INTEGRATION_LIMIT); /*roll 角速度积分限幅设置*/
pidSetIntegralLimit(&pidRatePitch, PID_RATE_PITCH_INTEGRATION_LIMIT); /*pitch 角速度积分限幅设置*/
pidSetIntegralLimit(&pidRateYaw, PID_RATE_YAW_INTEGRATION_LIMIT); /*yaw 角速度积分限幅设置*/
}
bool attitudeControlTest()
{
return true;
}
void attitudeRatePID(Axis3f *actualRate,attitude_t *desiredRate,control_t *output) /* 角速度环PID */
{
output->roll = pidOutLimit(pidUpdate(&pidRateRoll, desiredRate->roll - actualRate->x));
output->pitch = pidOutLimit(pidUpdate(&pidRatePitch, desiredRate->pitch - actualRate->y));
output->yaw = pidOutLimit(pidUpdate(&pidRateYaw, desiredRate->yaw - actualRate->z));
}
void attitudeAnglePID(attitude_t *actualAngle,attitude_t *desiredAngle,attitude_t *outDesiredRate) /* 角度环PID */
{
outDesiredRate->roll = pidUpdate(&pidAngleRoll, desiredAngle->roll - actualAngle->roll); //maxi:这成功地说明了外环的输出就内环的输入也就是内环的期望值。
outDesiredRate->pitch = pidUpdate(&pidAnglePitch, desiredAngle->pitch - actualAngle->pitch);
float yawError = desiredAngle->yaw - actualAngle->yaw ;
if (yawError > 180.0f)
yawError -= 360.0f;
else if (yawError < -180.0)
yawError += 360.0f;
outDesiredRate->yaw = pidUpdate(&pidAngleYaw, yawError);
}
void attitudeControllerResetRollAttitudePID(void)
{
pidReset(&pidAngleRoll);
}
void attitudeControllerResetPitchAttitudePID(void)
{
pidReset(&pidAnglePitch);
}
void attitudeResetAllPID(void) /*复位PID*/
{
pidReset(&pidAngleRoll);
pidReset(&pidAnglePitch);
pidReset(&pidAngleYaw);
pidReset(&pidRateRoll);
pidReset(&pidRatePitch);
pidReset(&pidRateYaw);
}
void attitudePIDwriteToConfigParam(void)
{
configParam.pidAngle.roll.kp = pidAngleRoll.kp;
configParam.pidAngle.roll.ki = pidAngleRoll.ki;
configParam.pidAngle.roll.kd = pidAngleRoll.kd;
configParam.pidAngle.pitch.kp = pidAnglePitch.kp;
configParam.pidAngle.pitch.ki = pidAnglePitch.ki;
configParam.pidAngle.pitch.kd = pidAnglePitch.kd;
configParam.pidAngle.yaw.kp = pidAngleYaw.kp;
configParam.pidAngle.yaw.ki = pidAngleYaw.ki;
configParam.pidAngle.yaw.kd = pidAngleYaw.kd;
configParam.pidRate.roll.kp = pidRateRoll.kp;
configParam.pidRate.roll.ki = pidRateRoll.ki;
configParam.pidRate.roll.kd = pidRateRoll.kd;
configParam.pidRate.pitch.kp = pidRatePitch.kp;
configParam.pidRate.pitch.ki = pidRatePitch.ki;
configParam.pidRate.pitch.kd = pidRatePitch.kd;
configParam.pidRate.yaw.kp = pidRateYaw.kp;
configParam.pidRate.yaw.ki = pidRateYaw.ki;
configParam.pidRate.yaw.kd = pidRateYaw.kd;
}
我现在发现正点原子也是四环串级,也就是 角速度环+角度环+速度环+位置环!!!!!!和无名的一样了那就。
每一个外环的输出就是内环的期望值,这在它的代码里面体现得很明显了。
你去读position_pid.c和attitude_pid.c就可以发现,前面包含速度环和位置环,后面包含角速度环和角度环。
这么串起来的话内外环的频率如何。
还有内外环频率不一样的话数据如何保持同步,比较外环的输入是内环的期望。
不过本身他们传感器的更新速率就不一样啊,气压计更新速率应该是没有三轴加速度传感器那么快的,那么自然也就导致外环速率应该没有内环速率那么高啊。
这种小型飞控的源码就清晰明了许多。