OpenMV板球PID控制实战:手把手教你用Python和两个舵机搞定视觉追踪(附完整代码)

张开发
2026/4/18 4:39:23 15 分钟阅读

分享文章

OpenMV板球PID控制实战:手把手教你用Python和两个舵机搞定视觉追踪(附完整代码)
OpenMV板球PID控制实战手把手教你用Python和两个舵机搞定视觉追踪附完整代码在电子设计竞赛和自动化控制领域视觉追踪系统一直是个既经典又充满挑战的项目。想象一下让一个小球在平板上保持平衡或者让摄像头实时追踪移动的物体——这种将硬件控制与计算机视觉结合的项目不仅能锻炼多学科综合能力还能让你深入理解PID控制这个工业界广泛使用的算法精髓。今天我们要实现的板球控制系统使用OpenMV这款强大的嵌入式视觉模块作为眼睛配合两个舵机作为手臂通过Python编写的PID控制算法作为大脑构建一个完整的闭环控制系统。不同于传统的理论讲解本文将带你从零开始一步步完成硬件连接、环境配置、视觉识别到PID调参的全过程即使你是非计算机专业的学生也能轻松上手。1. 硬件准备与环境搭建1.1 所需材料清单在开始项目前确保你已准备好以下硬件OpenMV Cam H7主控设备负责图像处理和算法运行SG90微型舵机×2用于控制平板在X/Y轴方向的倾斜亚克力板或轻质平板作为小球运动的平台建议尺寸15×15cm乒乓球或小型钢球追踪目标直径建议3-4cm舵机支架与联轴器固定舵机并连接平板USB数据线用于OpenMV供电和程序烧录杜邦线若干用于电路连接提示舵机建议选用金属齿轮版本普通塑料齿轮舵机在频繁调节下容易损坏。1.2 硬件连接示意图正确的硬件连接是项目成功的第一步。下面是各组件连接方式组件OpenMV接口备注X轴舵机信号线P7控制平板左右倾斜Y轴舵机信号线P8控制平板前后倾斜舵机电源正极VIN需外接5V电源舵机电源负极GND共地连接# 舵机初始化代码示例 from pyb import Servo servo_x Servo(1) # P7引脚对应Servo(1) servo_y Servo(2) # P8引脚对应Servo(2)1.3 MicroPython开发环境配置OpenMV使用MicroPython作为编程语言配置步骤如下下载并安装OpenMV IDE官网提供各平台版本通过USB连接OpenMV摄像头IDE会自动识别设备点击连接按钮建立通信右下角指示灯变绿表示成功新建Python脚本文件准备开始编码注意首次使用时可能需要安装固件按照IDE提示操作即可。2. 视觉识别让OpenMV看见小球2.1 图像采集基础设置OpenMV的视觉功能基于其内置的OV7725传感器我们需要先进行基本的摄像头配置import sensor, image, time # 初始化摄像头 sensor.reset() sensor.set_pixformat(sensor.RGB565) # 设置彩色图像格式 sensor.set_framesize(sensor.QQVGA) # 160x120分辨率处理速度快 sensor.skip_frames(time2000) # 等待摄像头稳定 # 关闭自动调节功能避免图像参数波动 sensor.set_auto_gain(False) sensor.set_auto_exposure(False, 5000) sensor.set_auto_whitebal(False)2.2 颜色阈值与目标识别识别小球的核心是通过颜色阈值过滤。OpenMV IDE提供了方便的颜色阈值选取工具点击IDE工具栏中的阈值编辑器将小球放置在平板上调整光照条件与实际使用环境一致用矩形框选小球区域IDE会自动计算LAB颜色空间的阈值范围将得到的阈值填入以下代码# 示例阈值需根据实际小球颜色调整 ball_threshold (41, 65, 60, 85, 0, 65) # (L_min, L_max, A_min, A_max, B_min, B_max) while True: img sensor.snapshot() blobs img.find_blobs([ball_threshold]) if blobs: # 绘制识别到的小球轮廓和中心点 for blob in blobs: img.draw_rectangle(blob.rect()) img.draw_cross(blob.cx(), blob.cy())2.3 干扰过滤与目标锁定实际环境中可能存在颜色相似的干扰物我们需要增加过滤条件确保只追踪真正的小球def find_target_blob(blobs): max_score 0 target None for blob in blobs: # 综合考量圆形度和面积大小 roundness blob.roundness() # 圆形度越接近1越圆 area blob.area() # 像素面积 # 自定义评分公式可根据实际情况调整权重 score roundness * 0.7 area * 0.3 if score max_score: max_score score target blob return target3. PID控制算法实现3.1 PID原理简明图解PID控制器由三个基本组件构成比例(P)与当前误差成正比决定系统响应速度积分(I)累积历史误差消除稳态误差微分(D)基于误差变化率抑制系统振荡这三个参数的组合能够使系统快速、稳定地达到目标状态。在板球控制系统中设定值(Setpoint)平板中心位置如图像中心(80,60)过程变量(PV)小球当前的中心坐标(blob.cx(), blob.cy())控制输出舵机需要转动的角度3.2 Python实现PID控制器虽然Python支持面向对象编程但为了便于理解我们先使用函数式实现# PID参数初始值需要根据实际调试 KP 0.25 # 比例系数 KI 0.02 # 积分系数 KD 6.0 # 微分系数 # X轴PID控制 def pid_x(setpoint, current_value): global last_err_x, integral_x error setpoint - current_value integral_x error derivative error - last_err_x output KP * error KI * integral_x KD * derivative last_err_x error return output # Y轴PID控制结构相同 def pid_y(setpoint, current_value): # ...与pid_x类似实现...3.3 舵机控制与输出映射PID输出需要转换为舵机角度注意舵机的有效角度范围通常±90度def constrain(value, min_val, max_val): return max(min(value, max_val), min_val) while True: # ...图像采集和blob检测... if target_blob: # 计算PID输出图像中心(80,60)为目标位置 output_x pid_x(80, target_blob.cx()) output_y pid_y(60, target_blob.cy()) # 限制输出范围并控制舵机 angle_x constrain(output_x, -80, 80) angle_y constrain(output_y, -80, 80) servo_x.angle(-angle_x) # 取反是因为舵机方向与坐标系可能相反 servo_y.angle(angle_y)4. 系统调试与性能优化4.1 PID参数整定技巧调试PID参数是有章可循的遵循以下步骤先调P再调D最后调I将KI和KD设为0逐渐增大KP直到系统开始振荡然后取振荡时KP值的50%作为初始P值增加KD抑制振荡通常从KP的1/10开始最后加入少量KI消除静差典型问题与对策现象可能原因解决方案小球来回振荡KP太大或KD太小降低KP或增加KD响应迟缓跟不上小球KP太小适当增加KP稳态时有固定偏差KI不足小幅增加KI系统变得不稳定KI过大减小KI值4.2 常见问题排查问题1舵机抖动严重检查电源是否充足建议外接5V 2A电源增加KD值或降低KP值在代码中加入输出滤波# 简单的移动平均滤波 angle_history [0] * 5 current_index 0 def filtered_angle(new_angle): global current_index angle_history[current_index] new_angle current_index (current_index 1) % len(angle_history) return sum(angle_history) / len(angle_history)问题2小球偶尔丢失跟踪优化颜色阈值确保在各种光照下都能识别增加图像预处理如中值滤波img sensor.snapshot() img.median(1) # 1像素半径的中值滤波去除噪点4.3 性能优化技巧帧率提升降低图像分辨率如使用QQVGA而非QVGA限制搜索ROI区域减少处理面积关闭不必要的图像处理功能控制周期优化固定控制频率避免不稳定的时间间隔使用板载时钟确保定时精确clock time.clock() while True: clock.tick() # 跟踪帧率 # ...控制代码... print(clock.fps()) # 监控实际帧率5. 完整代码实现与扩展思路5.1 项目完整源代码以下是整合了所有优化措施的完整代码import sensor, image, time from pyb import Servo # 硬件初始化 sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QQVGA) sensor.skip_frames(time2000) sensor.set_auto_gain(False) sensor.set_auto_exposure(False, 5000) sensor.set_auto_whitebal(False) # 舵机初始化 servo_x Servo(1) # P7 servo_y Servo(2) # P8 # PID参数 KP 0.25 KI 0.02 KD 6.0 # 全局变量 last_err_x 0 integral_x 0 last_err_y 0 integral_y 0 angle_history_x [0] * 3 angle_history_y [0] * 3 hist_index 0 # 颜色阈值根据实际调整 BALL_THRESHOLD (41, 65, 60, 85, 0, 65) def pid_control(setpoint, current, last_err, integral): error setpoint - current integral error derivative error - last_err output KP * error KI * integral KD * derivative return output, error, integral def filtered_angle(new_angle, history): history[hist_index] new_angle return sum(history) / len(history) clock time.clock() while True: clock.tick() img sensor.snapshot() # 识别小球 blobs img.find_blobs([BALL_THRESHOLD]) target None max_score 0 if blobs: for blob in blobs: score blob.roundness() * blob.area() if score max_score: max_score score target blob if target: img.draw_rectangle(target.rect()) img.draw_cross(target.cx(), target.cy()) # PID计算 output_x, last_err_x, integral_x pid_control(80, target.cx(), last_err_x, integral_x) output_y, last_err_y, integral_y pid_control(60, target.cy(), last_err_y, integral_y) # 角度滤波与限制 angle_x max(min(output_x, 80), -80) angle_y max(min(output_y, 80), -80) filtered_x filtered_angle(-angle_x, angle_history_x) filtered_y filtered_angle(angle_y, angle_history_y) # 更新舵机 servo_x.angle(filtered_x) servo_y.angle(filtered_y) hist_index (hist_index 1) % len(angle_history_x) print(clock.fps())5.2 项目扩展方向当基础功能实现后可以考虑以下扩展无线监控功能通过Wi-Fi模块将图像和参数实时传输到PC开发简单的PC端监控界面自适应PID控制根据小球速度动态调整PID参数实现参数自整定算法多目标追踪同时追踪多个不同颜色的小球为每个目标实现独立的PID控制机械结构优化使用3D打印定制更精准的舵机支架尝试不同材质的平板表面减少摩擦在实际调试过程中我发现最关键的还是PID参数的耐心调整。有时候微小的参数变化会带来系统性能的显著提升建议准备一个小本子记录每次参数调整的效果这样能更快找到最佳组合。另外保持平板表面的清洁也很重要灰尘和指纹会影响小球的运动轨迹定期擦拭能让系统表现更加稳定。

更多文章