去年带队参加电赛时,我们组选择了激光打靶题目。当时最大的挑战是如何让OpenMV摄像头稳定识别靶框,并精确控制激光头完成循迹。这里分享下我们最终采用的方案:将摄像头光轴与激光发射器同轴安装,这样图像坐标系和物理坐标系就能保持线性关系,省去了复杂的坐标变换。
实际调试中发现,靶框识别稳定性直接影响整个系统性能。我们尝试过多种图像预处理方法,最终确定的工作流程是:
python复制# 硬件初始化代码片段
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.set_auto_gain(False) # 必须关闭自动增益
sensor.set_auto_whitebal(False) # 关闭白平衡
在矩形检测环节,我们踩过几个坑:
解决方案是采用动态阈值补偿:当检测到四个角点后,取每个角点周围7个像素的RGB均值作为局部参考值。这里有个细节处理:对角点坐标进行±3像素的微调,可以显著提升直线方程计算精度。
python复制# 角点坐标补偿算法
for i in range(4):
if i==1: # 右上角点
point[i][0] -= 3
point[i][1] -= 3
elif i==2: # 右下角点
point[i][0] -= 3
point[i][1] += 3
elif i==3: # 左下角点
point[i][0] += 4
point[i][1] += 4
循迹控制的核心是计算相邻角点间的直线方程。我们采用分阶段PID控制策略:
每条边的控制逻辑略有不同。以右边为例,其直线方程计算方式为:
python复制# 右边直线方程计算
k1 = (point[1][1]-point[2][1])/(point[1][0]-point[2][0]+0.0001) # 避免除零
xp1 = k1*k1 + 1
yp = ((80*k1 + (60-point[2][1])*(xp1-1) - point[2][0]*k1)/xp1 + point[2][1]) + (l1*k1)/math.sqrt(xp1)
与下位机的通信采用自定义协议:
实测发现,传输前对坐标值取整能降低通信错误率。例如x坐标82.356应处理为:
python复制uart.write('%')
uart.write(str(len(str(round(xp,1))))) # 写入数据长度
uart.write(str(round(xp,1))) # 写入x坐标
uart.write(str(len(str(round(yp,1))))) # 写入数据长度
uart.write(str(round(yp,1))) # 写入y坐标
uart.write('&')
调试时建议先用img.draw_line()可视化检测结果,确认算法正确后再接入执行机构。我们团队在最终比赛时,系统完成了连续50圈循迹无丢靶的稳定表现。