1.0
This commit is contained in:
@@ -38,6 +38,7 @@ static struct {
|
||||
float turn_start_yaw_deg; /* IMU yaw_continuous at turn start */
|
||||
float turn_target_delta_deg; /* 90° */
|
||||
int8_t turn_sign; /* +1 (CCW) or -1 (CW) */
|
||||
float turn_goal_yaw_deg; /* 本次转向完成后的名义目标航向 */
|
||||
|
||||
/* 里程 (用里程计积分距离) */
|
||||
float stage_entry_odom_vx_accum; /* 进入阶段时的里程计累计距离 */
|
||||
@@ -454,6 +455,7 @@ static void transition_to(GlobalNavStage_t next, const RobotBlackboard_t* board)
|
||||
s_nav.turn_sign = (int8_t)cd->entry_turn_dir;
|
||||
s_nav.turn_start_yaw_deg = imu_yaw;
|
||||
s_nav.turn_target_delta_deg = 90.0f;
|
||||
s_nav.turn_goal_yaw_deg = s_nav.turn_start_yaw_deg + (float)s_nav.turn_sign * 90.0f;
|
||||
break;
|
||||
}
|
||||
case GNAV_TURN_OUT_OF_CORRIDOR: {
|
||||
@@ -461,6 +463,7 @@ static void transition_to(GlobalNavStage_t next, const RobotBlackboard_t* board)
|
||||
s_nav.turn_sign = (int8_t)cd->exit_turn_dir;
|
||||
s_nav.turn_start_yaw_deg = imu_yaw;
|
||||
s_nav.turn_target_delta_deg = 90.0f;
|
||||
s_nav.turn_goal_yaw_deg = s_nav.turn_start_yaw_deg + (float)s_nav.turn_sign * 90.0f;
|
||||
break;
|
||||
}
|
||||
case GNAV_TURN_INTO_NEXT: {
|
||||
@@ -469,6 +472,7 @@ static void transition_to(GlobalNavStage_t next, const RobotBlackboard_t* board)
|
||||
s_nav.turn_sign = (int8_t)cd->entry_turn_dir;
|
||||
s_nav.turn_start_yaw_deg = imu_yaw;
|
||||
s_nav.turn_target_delta_deg = 90.0f;
|
||||
s_nav.turn_goal_yaw_deg = s_nav.turn_start_yaw_deg + (float)s_nav.turn_sign * 90.0f;
|
||||
s_nav.current_corridor_id = next_id;
|
||||
break;
|
||||
}
|
||||
@@ -700,25 +704,9 @@ void GlobalNav_Update(const CorridorObs_t* obs,
|
||||
}
|
||||
|
||||
if (s_nav.reacquire_ok_count >= s_nav.cfg.reacquire_confirm_ticks) {
|
||||
CorridorPoseEval_t pose_eval;
|
||||
evaluate_corridor_pose(obs, board, &pose_eval);
|
||||
update_wall_heading_stability(pose_eval.heading_valid, pose_eval.heading_rad);
|
||||
|
||||
/* 评估结果说明:
|
||||
* - need_align: 车头歪/偏心/贴墙/对角近墙,需要先停一下
|
||||
* - safe_for_align: 当前几何足够健康,允许按姿态估计输出转向
|
||||
*
|
||||
* 即使几何暂时不安全,只要 need_align=true 也先进入 ALIGN 停住,
|
||||
* 避免一边前进一边突然大角度纠正。 */
|
||||
if (pose_eval.need_align) {
|
||||
transition_to(GNAV_ALIGN, board);
|
||||
} else {
|
||||
if (board->imu_yaw_continuous.is_valid) {
|
||||
CorridorFilter_RebaseHeading(board->imu_yaw_continuous.value * 0.01745329252f);
|
||||
s_nav.heading_ref_deg = board->imu_yaw_continuous.value;
|
||||
}
|
||||
transition_to(GNAV_CORRIDOR_TRACK, board);
|
||||
}
|
||||
/* 简化:重捕获成功后统一停车摆正航向。
|
||||
* 不再在这里用墙姿态决定“摆不摆正”,避免不同沟表现不一致。 */
|
||||
transition_to(GNAV_ALIGN, board);
|
||||
}
|
||||
if (elapsed_ms > s_nav.cfg.reacquire_timeout_ms) {
|
||||
/* 取消重捕获失败态:超时后不进 ERROR,
|
||||
@@ -735,26 +723,35 @@ void GlobalNav_Update(const CorridorObs_t* obs,
|
||||
* 控制器还继续朝墙边打”的情况。
|
||||
* ============================================================ */
|
||||
case GNAV_ALIGN: {
|
||||
CorridorPoseEval_t pose_eval;
|
||||
evaluate_corridor_pose(obs, board, &pose_eval);
|
||||
update_wall_heading_stability(pose_eval.heading_valid, pose_eval.heading_rad);
|
||||
float imu_yaw_err_rad = 0.0f;
|
||||
bool imu_align_ok = false;
|
||||
|
||||
if (board->imu_yaw_continuous.is_valid) {
|
||||
imu_yaw_err_rad = PARAM_DEG2RAD(s_nav.turn_goal_yaw_deg - board->imu_yaw_continuous.value);
|
||||
while (imu_yaw_err_rad > 3.14159265f) imu_yaw_err_rad -= 6.2831853f;
|
||||
while (imu_yaw_err_rad < -3.14159265f) imu_yaw_err_rad += 6.2831853f;
|
||||
|
||||
if (gnav_fabsf(imu_yaw_err_rad) < s_nav.cfg.align_th_tol_rad &&
|
||||
(!board->imu_wz.is_valid || gnav_fabsf(board->imu_wz.value) < 15.0f)) {
|
||||
imu_align_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
out->override_v = 0.0f;
|
||||
out->use_override = true;
|
||||
out->request_corridor = false;
|
||||
out->safety_mode = SAFETY_MODE_STRAIGHT;
|
||||
|
||||
if (pose_eval.safe_for_align && s_nav.wall_heading_stable_count >= 2U) {
|
||||
float w_align = -(s_nav.cfg.align_kp_th * pose_eval.heading_rad
|
||||
+ s_nav.cfg.align_kp_y * pose_eval.e_y_m);
|
||||
out->override_w = gnav_clampf(w_align, -0.20f, 0.20f);
|
||||
if (board->imu_yaw_continuous.is_valid) {
|
||||
/* imu_yaw_err_rad = target - current
|
||||
* 误差为正时,需要正角速度(左转/逆时针)去追目标,不能取反。 */
|
||||
float w_align_imu = 1.2f * imu_yaw_err_rad;
|
||||
out->override_w = gnav_clampf(w_align_imu, -0.18f, 0.18f);
|
||||
} else {
|
||||
out->override_w = 0.0f;
|
||||
}
|
||||
|
||||
if (pose_eval.safe_for_align &&
|
||||
gnav_fabsf(pose_eval.heading_rad) < s_nav.cfg.align_th_tol_rad &&
|
||||
gnav_fabsf(pose_eval.e_y_m) < s_nav.cfg.align_y_tol_m) {
|
||||
if (imu_align_ok) {
|
||||
s_nav.align_ok_count++;
|
||||
} else {
|
||||
s_nav.align_ok_count = 0;
|
||||
@@ -767,12 +764,12 @@ void GlobalNav_Update(const CorridorObs_t* obs,
|
||||
}
|
||||
transition_to(GNAV_CORRIDOR_TRACK, board);
|
||||
}
|
||||
if (!pose_eval.safe_for_align && elapsed_ms > 400U) {
|
||||
if (board->imu_yaw_continuous.is_valid) {
|
||||
if (elapsed_ms > 400U) {
|
||||
if (board->imu_yaw_continuous.is_valid && imu_align_ok) {
|
||||
CorridorFilter_RebaseHeading(board->imu_yaw_continuous.value * 0.01745329252f);
|
||||
s_nav.heading_ref_deg = board->imu_yaw_continuous.value;
|
||||
transition_to(GNAV_CORRIDOR_TRACK, board);
|
||||
}
|
||||
transition_to(GNAV_CORRIDOR_TRACK, board);
|
||||
}
|
||||
if (elapsed_ms > s_nav.cfg.align_timeout_ms) {
|
||||
if (board->imu_yaw_continuous.is_valid) {
|
||||
@@ -825,6 +822,7 @@ void GlobalNav_Update(const CorridorObs_t* obs,
|
||||
float w_heading = heading_hold_pd(imu_yaw_deg, s_nav.heading_ref_deg,
|
||||
s_nav.cfg.heading_kp);
|
||||
float w_wall_guard = 0.0f;
|
||||
float w_wall_parallel = 0.0f;
|
||||
const CorridorDescriptor_t* corridor = TrackMap_GetCorridor(s_nav.current_corridor_id);
|
||||
|
||||
if (corridor != NULL && corridor->travel_dir == TRAVEL_DIR_EAST) {
|
||||
@@ -835,6 +833,14 @@ void GlobalNav_Update(const CorridorObs_t* obs,
|
||||
float error = s_nav.cfg.link_wall_target - d_right;
|
||||
w_wall_guard = s_nav.cfg.link_wall_kp * error;
|
||||
}
|
||||
|
||||
/* 右端通道:右侧是围栏。
|
||||
* 用右前/右后距离差把车身摆成与围栏平行,
|
||||
* 避免“不蹭墙但车身是歪的”。 */
|
||||
{
|
||||
float heading_right = atan2f(obs->d_rf - obs->d_rr, PARAM_SENSOR_BASE_LENGTH);
|
||||
w_wall_parallel = -s_nav.cfg.link_wall_heading_kp * heading_right;
|
||||
}
|
||||
}
|
||||
} else if (corridor != NULL) {
|
||||
if ((obs->valid_mask & CORRIDOR_OBS_MASK_LF) &&
|
||||
@@ -844,10 +850,17 @@ void GlobalNav_Update(const CorridorObs_t* obs,
|
||||
float error = s_nav.cfg.link_wall_target - d_left;
|
||||
w_wall_guard = -(s_nav.cfg.link_wall_kp * error);
|
||||
}
|
||||
|
||||
/* 左端通道:左侧是围栏。 */
|
||||
{
|
||||
float heading_left = atan2f(obs->d_lr - obs->d_lf, PARAM_SENSOR_BASE_LENGTH);
|
||||
w_wall_parallel = -s_nav.cfg.link_wall_heading_kp * heading_left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out->override_w = gnav_clampf(w_heading + w_wall_guard, -1.0f, 1.0f);
|
||||
w_wall_parallel = gnav_clampf(w_wall_parallel, -0.20f, 0.20f);
|
||||
out->override_w = gnav_clampf(w_heading + w_wall_guard + w_wall_parallel, -1.0f, 1.0f);
|
||||
|
||||
{
|
||||
bool front_valid = (obs->valid_mask & CORRIDOR_OBS_MASK_FRONT) != 0U;
|
||||
|
||||
Reference in New Issue
Block a user