Files
ASER/App/nav/corridor_ctrl.c

240 lines
8.8 KiB
C
Raw Normal View History

2026-03-31 23:30:33 +08:00
#include "corridor_ctrl.h"
#include <math.h>
#include <stdbool.h>
2026-04-12 13:31:07 +08:00
#include <stdint.h>
2026-03-31 23:30:33 +08:00
/* ====================== 内部状态 ====================== */
static CorridorCtrlConfig_t s_cfg;
static bool s_initialized = false;
2026-04-12 13:31:07 +08:00
static float s_last_w_cmd = 0.0f;
static uint32_t s_last_t_ms = 0U;
2026-03-31 23:30:33 +08:00
/* 辅助:浮点数限幅 */
static inline float clampf(float val, float lo, float hi)
{
if (val < lo) return lo;
if (val > hi) return hi;
return val;
}
void CorridorCtrl_Init(const CorridorCtrlConfig_t *config)
{
s_cfg = *config;
s_initialized = true;
2026-04-12 13:31:07 +08:00
s_last_w_cmd = 0.0f;
s_last_t_ms = 0U;
2026-03-31 23:30:33 +08:00
}
void CorridorCtrl_Compute(const CorridorState_t *state,
const CorridorObs_t *obs,
float imu_wz,
RawCmd_t *out_cmd)
{
if (!s_initialized) {
out_cmd->v = 0.0f;
out_cmd->w = 0.0f;
out_cmd->flags = 0U;
return;
}
2026-04-12 11:57:14 +08:00
/* ========================================================
* : 使
*
* ======================================================== */
bool near_exit = false;
if ((obs->valid_mask & (1U << 4)) != 0U) { /* 前激光有效 (bit 4) */
if (obs->d_front <= s_cfg.exit_front_dist) {
near_exit = true;
}
}
2026-03-31 23:30:33 +08:00
/* ========================================================
* :
* w_cmd = kp_theta * e_th + kd_theta * (-imu_wz) + kp_y * e_y
*
* - kp_theta * e_th :
* - kd_theta * (-imu_wz) : "阻止车头继续转"
* IMU e_th
* - kp_y * e_y :
2026-04-12 11:57:14 +08:00
*
* : 使使
2026-03-31 23:30:33 +08:00
* ======================================================== */
2026-04-12 11:57:14 +08:00
float w_cmd;
bool escape_active = false;
2026-04-12 13:31:07 +08:00
bool front_guard_active = false;
float kp_theta_eff = s_cfg.kp_theta;
float kp_y_eff = s_cfg.kp_y;
float w_max_eff = s_cfg.w_max;
if (!near_exit && s_cfg.startup_dist > 0.01f && state->s < s_cfg.startup_dist) {
float ratio = state->s / s_cfg.startup_dist;
if (ratio < 0.0f) ratio = 0.0f;
if (ratio > 1.0f) ratio = 1.0f;
kp_y_eff = s_cfg.kp_y * (s_cfg.startup_kp_y_scale + (1.0f - s_cfg.startup_kp_y_scale) * ratio);
w_max_eff = s_cfg.w_max * (s_cfg.startup_w_scale + (1.0f - s_cfg.startup_w_scale) * ratio);
if (w_max_eff < 0.25f) {
w_max_eff = 0.25f;
}
}
2026-04-12 11:57:14 +08:00
if (near_exit) {
/* 接近出口: 仅保持航向惯性,禁用左右激光控制 */
w_cmd = -(s_cfg.kd_theta * imu_wz);
} else {
/* 正常控制: 完整PD控制律 */
2026-04-12 13:31:07 +08:00
w_cmd = -(kp_theta_eff * state->e_th
2026-04-12 11:57:14 +08:00
+ s_cfg.kd_theta * imu_wz
2026-04-12 13:31:07 +08:00
+ kp_y_eff * state->e_y);
2026-04-12 11:57:14 +08:00
/* ========================================================
* :
*
* EKF
* ======================================================== */
{
bool left_front_ok = ((obs->valid_mask & (1U << 0)) != 0U);
bool left_rear_ok = ((obs->valid_mask & (1U << 1)) != 0U);
bool right_front_ok = ((obs->valid_mask & (1U << 2)) != 0U);
bool right_rear_ok = ((obs->valid_mask & (1U << 3)) != 0U);
float w_escape = 0.0f;
float left_min = 10.0f;
float right_min = 10.0f;
if (left_front_ok && obs->d_lf < left_min) left_min = obs->d_lf;
if (left_rear_ok && obs->d_lr < left_min) left_min = obs->d_lr;
if (right_front_ok && obs->d_rf < right_min) right_min = obs->d_rf;
if (right_rear_ok && obs->d_rr < right_min) right_min = obs->d_rr;
if (left_min < s_cfg.wall_escape_dist) {
float err = s_cfg.wall_escape_dist - left_min;
w_escape -= s_cfg.wall_escape_kp * err; /* 左侧很近 -> 轻微右转 */
escape_active = true;
}
if (right_min < s_cfg.wall_escape_dist) {
float err = s_cfg.wall_escape_dist - right_min;
w_escape += s_cfg.wall_escape_kp * err; /* 右侧很近 -> 轻微左转 */
escape_active = true;
}
w_escape = clampf(w_escape, -s_cfg.wall_escape_w_max, s_cfg.wall_escape_w_max);
w_cmd += w_escape;
2026-04-12 13:31:07 +08:00
/* 前角防呆:
*
* / */
{
float front_guard_dist = s_cfg.wall_escape_dist + 0.01f;
if (left_front_ok && obs->d_lf < front_guard_dist) {
float err = front_guard_dist - obs->d_lf;
float w_guard = 0.15f + 0.20f * (err / front_guard_dist);
if (w_cmd > -w_guard) {
w_cmd = -w_guard;
}
front_guard_active = true;
}
if (right_front_ok && obs->d_rf < front_guard_dist) {
float err = front_guard_dist - obs->d_rf;
float w_guard = 0.15f + 0.20f * (err / front_guard_dist);
if (w_cmd < w_guard) {
w_cmd = w_guard;
}
front_guard_active = true;
}
}
2026-04-12 11:57:14 +08:00
}
}
2026-03-31 23:30:33 +08:00
/* 角速度限幅:防止 PD 溢出导致原地打转 */
2026-04-12 13:31:07 +08:00
w_cmd = clampf(w_cmd, -w_max_eff, w_max_eff);
/* 近墙保护触发时,再对总角速度做一次更保守的限幅,
* -> -> */
if (escape_active) {
w_cmd = clampf(w_cmd, -0.60f, 0.60f);
}
if (front_guard_active) {
w_cmd = clampf(w_cmd, -0.35f, 0.35f);
}
/* 角速度变化率限幅:抑制单拍突变,避免看起来像“突然失控猛打方向”。 */
{
float dt = 0.01f;
if (s_last_t_ms != 0U && state->t_ms > s_last_t_ms) {
dt = (float)(state->t_ms - s_last_t_ms) * 0.001f;
if (dt <= 0.0f || dt > 0.1f) {
dt = 0.01f;
}
}
{
float max_step = s_cfg.w_slew_rate * dt;
float delta = w_cmd - s_last_w_cmd;
delta = clampf(delta, -max_step, max_step);
w_cmd = s_last_w_cmd + delta;
}
s_last_w_cmd = w_cmd;
s_last_t_ms = state->t_ms;
}
2026-03-31 23:30:33 +08:00
/* ========================================================
* 线:
* v_cruise
*
* : v = v_cruise * (1 - k * |w/w_max|)
* k 0.3~0.5
* ======================================================== */
2026-04-12 13:31:07 +08:00
float speed_reduction = 0.0f;
{
float w_ratio = fabsf(w_cmd) / w_max_eff;
float db = s_cfg.speed_reduction_deadband;
if (db < 0.0f) db = 0.0f;
if (db > 0.95f) db = 0.95f;
if (w_ratio > db) {
float active_ratio = (w_ratio - db) / (1.0f - db);
speed_reduction = s_cfg.speed_reduction_k * active_ratio;
}
}
2026-03-31 23:30:33 +08:00
float v_cmd = s_cfg.v_cruise * (1.0f - speed_reduction);
2026-04-12 11:57:14 +08:00
/* 近墙脱离时轻微降速,避免“贴着墙还继续冲” */
if (escape_active) {
v_cmd *= 0.80f;
}
2026-04-12 13:31:07 +08:00
if (front_guard_active) {
v_cmd *= 0.65f;
}
2026-03-31 23:30:33 +08:00
/* 线速度限幅:不允许倒车,不允许超速 */
v_cmd = clampf(v_cmd, 0.0f, s_cfg.v_max);
/* ========================================================
* :
* conf
* 线
2026-04-12 11:57:14 +08:00
*
*
2026-03-31 23:30:33 +08:00
* ======================================================== */
2026-04-12 11:57:14 +08:00
if (state->conf < 0.2f) {
2026-03-31 23:30:33 +08:00
/* 健康度极低:速度打三折,保持航向惯性滑行 */
v_cmd *= 0.3f;
2026-04-12 11:57:14 +08:00
} else if (state->conf < 0.4f) {
2026-03-31 23:30:33 +08:00
/* 健康度较低(单侧退化):速度打七折 */
v_cmd *= 0.7f;
}
/* 输出赋值 */
out_cmd->t_ms = state->t_ms;
out_cmd->v = v_cmd;
out_cmd->w = w_cmd;
out_cmd->flags = 0U;
}