Files
FDR-Core/Core/Src/ladrc.c

265 lines
6.3 KiB
C
Raw Normal View History

2026-03-08 18:17:14 +08:00
#include "ladrc.h"
2026-03-18 22:03:16 +08:00
#include "f4_can_app.h"
2026-03-08 18:17:14 +08:00
2026-03-14 17:17:17 +08:00
/*
*
* 1) LADRC
* 2) -> -> LADRC -> PWM
*
*
* - RPM / getter使
*/
#define LADRC_CONTROL_DT_S 0.01f
#define LADRC_RPM_FILTER_ALPHA 0.30f
2026-03-28 00:07:15 +08:00
#define LADRC_DEFAULT_WC 20.0f
2026-03-27 23:32:15 +08:00
#define LADRC_DEFAULT_WO 25.0f
#define LADRC_DEFAULT_B0 0.40f
2026-03-14 17:17:17 +08:00
#define LADRC_DEFAULT_OUT_MAX 1000.0f
/* ================== 内部辅助函数 ================== */
static float LADRC_Abs(float x);
static float LADRC_Clamp(float x, float min_value, float max_value);
2026-03-18 22:03:16 +08:00
static void LADRC_ResetStates(LADRC_TypeDef *ladrc);
static float s_filtered_rpm[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2026-03-14 17:17:17 +08:00
static float LADRC_Abs(float x)
{
return (x >= 0.0f) ? x : -x;
}
static float LADRC_Clamp(float x, float min_value, float max_value)
{
if (x > max_value)
{
return max_value;
}
if (x < min_value)
{
return min_value;
}
return x;
}
2026-03-18 22:03:16 +08:00
static void LADRC_ResetStates(LADRC_TypeDef *ladrc)
{
if (ladrc == NULL)
{
return;
}
ladrc->v = 0.0f;
ladrc->y = 0.0f;
ladrc->z1 = 0.0f;
ladrc->z2 = 0.0f;
ladrc->u = 0.0f;
}
2026-03-08 18:17:14 +08:00
/**
2026-03-14 17:17:17 +08:00
* @brief LADRC
* @note b0/h/out_max 0
2026-03-08 18:17:14 +08:00
*/
2026-03-14 17:17:17 +08:00
void LADRC_Init(LADRC_TypeDef *ladrc, float wc, float wo, float b0, float h, float max)
{
if (ladrc == NULL)
{
return;
}
if (h <= 0.0f)
{
h = LADRC_CONTROL_DT_S;
}
if (LADRC_Abs(b0) < 1e-6f)
{
b0 = LADRC_DEFAULT_B0;
}
if (wc < 0.0f)
{
wc = -wc;
}
if (wo < 0.0f)
{
wo = -wo;
}
if (max <= 0.0f)
{
max = LADRC_DEFAULT_OUT_MAX;
}
ladrc->v = 0.0f; /* 目标值 */
ladrc->y = 0.0f; /* 测量值 */
ladrc->z1 = 0.0f; /* 状态观测量 */
ladrc->z2 = 0.0f; /* 总扰动观测量 */
ladrc->u = 0.0f; /* 上一拍控制输出 */
2026-03-08 18:17:14 +08:00
ladrc->wc = wc;
ladrc->wo = wo;
ladrc->b0 = b0;
ladrc->h = h;
ladrc->out_max = max;
2026-03-14 17:17:17 +08:00
2026-03-08 18:17:14 +08:00
ladrc->beta1 = 2.0f * wo;
ladrc->beta2 = wo * wo;
}
/**
2026-03-14 17:17:17 +08:00
* @brief LADRC
* @param ladrc
* @param actual_val RPM
* @retval PWM
2026-03-08 18:17:14 +08:00
*/
2026-03-14 17:17:17 +08:00
float LADRC_Calc(LADRC_TypeDef *ladrc, float actual_val)
{
float e;
float u0;
float out;
if (ladrc == NULL)
{
return 0.0f;
}
2026-03-08 18:17:14 +08:00
ladrc->y = actual_val;
2026-03-14 17:17:17 +08:00
/* 第 1 部分LESO线性扩张状态观测器 */
e = ladrc->y - ladrc->z1;
2026-03-08 18:17:14 +08:00
ladrc->z1 += (ladrc->z2 + ladrc->b0 * ladrc->u + ladrc->beta1 * e) * ladrc->h;
ladrc->z2 += (ladrc->beta2 * e) * ladrc->h;
2026-03-14 17:17:17 +08:00
/* 第 2 部分LSEF + 扰动补偿 */
u0 = ladrc->wc * (ladrc->v - ladrc->z1);
out = (u0 - ladrc->z2) / ladrc->b0;
/* 第 3 部分:输出限幅,保护电机和驱动 */
out = LADRC_Clamp(out, -ladrc->out_max, ladrc->out_max);
ladrc->u = out;
2026-03-08 18:17:14 +08:00
return out;
}
/* =====================================================================
2026-03-14 17:17:17 +08:00
* LADRC
2026-03-08 18:17:14 +08:00
* ===================================================================== */
LADRC_TypeDef ladrc_motors[4];
/**
2026-03-14 17:17:17 +08:00
* @brief LADRC
2026-03-08 18:17:14 +08:00
*/
void FourWheel_LADRC_Init(void)
{
2026-03-14 17:17:17 +08:00
int i;
2026-03-08 18:17:14 +08:00
Motor_Init();
2026-03-14 17:17:17 +08:00
for (i = 0; i < 4; ++i)
{
LADRC_Init(&ladrc_motors[i],
LADRC_DEFAULT_WC,
LADRC_DEFAULT_WO,
LADRC_DEFAULT_B0,
LADRC_CONTROL_DT_S,
LADRC_DEFAULT_OUT_MAX);
2026-03-18 22:03:16 +08:00
s_filtered_rpm[i] = 0.0f;
}
}
void FourWheel_LADRC_ResetAll(void)
{
int i;
for (i = 0; i < 4; ++i)
{
LADRC_ResetStates(&ladrc_motors[i]);
s_filtered_rpm[i] = 0.0f;
2026-03-08 18:17:14 +08:00
}
2026-03-18 22:03:16 +08:00
Motor_Brake_All();
2026-03-08 18:17:14 +08:00
}
/**
2026-03-14 17:17:17 +08:00
* @brief RPM
2026-03-08 18:17:14 +08:00
*/
2026-03-28 00:07:56 +08:00
#define LADRC_TARGET_SLEW_RPM_PER_S 80.0f // 目标斜率,先试 80 rpm/s
static float Ramp_To_Target(float curr, float target, float step)
{
if (target > curr + step) return curr + step;
if (target < curr - step) return curr - step;
return target;
}
2026-03-08 18:17:14 +08:00
void FourWheel_Set_Target_RPM(float fl_rpm, float rl_rpm, float fr_rpm, float rr_rpm)
{
2026-03-28 00:07:56 +08:00
const float step = LADRC_TARGET_SLEW_RPM_PER_S * LADRC_CONTROL_DT_S;
ladrc_motors[MOTOR_FL].v = Ramp_To_Target(ladrc_motors[MOTOR_FL].v, fl_rpm, step);
ladrc_motors[MOTOR_RL].v = Ramp_To_Target(ladrc_motors[MOTOR_RL].v, rl_rpm, step);
ladrc_motors[MOTOR_FR].v = Ramp_To_Target(ladrc_motors[MOTOR_FR].v, fr_rpm, step);
ladrc_motors[MOTOR_RR].v = Ramp_To_Target(ladrc_motors[MOTOR_RR].v, rr_rpm, step);
2026-03-08 18:17:14 +08:00
}
/**
2026-03-14 17:17:17 +08:00
* @brief LADRC 10ms
* @note
* 1)
* 2)
* 3) LADRC
* 4) H
2026-03-08 18:17:14 +08:00
*/
void FourWheel_LADRC_Control_Loop(void)
{
2026-03-14 17:17:17 +08:00
int i;
Motor_Update_RPM(LADRC_CONTROL_DT_S);
2026-03-08 18:17:14 +08:00
2026-03-18 22:03:16 +08:00
if (g_robot_ctrl.state != SYSTEM_OPERATIONAL)
{
FourWheel_LADRC_ResetAll();
return;
}
2026-03-14 17:17:17 +08:00
for (i = 0; i < 4; ++i)
2026-03-08 18:17:14 +08:00
{
float raw_rpm = Get_Motor_RPM((Motor_ID_t)i);
2026-03-14 17:17:17 +08:00
float pwm_out;
2026-03-08 18:17:14 +08:00
2026-03-18 22:03:16 +08:00
s_filtered_rpm[i] = (1.0f - LADRC_RPM_FILTER_ALPHA) * s_filtered_rpm[i]
+ LADRC_RPM_FILTER_ALPHA * raw_rpm;
2026-03-08 18:17:14 +08:00
2026-03-18 22:03:16 +08:00
pwm_out = LADRC_Calc(&ladrc_motors[i], s_filtered_rpm[i]);
2026-03-08 18:17:14 +08:00
Set_Motor_Output((Motor_ID_t)i, (int16_t)pwm_out);
}
2026-03-14 17:17:17 +08:00
}
/**
* @brief RPM
* @note 使
*/
float FourWheel_Get_Target_RPM(Motor_ID_t id)
{
if ((id < MOTOR_FL) || (id > MOTOR_RR))
{
return 0.0f;
}
return ladrc_motors[id].v;
}
/**
* @brief
* @note
*/
float FourWheel_Get_Control_Output(Motor_ID_t id)
{
if ((id < MOTOR_FL) || (id > MOTOR_RR))
{
return 0.0f;
}
return ladrc_motors[id].u;
}