挑战全网最低成本!STM32+OpenCV+PID 打造“视觉追踪火控云台” (附源码)

挑战全网最低成本!STM32+OpenCV+PID 打造“视觉追踪火控云台” (附源码)

前言

想做一个“软硬结合”的项目,于是选择了当下最火的机器视觉方向。

市面上的视觉云台动辄几百上千,作为一个穷学生,我决定挑战极限:用最便宜的 SG90 舵机(3元/个)配合 STM32(hal库) 和 Python,手搓一个 AI 自动瞄准系统。

虽然硬件简陋,但通过引入 PID 控制算法 和 视差补偿逻辑,我成功克服了廉价舵机的抖动问题,实现了还不错的追踪效果。

一、 硬件清单:成本不到一杯咖啡 ☕️

这个项目的核心理念就是“低成本”。

硬件名称 型号/参数 参考价格 作用
主控芯片 STM32F103C8T6 15元 控制核心,产生 PWM 波
执行器 SG90 180度舵机 x2 6元 组成二自由度云台 (X轴/Y轴)
视觉传感器 电脑自带摄像头 0元 图像采集
通信模块 USB 转 TTL (CH340) 5元 电脑与单片机的数据桥梁
其他 激光头 + 热熔胶 2元 模拟“发射器”
总计 < 30元

二、 系统架构设计 🛠️

整个系统分为 上位机 (电脑) 和 下位机 (STM32) 两部分,通过串口通讯。

  • PC 端 (Python): 负责“眼睛”和“大脑”。使用 OpenCV 捕捉目标(橙色小球),计算坐标误差,并通过 PID 算法计算出舵机需要移动的角度,通过串口发送。
  • STM32 端 (C语言): 负责“手”。接收串口数据,解析指令,输出 PWM 波控制舵机转动。
  • 工作流程:摄像头 —> Python —> 串口 —> STM32 —> 舵机

三、 核心难点突破 (干货部分) ⚡️

1. 视觉识别:HSV 颜色空间提取

为了快速锁定目标,我使用了颜色阈值分割。相比于 RGB,HSV 空间对光照更具有鲁棒性。

2. 通信协议:如何防止数据“打架”

为了保证 STM32 能准确解析数据,我设计了简单的包格式:X增量,Y增量\n。

在 STM32 端,使用 sscanf 进行解析,只有检测到 \n 换行符才开始处理,有效防止了粘包问题。

3. 灵魂算法:PID 控制与消抖 (重点!)

这是本项目的最大挑战。 SG90 舵机存在极大的虚位死区

  • 初期问题: 使用简单的比例控制 (P),云台在目标附近疯狂“摇头”(震荡)。
  • 解决方案: 引入 PID 算法。
    • P (比例): 提供响应速度。
    • D (微分): 提供“阻尼感”,在接近目标时提前刹车,消除抖动。
    • 软件死区: 当误差小于 40 像素时,强制停止调整,防止舵机在终点附近反复横跳。
 # PID 代码 import time   
class PID:     
    def __init__(self, kp, ki, kd):         
        self.kp = kp  # 比例(动力)         
        self.ki = ki  # 积分(很少用)         
        self.kd = kd  # 微分(阻尼/防抖)          
        self.last_error = 0         
        self.last_time = time.time()
      
    def compute(self, error):         
        current_time = time.time()         
        delta_time = current_time - self.last_time          
        # 防止时间过短导致除以0 
        if delta_time <= 0: 
            delta_time = 0.001                    # P: 比例项         
            p_out = self.kp * error               # D: 微分项 (本次误差 - 上次误差) / 时间         
            derivative = (error - self.last_error) / delta_time         
            d_out = self.kd * derivative          # I: 积分项 (视觉追踪通常不需要,设为0即可) 
        # 如果需要,这里可以加 integral 逻辑 
   
        # 总输出         
    output = p_out + d_out          # 更新状态         
    self.last_error = error         
    self.last_time = current_time          
return output
 

四、 效果展示 & 遇到的坑 💣

1. 物理视差问题

现象: 摄像头识别准了,但激光总是打偏。

分析: 激光笔是粘在云台上的,两者物理上不重合。

解决: 在 Python 代码中加入 OFFSET_X 和 OFFSET_Y 进行软件补偿。

2. 成果展示

虽然受限于 SG90 的机械精度,无法做到指哪打哪的工业级精度,但它已经能灵敏地跟随小球运动。

动图封面

五、 源码下载 📥

本项目的完整代码(Python上位机 + STM32源码)已上传。

Github链接:github.com/edythieajahg