基于FPGA的视觉跟踪系统,配合舵机云台跟踪单色物体,例如乒乓球。 vivado工程,基于Basys3板卡。 注意:不硬件部分。

先看图像处理流水线。OV7670摄像头出来的RGB565数据进FPGA后,首要任务是转换成HSV颜色空间。这里有个取巧的写法:

// RGB转HSV核心计算
always @(posedge clk) begin
    max = (R > G) ? ((R > B) ? R : B) : ((G > B) ? G : B);
    min = (R < G) ? ((R < B) ? R : B) : ((G < B) ? G : B);
    delta = max - min;
    
    // 色相计算部分
    if(delta == 0) H <= 0;
    else if(max == R) H <= ((G - B) * 60) / delta;
    else if(max == G) H <= 120 + ((B - R) * 60) / delta;
    else H <= 240 + ((R - G) * 60) / delta;
end

这个实现用了三级流水,实际跑在100MHz时钟下处理640x480图像毫无压力。注意除法运算这里直接用了IP核,自己写迭代除法器会严重拖慢时序。

颜色阈值处理阶段,重点在于动态调整。我们在Block Memory里存了六组阈值参数,通过板载按键实时切换:

reg [7:0] hue_threshold[5:0];
reg [2:0] preset_sel = 0;

always @(posedge clk) begin
    if(hue > hue_threshold[preset_sel][7:4] && 
       hue < hue_threshold[preset_sel][3:0])
        binary_out <= 1'b1;
    else
        binary_out <= 1'b0;
end

调试时发现乒乓球的HSV值在特定光照下会漂移,所以预留了多个预设档位,现场调试时哪个档位锁定效果好用哪个。

物体追踪算法采用质心追踪法。每帧统计白色像素的坐标和:

reg [18:0] sum_x, sum_y; // 640*480=307200 < 2^19
reg [18:0] pixel_count;

always @(posedge vsync) begin
    if(pixel_count != 0) begin
        center_x <= sum_x / pixel_count;
        center_y <= sum_y / pixel_count;
    end
    // 复位累加器
    sum_x <= 0;
    sum_y <= 0; 
    pixel_count <= 0;
end

这里有个坑:当目标移出画面时pixel_count可能为0,必须做除零保护。后来在除法器前加了条件判断,避免系统崩溃。

舵机控制用PWM波实现,重点在动态响应。根据目标偏移量计算舵机角度:

// 水平方向控制参数
reg signed [15:0] error_x;
reg [7:0] pwm_duty_x;

always @(posedge clk) begin
    error_x = center_x - 320; // 屏幕中心320像素处
    // 比例系数0.4,8位定点数计算
    pwm_duty_x = 90 + (error_x * 10'sd102) >>> 8; 
end

这个位移公式经过实测调校,系数102相当于0.4的定点数表示(102/256≈0.4)。右移8位替代除法运算,节省了大量逻辑资源。

最后来个联调技巧:在Vivado里设置ILA抓取图像处理中间信号,直接叠在VGA画面上显示阈值范围和质心位置,比用SignalTap逐帧分析效率高十倍。当看到红色标记框稳稳套住乱窜的乒乓球时,就知道这波稳了。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐