清理编码器+死代码+可读性整理: 删除ENCODER类(含UB析构), MotorController简化为PWM+GPIO裸控制器, 移除mortor_kp/ki/kd全局变量, 排除vl53l0x/zebra_detect死代码, 修复image_cv行列写反, 清理无关include

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
spdis
2026-06-10 15:15:34 +08:00
parent d284e18407
commit 114d93cec7
16 changed files with 264 additions and 519 deletions
+11 -63
View File
@@ -15,11 +15,10 @@
// 全局图像变量
// ============================================================
cv::Mat raw_frame; // 摄像头原始帧 (320×240, BGR)
cv::Mat grayFrame; // 灰度图 (未在当前管线中使用,保留)
cv::Mat binarizedFrame; // HSV 双通道 Otsu 二值化结果
cv::Mat morphologyExFrame; // 形态学开运算后的图像
cv::Mat track; // 洪泛填充后的赛道区域蒙版
cv::Mat raw_frame;
cv::Mat binarizedFrame;
cv::Mat morphologyExFrame;
cv::Mat track;
// ============================================================
// 边界线数组 — 左/右边缘和中线的逐行列坐标
@@ -28,12 +27,9 @@ cv::Mat track; // 洪泛填充后的赛道区域蒙版
// 列坐标范围: 0 ~ line_tracking_width-1 (0~79)
// 未检测到边界 = -1
// ============================================================
std::vector<int> left_line; // 左边缘列号 (逐行)
std::vector<int> right_line; // 右边缘列号 (逐行)
std::vector<int> mid_line; // 中线列号 = (left+right)/2
std::vector<double> left_line_filtered; // 左边缘 EMA 滤波结果
std::vector<double> right_line_filtered; // 右边缘 EMA 滤波结果
std::vector<double> mid_line_filtered; // 中线滤波结果
std::vector<int> left_line;
std::vector<int> right_line;
std::vector<int> mid_line;
int line_tracking_width; // 处理宽度 = 80
int line_tracking_height; // 处理高度 = 60
@@ -118,7 +114,7 @@ cv::Mat find_road(cv::Mat &frame)
// 1. 形态学开运算去噪
// MORPH_CROSS: 十字形结构元素,2×2
// MORPH_OPEN: 先腐蚀(去除小白点) 再膨胀(恢复区域尺寸)
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(2, 2));
static cv::Mat kernel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(2, 2));
cv::morphologyEx(binarizedFrame, morphologyExFrame, cv::MORPH_OPEN, kernel);
// 2. 创建洪泛填充蒙版
@@ -150,7 +146,7 @@ cv::Mat find_road(cv::Mat &frame)
// 7. 从蒙版提取赛道区域
// mask 的外扩边框(±1) 用于 floodFill 的内部计算,实际区域在(1,1)起
// ROI 裁掉边框后即为赛道主体蒙版
cv::Mat outputImage = cv::Mat::zeros(line_tracking_width, line_tracking_height, CV_8UC1);
cv::Mat outputImage = cv::Mat::zeros(line_tracking_height, line_tracking_width, CV_8UC1);
mask(cv::Rect(1, 1, line_tracking_width, line_tracking_height)).copyTo(outputImage);
return outputImage;
@@ -191,16 +187,10 @@ void image_main()
left_line.clear();
right_line.clear();
mid_line.clear();
left_line_filtered.clear();
right_line_filtered.clear();
mid_line_filtered.clear();
left_line.resize(line_tracking_height, -1);
right_line.resize(line_tracking_height, -1);
mid_line.resize(line_tracking_height, -1);
left_line_filtered.resize(line_tracking_height, -1);
right_line_filtered.resize(line_tracking_height, -1);
mid_line_filtered.resize(line_tracking_height, -1);
// ── 5. 逐行最长连续段搜索 ──────────────────────────
//
@@ -270,28 +260,10 @@ void image_main()
}
}
// ── 6. 中线计算 + 丢线补全 → 自底向上 EMA 滤波 ─────
//
// 核心逻辑(从底部 row=59 往上到 row=10:
//
// 6a. 如果当前行左右边界均有效 → 中线 = (left + right) / 2
//
// 6b. 如果当前行丢线(左右均无效):
// 用下一行(row+1)的中线补全:
// → 中线下半区: 虚拟右边界在右边缘,左边界 = 下行中线
// → 中线上半区: 虚拟左边界在左边缘,右边界 = 下行中线
// 自动适应赛道偏左还是偏右的情况
//
// 6c. EMA 滤波 (指数移动平均):
// row 本身的值权重 = a (0.4), 下行滤波值权重 = 1-a (0.6)
// 从底部往顶部递推: 近处(底部)值稳定,远处(顶部)靠递推外推
// a=0.4 → 近处值占主导,但保留过去趋势的惯性
//
double a = 0.4; // EMA 系数: 平衡当前测量与历史递推
// ── 6. 中线计算 + 丢线补全 ─────
for (int row = line_tracking_height - 1; row >= 10; --row)
{
// ── 6b. 丢线补全 ──────────────────────────────
// ── 6a. 丢线补全 ──────────────────────────────
if (left_line[row] == -1 && right_line[row] == -1)
{
// 当前行完全丢线: 用下行(row+1)的中线来虚拟补线
@@ -317,29 +289,5 @@ void image_main()
// 正常行: 中线 = 左右边界中点
mid_line[row] = (left_line[row] + right_line[row]) / 2;
}
// ── 6c. EMA 滤波 (自底向上) ────────────────────
if (row == line_tracking_height - 1)
{
// 最底行(最近处): 无下行参考,直接使用原始值
left_line_filtered[row] = left_line[row];
right_line_filtered[row] = right_line[row];
mid_line_filtered[row] = mid_line[row];
}
else
{
// 公式: filtered[row] = a * raw[row] + (1-a) * filtered[row+1]
// a=0.4: 40% 当前行实测值 + 60% 下行滤波值的递推
// 效果: 近处值稳定,越往远处越靠递推,杜绝抖动的概率传播
left_line_filtered[row] = a * left_line[row]
+ (1 - a) * left_line_filtered[row + 1];
right_line_filtered[row] = a * right_line[row]
+ (1 - a) * right_line_filtered[row + 1];
// 中线的滤波值为左右滤波边界的均值(不是对原始中线做 EMA)
// 即: 先对左右边界各自滤波, 再求平均 → 减少中线突跳
// 原注释行: mid_line_filtered[row] = a*mid_line[row] + (1-a)*mid_line_filtered[row+1]
mid_line_filtered[row] = (left_line_filtered[row] + right_line_filtered[row]) / 2.0;
}
}
}