基于图像传感器的小车循迹控制
常州工学院
制作学生:杨义鹏,杨锟,高星宇
指导老师:肖闽进,蔡纪鹤,马金祥
一、设计方案工作原理
1、摄像头图像识别的循迹小车设计背景
当前,实用的图像处理系统都要求高速处理。目前广泛采用软件进行处理,但软件处理存在速度、成本的问题。近年来,随着现成可编程门阵列FPGA 的发展,为提高图像处理系统的性能提供了新的思路和方法。FPGA 的并行特性所带来的高速性,以及低成本低功耗等特性,都是计算机无法比拟的。
摄像头循迹小车的FPGA 以及PCB 部分采用digilent 公司Basys3 FPGA 开发板作为控制核心,此款开发板采用xilinx 7系列芯片,板卡设计小巧,同时片上资源也足以满足大多教学应用场合。
2、预期实现目标定位
设计并制作基于basys3的FPGA 运用ov7725摄像头进行图像识别的循迹小车,能够拍摄画面并经行捕捉,在小车偏离赛道时进行控制使其能够完成循迹的目的。
3、技术方案分析比较
方案1:采用带fifo 的ov7670摄像头做二值化循迹
图1-1带fifo 的ov7670摄像头
该摄像头自带fifo 模块,是针对慢速的MCU 能够实现图像采集控制推出的带有缓冲存储空间的一种模块,自带的fifo(先进先出)存储芯片使得处理图像拍摄数据存储时避免了SDRAM 、DDR 的使用,包含30w 像素的图像感光芯片,操作和使用很方便,对读出的数据进行二值化处理,加上阈值后可以进行循迹使用。
方案2:采用带硬件二值化的ov7725摄像头做二值化循迹
图1-2 带硬件二值化的ov7725摄像头
此摄像头自带硬件二值化可以直接输出二值化后的0和1黑白图像,并且采样和输出速度要高于ov7670, 在进行黑线循迹时优化二值化算法使得循迹变得简单。 方案3:采用ov7725摄像头进行图像捕捉
此摄像头相对于ov7670的优点仍为高速的采样和输出速度,相对于带有硬件二值化摄像头丧失了二值化的优势但是可以摒弃二值化单纯只能循迹黑线的问题,进行图像识别而可以直接对物体进行图像捕捉,增加了使用的范围。
最后选用方案及理由:采用带fifo 的ov7725摄像头,原因为相比于ov7670摄像头,其处理速度更加快,相比于带硬件二值化的摄像头其可以做的不仅仅为简单的二值化循迹,可以上升到图像识别和捕捉的层面从而可以满足更多的需要。
4、系统结构工作原理
系统的总体框图如图所示
图1-3 系统结构工作原理
5、功能指标和实现方法
(1)通过ov7725摄像头拍摄画面
采用ov7725摄像头,对画面进行初步处理,检测能否拍到数据为后续的图像处理和控制打下基础。
(2)对ov7725捕捉到的画面进行像素转换 首先将采集到的RGB 像素,转换成HSV 像素,由于RGB 色空间和HSV 空间之间的转换为非线性的,硬件实现需要考虑时钟同步、算法优化、实时性等问题。采用了低延迟的除法器实现Hue 分量与Saturation 分量的高速计算,从而实现了RGB 转换成HSV 。
(3)进行色彩提取和坐标计算
原理是应用了色彩方面的理论,寻找类似黑线色彩的区域,然后计算这个区域的中心。首先需要人为提取黑线的HSV 分量(只提取一次);之后的每一帧都进行如下操作:遍历图像每个像素,对HSV 分量和黑线相近的像素进行标注,然后对标注后的区域去噪,去噪后,对此区域进行中心点的计算。每一帧结束都会将计算所得的中心坐标发送给舵机控制模块。在标注过程中,假如背景有黑色区域,就会产生噪声。本系统去噪、降噪的策略有两个方面:
1. 形态学处理,直接去除面积较小的噪点;2. 设置权值的概念,降低较大噪点影响。对于权值降噪,运用一个权值计算算法,中心点的计算会和权值相关。对于每一个标注像素,都计算此像素和上一帧得到的中心点的距离,根据距离远近设定不同大小的权值,越接近中心的标注像素,权值越大,否则越小。这样就会降低和捕捉物体距离较远,但面积较大的噪点的影响。
二、核心部件电路设计
1、关键器件性能分析
ov7725摄像头捕捉测试
拍摄测试路线的图像通过VGA 接口接显示器显示图像如2-1图所示
图2-1 摄像头捕捉图像
2、关键电路驱动接口
(1)ov7725摄像头电路如图2-2所示
图2-2 摄像头电路图
(2)模数转换模块电路如图2-3所示
图2-3 ADC电路图
三、系统软件设计分析
1、系统总体设计
主程序流程图如图3-1所示
图3-1 主程序流程图
系统分为FPGA 主控制器、摄像头采集、数据缓存机构、图像捕捉识别机构、图像追踪机构、VGA 显示模块、舵机驱动模块以及反馈模块。
(1)FPGA 主控制器:完成采集和信号处理等核心计算。
(2)摄像头采集机构:完成摄像头的数据采集。
(3)数据缓存机构:通过双扣ram 来缓存采集到的数据。
(4)图像捕捉识别机构:捕捉特定区间的画面用来对比
(5)图像追踪机构:与图像捕捉的特定区间进行比较,以此来追踪图像
(6)VGA 显示模块:现实摄像头拍摄和捕捉到的画面
(7)舵机驱动模块:生成pwm 波控制舵机和电机
(8)反馈模块:反馈舵机的角度和当前追踪的位置运用PID 算法进行闭环控制
2、关键模块的主要代码
(1)顶层设计文件如图所示
图3-2 顶层模块图
module design_1_wrapper
(Config_Done,
Move_EN,
OV7725_D,
OV7725_HREF,
OV7725_PCLK,
OV7725_SIOC,
OV7725_SIOD,
OV7725_VSYNC,
OV7725_XCLK,
btn_ColorExtract,
clk100,
pwm_out_x,
pwm_out_y,
rst,
sw_ColorClear,
vauxn14,
vauxn6,
vauxn7,
vauxp14,
vauxp15,
vauxp6,
vauxp7,
vga_blue,
vga_green,
vga_hsync,
vga_red,
vga_vsync);
output Config_Done;
input Move_EN;
input [7:0]OV7725_D;
input OV7725_HREF;
input OV7725_PCLK;
output OV7725_SIOC;
inout OV7725_SIOD;
input OV7725_VSYNC;
output OV7725_XCLK;
input btn_ColorExtract;
input clk100;
output pwm_out_x;
output pwm_out_y;
input rst;
input sw_ColorClear;
input vauxn14;
input vauxn15;
input vauxn6;
input vauxp14;
input vauxp15;
input vauxp6;
input vauxp7;
output [3:0]vga_blue;
output [3:0]vga_green;
output vga_hsync;
output [3:0]vga_red;
output vga_vsync;
wire Config_Done;
wire Move_EN;
wire [7:0]OV7725_D;
wire OV7725_HREF;
wire OV7725_PCLK;
wire OV7725_SIOC;
wire OV7725_SIOD;
wire OV7725_VSYNC;
wire OV7725_XCLK;
wire btn_ColorExtract;
wire clk100;
wire pwm_out_x;
wire pwm_out_y;
wire rst;
wire sw_ColorClear;
wire vauxn14;
wire vauxn15;
wire vauxn6;
wire vauxn7;
wire vauxp15;
wire vauxp6;
wire vauxp7;
wire [3:0]vga_blue;
wire [3:0]vga_green;
wire vga_hsync;
wire [3:0]vga_red;
wire vga_vsync;
design_1 design_1_i
(.Config_Done(Config_Done), .Move_EN(Move_EN),
.OV7725_D(OV7725_D),
.OV7725_HREF(OV7725_HREF), .OV7725_PCLK(OV7725_PCLK), .OV7725_SIOC(OV7725_SIOC), .OV7725_SIOD(OV7725_SIOD), .OV7725_VSYNC(OV7725_VSYNC), .OV7725_XCLK(OV7725_XCLK),
.btn_ColorExtract(btn_ColorExtract), .clk100(clk100),
.pwm_out_x(pwm_out_x), .pwm_out_y(pwm_out_y), .rst(rst),
.sw_ColorClear(sw_ColorClear), .vauxn14(vauxn14),
.vauxn15(vauxn15),
.vauxn6(vauxn6),
.vauxn7(vauxn7),
.vauxp14(vauxp14), .vauxp15(vauxp15), .vauxp6(vauxp6), .vauxp7(vauxp7), .vga_blue(vga_blue), .vga_green(vga_green), .vga_hsync(vga_hsync), .vga_red(vga_red),
.vga_vsync(vga_vsync)); endmodule
(2)摄像头ov7725模块
图3-3 ov7725模块
module design_1_cam_ov7725_0_0 ( pclk,
vsync,
href,
d,
H_cnt,
V_cnt,
addr,
dout,
we,
wclk
);
input wire pclk;
input wire vsync;
input wire href;
input wire [7 : 0] d;
output wire [11 : 0] H_cnt;
output wire [10 : 0] V_cnt;
output wire [16 : 0] addr;
output wire [15 : 0] dout;
output wire we;
output wire wclk;
cam_ov7725 inst (
.pclk(pclk),
.vsync(vsync),
.href(href),
.d(d),
.H_cnt(H_cnt),
.V_cnt(V_cnt),
.addr(addr),
.dout(dout),
.we(we),
.wclk(wclk) module cam_ov7670_ov7725(
input pclk,
input vsync,
input href,
input[7:0] d,
output [11:0]H_cnt,
output [10:0]V_cnt,
output[16:0] addr,
output reg[15:0] dout,
output reg we,
output wclk
);
reg [15:0] d_latch;
reg [16:0] address;
reg [16:0] address_next;
reg [1:0] wr_hold;
reg [1:0] cnt;
initial d_latch = 16'b0;
initial address = 19'b0;
initial address_next = 19'b0;
initial wr_hold = 2'b0;
initial cnt = 2'b0;
assign addr = address;
assign wclk = pclk;
reg[9:0]hcnt,vcnt,href_post;
assign H_cnt = (hcnt/2>=0&&hcnt/2
assign V_cnt = (vcnt>=0&&vcnt
always@(posedge pclk)begin
if( vsync ==1) begin
address
address_next
wr_hold
cnt
else begin
if(address
address
else
address
we
wr_hold
d_latch
if (wr_hold[1] ==1 )begin
address_next
dout[15:0]
end;
end
always@(posedge pclk)begin
if( vsync ==1) begin
vcnt
hcnt
end
else begin
if ({href_post,href}==2'b10 )begin
vcnt
hcnt
end
if(href ==1 )begin
hcnt
end
end
end
endmodule
(3)舵机控制模块
图3-4 舵机控制模块
module design_1_servo_ctrl_0_0 (
vsync_in,
x,
y,
ad_data_x,
ad_data_y,
duty_x,
duty_y
);
input wire vsync_in;
input wire [11 : 0] x;
input wire [10 : 0] y;
input wire [15 : 0] ad_data_x;
input wire [15 : 0] ad_data_y;
output wire [14 : 0] duty_x;
output wire [14 : 0] duty_y;
servo_ctrl inst (
.vsync_in(vsync_in),
.x(x),
.y(y),
.ad_data_x(ad_data_x),
.ad_data_y(ad_data_y),
.duty_x(duty_x),
.duty_y(duty_y)
module design_1_servo_ctrl_0_0 (
vsync_in,
x,
y,
ad_data_x,
ad_data_y,
duty_x,
duty_y
);
input wire vsync_in;
input wire [11 : 0] x;
input wire [10 : 0] y;
input wire [15 : 0] ad_data_x;
input wire [15 : 0] ad_data_y;
output wire [14 : 0] duty_x;
output wire [14 : 0] duty_y;
servo_ctrl inst (
.vsync_in(vsync_in),
.x(x),
.y(y),
.ad_data_x(ad_data_x),
.ad_data_y(ad_data_y),
.duty_x(duty_x),
.duty_y(duty_y)
(4)模数转换、闭环反馈模块
图3-5 ADC模块
module xadc(
input clk100, // Clock input for DRP
input rst,
input vauxp6, vauxn6, // Auxiliary analog channel inputs input vauxp7, vauxn7, // Auxiliary analog channel inputs input vauxp14, vauxn14, // Auxiliary analog channel inputs input vauxp15, vauxn15, // Auxiliary analog channel inputs
output [15:0] temperature_out,
output [15:0] aux_out_6,aux_out_7,aux_out_14,aux_out_15 );
reg [15:0] MEASURED_TEMP;
reg [15:0] MEASURED_AUX0, MEASURED_AUX1;
reg [15:0] MEASURED_AUX2, MEASURED_AUX3;
reg [15:0] MEASURED_VCCINT,MEASURED_VCCAUX,MEASURED_VCCBRAM;
assign aux_out_14 = MEASURED_AUX0;
assign aux_out_15 = MEASURED_AUX1;
assign aux_out_6 = MEASURED_AUX2;
assign aux_out_7 = MEASURED_AUX3;
assign temperature_out = MEASURED_TEMP;
wire busy;
wire [5:0] channel;
wire drdy;
wire eoc;
wire eos;
wire i2c_sclk_in;
wire i2c_sclk_ts;
wire i2c_sda_in;
wire i2c_sda_ts;
reg [6:0] daddr;
reg [15:0] di_drp;
wire [15:0] do_drp;
wire [15:0] vauxp_active;
wire [15:0] vauxn_active;
wire dclk_bufg;
reg [1:0] den_reg;
reg [1:0] dwe_reg;
reg [7:0] state = init_read;
parameter init_read = 8'h00,
read_waitdrdy = 8'h01,
write_waitdrdy = 8'h03,
read_reg00 = 8'h04,
reg00_waitdrdy = 8'h05,
read_reg01 = 8'h06,
reg01_waitdrdy = 8'h07,
read_reg02 = 8'h08,
reg02_waitdrdy = 8'h09,
read_reg06 = 8'h0a,
reg06_waitdrdy = 8'h0b,
read_reg10 = 8'h0c,
reg10_waitdrdy = 8'h0d,
read_reg11 = 8'h0e,
reg11_waitdrdy = 8'h0f,
read_reg12 = 8'h10,
reg12_waitdrdy = 8'h11,
read_reg13 = 8'h12,
reg13_waitdrdy = 8'h13;
BUFG i_bufg (.I(clk100), .O(dclk_bufg));
always @(posedge dclk_bufg)
if (rst) begin
state
den_reg
dwe_reg
di_drp
end
else
case (state)
init_read : begin
daddr
den_reg
if (busy == 0 ) state
end
read_waitdrdy :
if (eos ==1) begin
di_drp
den_reg
dwe_reg
end
else begin
den_reg
write_waitdrdy :
if (drdy ==1) begin
state
end
else begin
den_reg
dwe_reg
end
read_reg00 : begin
daddr
den_reg
if (eos == 1) state
reg00_waitdrdy :
if (drdy ==1) begin
MEASURED_TEMP
state
end
else begin
den_reg
dwe_reg
end
read_reg01 : begin
daddr
den_reg
end
reg01_waitdrdy :
if (drdy ==1) begin
MEASURED_VCCINT = do_drp;
state
end
else begin
den_reg
dwe_reg
end
read_reg02 : begin
daddr
den_reg
end
reg02_waitdrdy :
if (drdy ==1) begin
MEASURED_VCCAUX
state
end
else begin
den_reg
dwe_reg
end
read_reg06 : begin
daddr
den_reg
end
reg06_waitdrdy :
if (drdy ==1) begin
MEASURED_VCCBRAM
state
end
else begin
den_reg
dwe_reg
end
read_reg10 : begin
daddr
den_reg
end
reg10_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX0
state
end
else begin
den_reg
dwe_reg
end
read_reg11 : begin
daddr
den_reg
end
reg11_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX1
state
end
else begin
den_reg
dwe_reg
end
read_reg12 : begin
daddr
den_reg
end
reg12_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX2
state
end
else begin
den_reg
dwe_reg
end
read_reg13 : begin
daddr
den_reg
state
end
reg13_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX3
state
daddr
end
else begin
den_reg
dwe_reg
end
default : begin
daddr
den_reg
end
endcase
xadc_wiz_0 u_xadc (
.di_in(di_drp), // input wire [15 : 0] di_in
.daddr_in(daddr), // input wire [6 : 0] daddr_in
.den_in(den_reg[0]), // input wire den_in
.dwe_in(dwe_reg[0]), // input wire dwe_in
.drdy_out(drdy), // output wire drdy_out
.do_out(do_drp), // output wire [15 : 0] do_out
.dclk_in(dclk_bufg), // input wire dclk_in
.reset_in(rst),
.vp_in(), // input wire vp_in
.vn_in(), // input wire vn_in
.vauxp6(vauxp6), // input wire vauxp6
.vauxn6(vauxn6), // input wire vauxn6
.vauxp7(vauxp7), // input wire vauxp7
.vauxn7(vauxn7), // input wire vauxn7
.vauxp14(vauxp14), // input wire vauxp14
.vauxn14(vauxn14), // input wire vauxn14
.vauxp15(vauxp15), // input wire vauxp15
.vauxn15(vauxn15), // input wire vauxn15
.channel_out(channel_out), // output wire [4 : 0] channel_out .eoc_out(eoc), // output wire eoc_out
.alarm_out(alarm_out), // output wire alarm_out
.eos_out(eos), // output wire eos_out
.busy_out(busy) // output wire busy_out
);
module xadc_wiz_0
(
daddr_in, //
dclk_in, //
den_in, // Enable Signal for the dynamic reconfiguration port
di_in, // Input data bus for the dynamic reconfiguration port
dwe_in, // Write Enable for the dynamic reconfiguration port
reset_in, //
vauxp6, // Auxiliary channel 6
vauxn6,
vauxp7, // Auxiliary channel 7
vauxn7,
vauxp14, // Auxiliary channel 14
vauxn14, Address bus for the dynamic reconfiguration port Clock input for the dynamic reconfiguration port Reset signal for the System Monitor control logic
vauxp15, // Auxiliary channel 15
vauxn15,
busy_out, // ADC Busy signal
channel_out, // Channel Selection Outputs
do_out, // Output data bus for dynamic reconfiguration port drdy_out, // Data ready signal for the dynamic
reconfiguration port
eoc_out, // End of Conversion Signal
eos_out, // End of Sequence Signal
ot_out, // Over-Temperature alarm output
vccaux_alarm_out, // VCCAUX-sensor alarm output
vccint_alarm_out, // VCCINT-sensor alarm output
user_temp_alarm_out, // Temperature-sensor alarm output
alarm_out, // OR'ed output of all the Alarms
vp_in, // Dedicated Analog Input Pair
vn_in);
input [6:0] daddr_in;
input dclk_in;
input den_in;
input [15:0] di_in;
input dwe_in;
input reset_in;
input vauxp6;
input vauxn6;
input vauxp7;
input vauxn7;
input vauxp14;
input vauxn14;
input vauxp15;
input vauxn15;
input vp_in;
input vn_in;
output busy_out;
output [4:0] channel_out;
output [15:0] do_out;
output drdy_out;
output eoc_out;
output eos_out;
output ot_out;
output vccaux_alarm_out;
output vccint_alarm_out;
output user_temp_alarm_out;
output alarm_out;
wire GND_BIT;
assign GND_BIT = 0;
wire [15:0] aux_channel_p;
wire [15:0] aux_channel_n;
wire [7:0] alm_int;
assign alarm_out = alm_int[7];
assign vccaux_alarm_out = alm_int[2];
assign vccint_alarm_out = alm_int[1];
assign user_temp_alarm_out = alm_int[0]; assign aux_channel_p[0] = 1'b0;
assign aux_channel_n[0] = 1'b0;
assign aux_channel_p[1] = 1'b0;
assign aux_channel_n[1] = 1'b0;
assign aux_channel_p[2] = 1'b0;
assign aux_channel_n[2] = 1'b0;
assign aux_channel_p[3] = 1'b0;
assign aux_channel_n[3] = 1'b0;
assign aux_channel_p[4] = 1'b0;
assign aux_channel_n[4] = 1'b0;
assign aux_channel_p[5] = 1'b0;
assign aux_channel_n[5] = 1'b0;
assign aux_channel_p[6] = vauxp6;
assign aux_channel_n[6] = vauxn6;
assign aux_channel_p[7] = vauxp7;
assign aux_channel_n[7] = vauxn7;
assign aux_channel_p[8] = 1'b0;
assign aux_channel_n[8] = 1'b0;
assign aux_channel_p[9] = 1'b0;
assign aux_channel_n[9] = 1'b0;
assign aux_channel_p[10] = 1'b0;
assign aux_channel_n[10] = 1'b0;
assign aux_channel_p[11] = 1'b0;
assign aux_channel_n[11] = 1'b0;
assign aux_channel_p[12] = 1'b0;
assign aux_channel_n[12] = 1'b0;
assign aux_channel_p[13] = 1'b0;
assign aux_channel_n[13] = 1'b0;
assign aux_channel_p[14] = vauxp14;
assign aux_channel_n[14] = vauxn14;
assign aux_channel_p[15] = vauxp15;
assign aux_channel_n[15] = vauxn15;
XADC #(
.INIT_40(16'h9000), // config reg 0
.INIT_41(16'h21F0), // config reg 1
.INIT_42(16'h0400), // config reg 2
.INIT_48(16'h4701), // Sequencer channel selection .INIT_49(16'hC0C0), // Sequencer channel selection .INIT_4A(16'h0000), // Sequencer Average selection .INIT_4B(16'h0000), // Sequencer Average selection .INIT_4C(16'h0000), // Sequencer Bipolar selection .INIT_4D(16'h0000), // Sequencer Bipolar selection .INIT_4E(16'h0000), // Sequencer Acq time selection .INIT_4F(16'h0000), // Sequencer Acq time selection .INIT_50(16'hB5ED), // Temp alarm trigger
.INIT_51(16'h57E4), // Vccint upper alarm limit .INIT_52(16'hA147), // Vccaux upper alarm limit .INIT_53(16'hCA33), // Temp alarm OT upper .INIT_54(16'hA93A), // Temp alarm reset
.INIT_55(16'h52C6), // Vccint lower alarm limit .INIT_56(16'h9555), // Vccaux lower alarm limit .INIT_57(16'hAE4E), // Temp alarm OT reset
.INIT_58(16'h5999), // VCCBRAM upper alarm limit .INIT_5C(16'h5111), // VCCBRAM lower alarm limit .SIM_DEVICE("7SERIES"),
)
inst (
.CONVST(GND_BIT),
.CONVSTCLK(GND_BIT), .DADDR(daddr_in[6:0]), .DCLK(dclk_in),
.DEN(den_in),
.DI(di_in[15:0]),
.DWE(dwe_in),
.RESET(reset_in),
.VAUXN(aux_channel_n[15:0]), .VAUXP(aux_channel_p[15:0]), .ALM(alm_int),
.BUSY(busy_out),
.CHANNEL(channel_out[4:0]), .DO(do_out[15:0]),
.DRDY(drdy_out),
.EOC(eoc_out),
.EOS(eos_out),
.JTAGBUSY(),
.JTAGLOCKED(),
.JTAGMODIFIED(),
.OT(ot_out),
.MUXADDR(),
.VP(vp_in),
.VN(vn_in)
);
endmodule
四、作品成效总结分析
1、系统心能指标测试
系统性能指标测试如图4-1、4-2、4-3、4-4所示
图4-1
捕捉画面图
图4-2 小车实物图
图4-3 小车实物图
图4-4 小车实物图
2、创新特色总结展望
从原来的单纯的只是二值化识别黑白进展到图像的直接识别,不仅可以追踪黑线还可以对物体以及人进行了追踪。
基于图像传感器的小车循迹控制
常州工学院
制作学生:杨义鹏,杨锟,高星宇
指导老师:肖闽进,蔡纪鹤,马金祥
一、设计方案工作原理
1、摄像头图像识别的循迹小车设计背景
当前,实用的图像处理系统都要求高速处理。目前广泛采用软件进行处理,但软件处理存在速度、成本的问题。近年来,随着现成可编程门阵列FPGA 的发展,为提高图像处理系统的性能提供了新的思路和方法。FPGA 的并行特性所带来的高速性,以及低成本低功耗等特性,都是计算机无法比拟的。
摄像头循迹小车的FPGA 以及PCB 部分采用digilent 公司Basys3 FPGA 开发板作为控制核心,此款开发板采用xilinx 7系列芯片,板卡设计小巧,同时片上资源也足以满足大多教学应用场合。
2、预期实现目标定位
设计并制作基于basys3的FPGA 运用ov7725摄像头进行图像识别的循迹小车,能够拍摄画面并经行捕捉,在小车偏离赛道时进行控制使其能够完成循迹的目的。
3、技术方案分析比较
方案1:采用带fifo 的ov7670摄像头做二值化循迹
图1-1带fifo 的ov7670摄像头
该摄像头自带fifo 模块,是针对慢速的MCU 能够实现图像采集控制推出的带有缓冲存储空间的一种模块,自带的fifo(先进先出)存储芯片使得处理图像拍摄数据存储时避免了SDRAM 、DDR 的使用,包含30w 像素的图像感光芯片,操作和使用很方便,对读出的数据进行二值化处理,加上阈值后可以进行循迹使用。
方案2:采用带硬件二值化的ov7725摄像头做二值化循迹
图1-2 带硬件二值化的ov7725摄像头
此摄像头自带硬件二值化可以直接输出二值化后的0和1黑白图像,并且采样和输出速度要高于ov7670, 在进行黑线循迹时优化二值化算法使得循迹变得简单。 方案3:采用ov7725摄像头进行图像捕捉
此摄像头相对于ov7670的优点仍为高速的采样和输出速度,相对于带有硬件二值化摄像头丧失了二值化的优势但是可以摒弃二值化单纯只能循迹黑线的问题,进行图像识别而可以直接对物体进行图像捕捉,增加了使用的范围。
最后选用方案及理由:采用带fifo 的ov7725摄像头,原因为相比于ov7670摄像头,其处理速度更加快,相比于带硬件二值化的摄像头其可以做的不仅仅为简单的二值化循迹,可以上升到图像识别和捕捉的层面从而可以满足更多的需要。
4、系统结构工作原理
系统的总体框图如图所示
图1-3 系统结构工作原理
5、功能指标和实现方法
(1)通过ov7725摄像头拍摄画面
采用ov7725摄像头,对画面进行初步处理,检测能否拍到数据为后续的图像处理和控制打下基础。
(2)对ov7725捕捉到的画面进行像素转换 首先将采集到的RGB 像素,转换成HSV 像素,由于RGB 色空间和HSV 空间之间的转换为非线性的,硬件实现需要考虑时钟同步、算法优化、实时性等问题。采用了低延迟的除法器实现Hue 分量与Saturation 分量的高速计算,从而实现了RGB 转换成HSV 。
(3)进行色彩提取和坐标计算
原理是应用了色彩方面的理论,寻找类似黑线色彩的区域,然后计算这个区域的中心。首先需要人为提取黑线的HSV 分量(只提取一次);之后的每一帧都进行如下操作:遍历图像每个像素,对HSV 分量和黑线相近的像素进行标注,然后对标注后的区域去噪,去噪后,对此区域进行中心点的计算。每一帧结束都会将计算所得的中心坐标发送给舵机控制模块。在标注过程中,假如背景有黑色区域,就会产生噪声。本系统去噪、降噪的策略有两个方面:
1. 形态学处理,直接去除面积较小的噪点;2. 设置权值的概念,降低较大噪点影响。对于权值降噪,运用一个权值计算算法,中心点的计算会和权值相关。对于每一个标注像素,都计算此像素和上一帧得到的中心点的距离,根据距离远近设定不同大小的权值,越接近中心的标注像素,权值越大,否则越小。这样就会降低和捕捉物体距离较远,但面积较大的噪点的影响。
二、核心部件电路设计
1、关键器件性能分析
ov7725摄像头捕捉测试
拍摄测试路线的图像通过VGA 接口接显示器显示图像如2-1图所示
图2-1 摄像头捕捉图像
2、关键电路驱动接口
(1)ov7725摄像头电路如图2-2所示
图2-2 摄像头电路图
(2)模数转换模块电路如图2-3所示
图2-3 ADC电路图
三、系统软件设计分析
1、系统总体设计
主程序流程图如图3-1所示
图3-1 主程序流程图
系统分为FPGA 主控制器、摄像头采集、数据缓存机构、图像捕捉识别机构、图像追踪机构、VGA 显示模块、舵机驱动模块以及反馈模块。
(1)FPGA 主控制器:完成采集和信号处理等核心计算。
(2)摄像头采集机构:完成摄像头的数据采集。
(3)数据缓存机构:通过双扣ram 来缓存采集到的数据。
(4)图像捕捉识别机构:捕捉特定区间的画面用来对比
(5)图像追踪机构:与图像捕捉的特定区间进行比较,以此来追踪图像
(6)VGA 显示模块:现实摄像头拍摄和捕捉到的画面
(7)舵机驱动模块:生成pwm 波控制舵机和电机
(8)反馈模块:反馈舵机的角度和当前追踪的位置运用PID 算法进行闭环控制
2、关键模块的主要代码
(1)顶层设计文件如图所示
图3-2 顶层模块图
module design_1_wrapper
(Config_Done,
Move_EN,
OV7725_D,
OV7725_HREF,
OV7725_PCLK,
OV7725_SIOC,
OV7725_SIOD,
OV7725_VSYNC,
OV7725_XCLK,
btn_ColorExtract,
clk100,
pwm_out_x,
pwm_out_y,
rst,
sw_ColorClear,
vauxn14,
vauxn6,
vauxn7,
vauxp14,
vauxp15,
vauxp6,
vauxp7,
vga_blue,
vga_green,
vga_hsync,
vga_red,
vga_vsync);
output Config_Done;
input Move_EN;
input [7:0]OV7725_D;
input OV7725_HREF;
input OV7725_PCLK;
output OV7725_SIOC;
inout OV7725_SIOD;
input OV7725_VSYNC;
output OV7725_XCLK;
input btn_ColorExtract;
input clk100;
output pwm_out_x;
output pwm_out_y;
input rst;
input sw_ColorClear;
input vauxn14;
input vauxn15;
input vauxn6;
input vauxp14;
input vauxp15;
input vauxp6;
input vauxp7;
output [3:0]vga_blue;
output [3:0]vga_green;
output vga_hsync;
output [3:0]vga_red;
output vga_vsync;
wire Config_Done;
wire Move_EN;
wire [7:0]OV7725_D;
wire OV7725_HREF;
wire OV7725_PCLK;
wire OV7725_SIOC;
wire OV7725_SIOD;
wire OV7725_VSYNC;
wire OV7725_XCLK;
wire btn_ColorExtract;
wire clk100;
wire pwm_out_x;
wire pwm_out_y;
wire rst;
wire sw_ColorClear;
wire vauxn14;
wire vauxn15;
wire vauxn6;
wire vauxn7;
wire vauxp15;
wire vauxp6;
wire vauxp7;
wire [3:0]vga_blue;
wire [3:0]vga_green;
wire vga_hsync;
wire [3:0]vga_red;
wire vga_vsync;
design_1 design_1_i
(.Config_Done(Config_Done), .Move_EN(Move_EN),
.OV7725_D(OV7725_D),
.OV7725_HREF(OV7725_HREF), .OV7725_PCLK(OV7725_PCLK), .OV7725_SIOC(OV7725_SIOC), .OV7725_SIOD(OV7725_SIOD), .OV7725_VSYNC(OV7725_VSYNC), .OV7725_XCLK(OV7725_XCLK),
.btn_ColorExtract(btn_ColorExtract), .clk100(clk100),
.pwm_out_x(pwm_out_x), .pwm_out_y(pwm_out_y), .rst(rst),
.sw_ColorClear(sw_ColorClear), .vauxn14(vauxn14),
.vauxn15(vauxn15),
.vauxn6(vauxn6),
.vauxn7(vauxn7),
.vauxp14(vauxp14), .vauxp15(vauxp15), .vauxp6(vauxp6), .vauxp7(vauxp7), .vga_blue(vga_blue), .vga_green(vga_green), .vga_hsync(vga_hsync), .vga_red(vga_red),
.vga_vsync(vga_vsync)); endmodule
(2)摄像头ov7725模块
图3-3 ov7725模块
module design_1_cam_ov7725_0_0 ( pclk,
vsync,
href,
d,
H_cnt,
V_cnt,
addr,
dout,
we,
wclk
);
input wire pclk;
input wire vsync;
input wire href;
input wire [7 : 0] d;
output wire [11 : 0] H_cnt;
output wire [10 : 0] V_cnt;
output wire [16 : 0] addr;
output wire [15 : 0] dout;
output wire we;
output wire wclk;
cam_ov7725 inst (
.pclk(pclk),
.vsync(vsync),
.href(href),
.d(d),
.H_cnt(H_cnt),
.V_cnt(V_cnt),
.addr(addr),
.dout(dout),
.we(we),
.wclk(wclk) module cam_ov7670_ov7725(
input pclk,
input vsync,
input href,
input[7:0] d,
output [11:0]H_cnt,
output [10:0]V_cnt,
output[16:0] addr,
output reg[15:0] dout,
output reg we,
output wclk
);
reg [15:0] d_latch;
reg [16:0] address;
reg [16:0] address_next;
reg [1:0] wr_hold;
reg [1:0] cnt;
initial d_latch = 16'b0;
initial address = 19'b0;
initial address_next = 19'b0;
initial wr_hold = 2'b0;
initial cnt = 2'b0;
assign addr = address;
assign wclk = pclk;
reg[9:0]hcnt,vcnt,href_post;
assign H_cnt = (hcnt/2>=0&&hcnt/2
assign V_cnt = (vcnt>=0&&vcnt
always@(posedge pclk)begin
if( vsync ==1) begin
address
address_next
wr_hold
cnt
else begin
if(address
address
else
address
we
wr_hold
d_latch
if (wr_hold[1] ==1 )begin
address_next
dout[15:0]
end;
end
always@(posedge pclk)begin
if( vsync ==1) begin
vcnt
hcnt
end
else begin
if ({href_post,href}==2'b10 )begin
vcnt
hcnt
end
if(href ==1 )begin
hcnt
end
end
end
endmodule
(3)舵机控制模块
图3-4 舵机控制模块
module design_1_servo_ctrl_0_0 (
vsync_in,
x,
y,
ad_data_x,
ad_data_y,
duty_x,
duty_y
);
input wire vsync_in;
input wire [11 : 0] x;
input wire [10 : 0] y;
input wire [15 : 0] ad_data_x;
input wire [15 : 0] ad_data_y;
output wire [14 : 0] duty_x;
output wire [14 : 0] duty_y;
servo_ctrl inst (
.vsync_in(vsync_in),
.x(x),
.y(y),
.ad_data_x(ad_data_x),
.ad_data_y(ad_data_y),
.duty_x(duty_x),
.duty_y(duty_y)
module design_1_servo_ctrl_0_0 (
vsync_in,
x,
y,
ad_data_x,
ad_data_y,
duty_x,
duty_y
);
input wire vsync_in;
input wire [11 : 0] x;
input wire [10 : 0] y;
input wire [15 : 0] ad_data_x;
input wire [15 : 0] ad_data_y;
output wire [14 : 0] duty_x;
output wire [14 : 0] duty_y;
servo_ctrl inst (
.vsync_in(vsync_in),
.x(x),
.y(y),
.ad_data_x(ad_data_x),
.ad_data_y(ad_data_y),
.duty_x(duty_x),
.duty_y(duty_y)
(4)模数转换、闭环反馈模块
图3-5 ADC模块
module xadc(
input clk100, // Clock input for DRP
input rst,
input vauxp6, vauxn6, // Auxiliary analog channel inputs input vauxp7, vauxn7, // Auxiliary analog channel inputs input vauxp14, vauxn14, // Auxiliary analog channel inputs input vauxp15, vauxn15, // Auxiliary analog channel inputs
output [15:0] temperature_out,
output [15:0] aux_out_6,aux_out_7,aux_out_14,aux_out_15 );
reg [15:0] MEASURED_TEMP;
reg [15:0] MEASURED_AUX0, MEASURED_AUX1;
reg [15:0] MEASURED_AUX2, MEASURED_AUX3;
reg [15:0] MEASURED_VCCINT,MEASURED_VCCAUX,MEASURED_VCCBRAM;
assign aux_out_14 = MEASURED_AUX0;
assign aux_out_15 = MEASURED_AUX1;
assign aux_out_6 = MEASURED_AUX2;
assign aux_out_7 = MEASURED_AUX3;
assign temperature_out = MEASURED_TEMP;
wire busy;
wire [5:0] channel;
wire drdy;
wire eoc;
wire eos;
wire i2c_sclk_in;
wire i2c_sclk_ts;
wire i2c_sda_in;
wire i2c_sda_ts;
reg [6:0] daddr;
reg [15:0] di_drp;
wire [15:0] do_drp;
wire [15:0] vauxp_active;
wire [15:0] vauxn_active;
wire dclk_bufg;
reg [1:0] den_reg;
reg [1:0] dwe_reg;
reg [7:0] state = init_read;
parameter init_read = 8'h00,
read_waitdrdy = 8'h01,
write_waitdrdy = 8'h03,
read_reg00 = 8'h04,
reg00_waitdrdy = 8'h05,
read_reg01 = 8'h06,
reg01_waitdrdy = 8'h07,
read_reg02 = 8'h08,
reg02_waitdrdy = 8'h09,
read_reg06 = 8'h0a,
reg06_waitdrdy = 8'h0b,
read_reg10 = 8'h0c,
reg10_waitdrdy = 8'h0d,
read_reg11 = 8'h0e,
reg11_waitdrdy = 8'h0f,
read_reg12 = 8'h10,
reg12_waitdrdy = 8'h11,
read_reg13 = 8'h12,
reg13_waitdrdy = 8'h13;
BUFG i_bufg (.I(clk100), .O(dclk_bufg));
always @(posedge dclk_bufg)
if (rst) begin
state
den_reg
dwe_reg
di_drp
end
else
case (state)
init_read : begin
daddr
den_reg
if (busy == 0 ) state
end
read_waitdrdy :
if (eos ==1) begin
di_drp
den_reg
dwe_reg
end
else begin
den_reg
write_waitdrdy :
if (drdy ==1) begin
state
end
else begin
den_reg
dwe_reg
end
read_reg00 : begin
daddr
den_reg
if (eos == 1) state
reg00_waitdrdy :
if (drdy ==1) begin
MEASURED_TEMP
state
end
else begin
den_reg
dwe_reg
end
read_reg01 : begin
daddr
den_reg
end
reg01_waitdrdy :
if (drdy ==1) begin
MEASURED_VCCINT = do_drp;
state
end
else begin
den_reg
dwe_reg
end
read_reg02 : begin
daddr
den_reg
end
reg02_waitdrdy :
if (drdy ==1) begin
MEASURED_VCCAUX
state
end
else begin
den_reg
dwe_reg
end
read_reg06 : begin
daddr
den_reg
end
reg06_waitdrdy :
if (drdy ==1) begin
MEASURED_VCCBRAM
state
end
else begin
den_reg
dwe_reg
end
read_reg10 : begin
daddr
den_reg
end
reg10_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX0
state
end
else begin
den_reg
dwe_reg
end
read_reg11 : begin
daddr
den_reg
end
reg11_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX1
state
end
else begin
den_reg
dwe_reg
end
read_reg12 : begin
daddr
den_reg
end
reg12_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX2
state
end
else begin
den_reg
dwe_reg
end
read_reg13 : begin
daddr
den_reg
state
end
reg13_waitdrdy :
if (drdy ==1) begin
MEASURED_AUX3
state
daddr
end
else begin
den_reg
dwe_reg
end
default : begin
daddr
den_reg
end
endcase
xadc_wiz_0 u_xadc (
.di_in(di_drp), // input wire [15 : 0] di_in
.daddr_in(daddr), // input wire [6 : 0] daddr_in
.den_in(den_reg[0]), // input wire den_in
.dwe_in(dwe_reg[0]), // input wire dwe_in
.drdy_out(drdy), // output wire drdy_out
.do_out(do_drp), // output wire [15 : 0] do_out
.dclk_in(dclk_bufg), // input wire dclk_in
.reset_in(rst),
.vp_in(), // input wire vp_in
.vn_in(), // input wire vn_in
.vauxp6(vauxp6), // input wire vauxp6
.vauxn6(vauxn6), // input wire vauxn6
.vauxp7(vauxp7), // input wire vauxp7
.vauxn7(vauxn7), // input wire vauxn7
.vauxp14(vauxp14), // input wire vauxp14
.vauxn14(vauxn14), // input wire vauxn14
.vauxp15(vauxp15), // input wire vauxp15
.vauxn15(vauxn15), // input wire vauxn15
.channel_out(channel_out), // output wire [4 : 0] channel_out .eoc_out(eoc), // output wire eoc_out
.alarm_out(alarm_out), // output wire alarm_out
.eos_out(eos), // output wire eos_out
.busy_out(busy) // output wire busy_out
);
module xadc_wiz_0
(
daddr_in, //
dclk_in, //
den_in, // Enable Signal for the dynamic reconfiguration port
di_in, // Input data bus for the dynamic reconfiguration port
dwe_in, // Write Enable for the dynamic reconfiguration port
reset_in, //
vauxp6, // Auxiliary channel 6
vauxn6,
vauxp7, // Auxiliary channel 7
vauxn7,
vauxp14, // Auxiliary channel 14
vauxn14, Address bus for the dynamic reconfiguration port Clock input for the dynamic reconfiguration port Reset signal for the System Monitor control logic
vauxp15, // Auxiliary channel 15
vauxn15,
busy_out, // ADC Busy signal
channel_out, // Channel Selection Outputs
do_out, // Output data bus for dynamic reconfiguration port drdy_out, // Data ready signal for the dynamic
reconfiguration port
eoc_out, // End of Conversion Signal
eos_out, // End of Sequence Signal
ot_out, // Over-Temperature alarm output
vccaux_alarm_out, // VCCAUX-sensor alarm output
vccint_alarm_out, // VCCINT-sensor alarm output
user_temp_alarm_out, // Temperature-sensor alarm output
alarm_out, // OR'ed output of all the Alarms
vp_in, // Dedicated Analog Input Pair
vn_in);
input [6:0] daddr_in;
input dclk_in;
input den_in;
input [15:0] di_in;
input dwe_in;
input reset_in;
input vauxp6;
input vauxn6;
input vauxp7;
input vauxn7;
input vauxp14;
input vauxn14;
input vauxp15;
input vauxn15;
input vp_in;
input vn_in;
output busy_out;
output [4:0] channel_out;
output [15:0] do_out;
output drdy_out;
output eoc_out;
output eos_out;
output ot_out;
output vccaux_alarm_out;
output vccint_alarm_out;
output user_temp_alarm_out;
output alarm_out;
wire GND_BIT;
assign GND_BIT = 0;
wire [15:0] aux_channel_p;
wire [15:0] aux_channel_n;
wire [7:0] alm_int;
assign alarm_out = alm_int[7];
assign vccaux_alarm_out = alm_int[2];
assign vccint_alarm_out = alm_int[1];
assign user_temp_alarm_out = alm_int[0]; assign aux_channel_p[0] = 1'b0;
assign aux_channel_n[0] = 1'b0;
assign aux_channel_p[1] = 1'b0;
assign aux_channel_n[1] = 1'b0;
assign aux_channel_p[2] = 1'b0;
assign aux_channel_n[2] = 1'b0;
assign aux_channel_p[3] = 1'b0;
assign aux_channel_n[3] = 1'b0;
assign aux_channel_p[4] = 1'b0;
assign aux_channel_n[4] = 1'b0;
assign aux_channel_p[5] = 1'b0;
assign aux_channel_n[5] = 1'b0;
assign aux_channel_p[6] = vauxp6;
assign aux_channel_n[6] = vauxn6;
assign aux_channel_p[7] = vauxp7;
assign aux_channel_n[7] = vauxn7;
assign aux_channel_p[8] = 1'b0;
assign aux_channel_n[8] = 1'b0;
assign aux_channel_p[9] = 1'b0;
assign aux_channel_n[9] = 1'b0;
assign aux_channel_p[10] = 1'b0;
assign aux_channel_n[10] = 1'b0;
assign aux_channel_p[11] = 1'b0;
assign aux_channel_n[11] = 1'b0;
assign aux_channel_p[12] = 1'b0;
assign aux_channel_n[12] = 1'b0;
assign aux_channel_p[13] = 1'b0;
assign aux_channel_n[13] = 1'b0;
assign aux_channel_p[14] = vauxp14;
assign aux_channel_n[14] = vauxn14;
assign aux_channel_p[15] = vauxp15;
assign aux_channel_n[15] = vauxn15;
XADC #(
.INIT_40(16'h9000), // config reg 0
.INIT_41(16'h21F0), // config reg 1
.INIT_42(16'h0400), // config reg 2
.INIT_48(16'h4701), // Sequencer channel selection .INIT_49(16'hC0C0), // Sequencer channel selection .INIT_4A(16'h0000), // Sequencer Average selection .INIT_4B(16'h0000), // Sequencer Average selection .INIT_4C(16'h0000), // Sequencer Bipolar selection .INIT_4D(16'h0000), // Sequencer Bipolar selection .INIT_4E(16'h0000), // Sequencer Acq time selection .INIT_4F(16'h0000), // Sequencer Acq time selection .INIT_50(16'hB5ED), // Temp alarm trigger
.INIT_51(16'h57E4), // Vccint upper alarm limit .INIT_52(16'hA147), // Vccaux upper alarm limit .INIT_53(16'hCA33), // Temp alarm OT upper .INIT_54(16'hA93A), // Temp alarm reset
.INIT_55(16'h52C6), // Vccint lower alarm limit .INIT_56(16'h9555), // Vccaux lower alarm limit .INIT_57(16'hAE4E), // Temp alarm OT reset
.INIT_58(16'h5999), // VCCBRAM upper alarm limit .INIT_5C(16'h5111), // VCCBRAM lower alarm limit .SIM_DEVICE("7SERIES"),
)
inst (
.CONVST(GND_BIT),
.CONVSTCLK(GND_BIT), .DADDR(daddr_in[6:0]), .DCLK(dclk_in),
.DEN(den_in),
.DI(di_in[15:0]),
.DWE(dwe_in),
.RESET(reset_in),
.VAUXN(aux_channel_n[15:0]), .VAUXP(aux_channel_p[15:0]), .ALM(alm_int),
.BUSY(busy_out),
.CHANNEL(channel_out[4:0]), .DO(do_out[15:0]),
.DRDY(drdy_out),
.EOC(eoc_out),
.EOS(eos_out),
.JTAGBUSY(),
.JTAGLOCKED(),
.JTAGMODIFIED(),
.OT(ot_out),
.MUXADDR(),
.VP(vp_in),
.VN(vn_in)
);
endmodule
四、作品成效总结分析
1、系统心能指标测试
系统性能指标测试如图4-1、4-2、4-3、4-4所示
图4-1
捕捉画面图
图4-2 小车实物图
图4-3 小车实物图
图4-4 小车实物图
2、创新特色总结展望
从原来的单纯的只是二值化识别黑白进展到图像的直接识别,不仅可以追踪黑线还可以对物体以及人进行了追踪。