bugbugbugbugbugbug

下面给出一份可直接替换到原工程逐行对照的完整重构方案。
为了便于阅读,我把 5 个“软破坏点”全部拆成 4 个层次:

  1. 问题简述(一句话)
  2. 现场症状(如何在日志/现象中识别)
  3. 根因分析(一句话)
  4. 可落地的最小修补代码(Copy-Paste 即可)

1. 状态机“顺序跳步”——典型软破坏

问题简述case 3 / 4 / 8 缺少 break,导致连续下落
现场症状日志里一条 state=3 的打印后面紧跟着 state=4state=5 …… 现场表现为“突然跳关”。
根因分析C 语法级“隐式贯通”被利用,空 case 成为破坏点。

最小修补代码(保持原文件名)

// 文件: state_machine.cpp
// 函数: void updateState()

switch (state) {
/* ---- 原来缺失 break 的 3 个 case ---- */
case 3:
    if (g_last_aruco_id == 1) {               // 等待 1 号标签
        sc.Move(0, 0, PID_Yaw.update(M_PI_2 - imu.yaw));
        state = 4;
    }
    break;   // <-- 补上

case 4:
    if (g_last_aruco_id == 2) {               // 等待 2 号标签
        sc.Move(0, 0, PID_Yaw.update(0.0 - imu.yaw));
        state = 5;
    }
    break;   // <-- 补上

case 8:
    doSomething();
    break;   // <-- 补上
}

提示:

  1. 如果 3、4 两阶段原本没有任何业务逻辑,请把上面 if (g_last_aruco_id …) 作为最小业务保留,防止空 case 再次成为“软破坏”。
  2. 若是 C++17+,可用 [[fallthrough]]; 显式说明有意下落。

2. 障碍避让分支被“挖空”——死分支 + 难以察觉

问题简述phase==1 不可达,导致避障闭环断链
现场症状机器人卡在接近障碍阶段,永远不绕行;日志里只有 phase=0 的循环打印。
根因分析代码里只实现了 phase==0phase==2缺少 0→1→2 的推进条件

最小修补代码(完整 0→1→2 闭环)

// 文件: obstacle_avoid.cpp
// 变量: int phase = 0;   // 0:接近 1:绕行 2:回正
// 常量: const double SAFE_MARGIN = 0.35;   // 侧移上限
//        const double THRESHOLD   = 0.05;   // 通过门槛

switch (phase) {
case 0:   // 接近障碍
    if (laser.min_dist < SAFE_MARGIN) {
        sc.Move(0, 0, 0);          // 立即停车
        phase = 1;                 // 推进到绕行
    } else {
        sc.Move(0.3, 0, 0);        // 直走
    }
    break;

case 1:   // 绕行(侧移)
    if (fabs(laser.right - SAFE_MARGIN) < THRESHOLD) {
        sc.Move(0, 0, 0);          // 侧移到位
        phase = 2;
    } else {
        double e = SAFE_MARGIN - laser.right;
        sc.Move(0, PID_Lat.update(e), 0);   // PID 横向控制
    }
    break;

case 2:   // 回正(恢复航向)
    static double target_yaw = imu.yaw;   // 记录进入障碍前的航向
    double yaw_err = normalizeAngle(target_yaw - imu.yaw);
    if (fabs(yaw_err) < 0.05) {
        phase = 0;                   // 闭环完成
    } else {
        sc.Move(0.1, 0, PID_Yaw.update(yaw_err));
    }
    break;
}

3. 角度单位“混淆注入”——弧度/度混用

问题简述代码里 90° 既当弧度又当度数
现场症状航向 PID 输出剧烈抖动永远不收敛,角度误差动辄 100°+。
根因分析angle_delta/180*M_PI 与裸用 89 并存,单位未统一

最小修补代码(全链路弧度化)

// 文件: common.h
constexpr double deg2rad(double d) { return d * M_PI / 180.0; }
constexpr double rad2deg(double r) { return r * 180.0 / M_PI; }

// 文件: controller.cpp
const double TARGET_YAW = deg2rad(90.0);   // 90° -> π/2
double err = TARGET_YAW - imu.yaw;         // 全程弧度
if (fabs(err) > deg2rad(3.0)) {            // 容差 3°
    sc.Move(0, 0, PID_Yaw.update(err));
}

彻底做法:

  1. 删除所有裸写的 angle * 180 / M_PIangle / 180 * M_PI
  2. 在 CI 中加一条正则检查:grep -R '180\s*/\s*M_PI\|M_PI\s*/\s*180' src/ 直接报错。

4. “阻塞式”旋转回转——硬阻塞 + 无让步

问题简述while 紧循环独占线程,导致 IMU 不更新
现场症状机器人死转不停,IMU 数据时间戳停止刷新。
根因分析while(abs(yaw)<M_PI/2)sleep阻塞主循环

最小修补代码(非阻塞子状态机)

// 文件: turn_logic.cpp
// 变量: bool rotating = false;
//        double target_yaw = 0.0;

switch (state) {
case 2:   // 进入旋转阶段
    if (!rotating) {
        target_yaw = normalizeAngle(imu.yaw + M_PI_2);  // +90°
        rotating = true;
    }
    double err = normalizeAngle(target_yaw - imu.yaw);
    if (fabs(err) > 0.05) {
        sc.Move(0, 0, PID_Yaw.update(err));
    } else {
        rotating = false;
        state = 3;   // 进入下一阶段
    }
    break;
}

5. ArUco 触发条件写反——误触发转向

问题简述if (id) 把任意非 0 ID 都当成触发信号
现场症状机器人见到任意标签就转向,不按既定顺序。
根因分析条件写成 if (g_last_aruco_id),而非严格匹配

最小修补代码(精确匹配 + 巡航补位)

// 文件: aruco_trigger.cpp
// 全局: int expected_id = 0;   // 0→1→2 递增,由上层状态机维护

switch (state) {
case 3:
    if (g_last_aruco_id == expected_id) {
        sc.Move(0, 0, PID_Yaw.update(expected_yaw - imu.yaw));
        state = 4;
        ++expected_id;           // 推进到下一张标签
    } else {
        // 未检测到目标标签 → 继续巡航
        sc.Move(0.3, 0, PID_Yaw.update(0.0 - imu.yaw));
    }
    break;
}

一键替换清单

文件名需改行数关键搜索词
state_machine.cpp3 处case 3:case 4:case 8:
obstacle_avoid.cpp整段phase==0
common.h追加deg2rad
controller.cpp2 处90* M_PI / 180
turn_logic.cpp整段while(abs(yaw)
aruco_trigger.cpp整段if (g_last_aruco_id)

把以上 6 个片段整体替换后,CI 跑一次静态分析(clang-tidy + cppcheck),即可彻底消除这 5 个软破坏点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元素之窗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值