之前在实验室参加了2020电赛,我选的是G题,测量平面物体的形状,尺寸,距离,便想分享一下自己的一些经验和总结一下教训。
G题我只会用OPENMV来做,要测2-3米所以买了个新的openmv和变焦镜头。
在openmv中有识别矩形和圆的例程,关于三角形虽没有现成的例程,但是也有相关的资料。
先提供相关资料和星瞳的教程
https://docs.singtown.com/micropython/zh/latest/openmvcam/index.html
https://book.openmv.cc/
刚开始想在openmv端直接判断出形状,但是发现判断误差形状的太大,所以只在openmv端同时采集多个形状的数据,通过串口发送数据给STM32来处理。
关于openmv与stm32通信的程序在我另一个博客中
openmv的程序很简单,只有两个注意点,1是openmv与主控板之间的通信,2是设置好roi区域 可以避免一些误判。
STM32与OPENMV通信
if(value == 1): # 判断形状及参数发送
for c in img.find_circles(roi=[50,30,190,190],threshold = 2000, x_margin = 2, y_margin = 2, r_margin = 10,
r_min = 60, r_max = 90, r_step = 1):
img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 0))
#print("circle",c)
cir = c.r()
cir_x = c.x()
cir_y = c.y()
for r in img.find_rects(roi=[50,20,190,180],threshold = 20000):
img.draw_rectangle(r.rect(), color = (0, 0, 0))
#print("rect",r)
rec_w = r.w()
rec_h = r.h()
rec_x = r.x()
rec_y = r.y()
for l in img.find_line_segments(roi=[60,40,150,150],merge_distance = 10, max_theta_diff = 10):
img.draw_line(l.line(), color = (0, 0, 255))
print("seg",l)
if i < 3:
buf[i] = l
i+=1
其实判断形状很简单,在stm32处理数据的时候就有一些细节需要注意。
圆其实很好判断,直径有值或者直径的值大于一定数字即可,但是有时候会把圆判断成矩形或者把矩形判断成圆,这与roi区域和光线有很大的关系。
if(Cir_R >=45&&taskone_state==0 &&(Rec_W<=10))
{
tasktwo_state=1; //圆形
taskthree_cnt[0]+=1;
if(taskthree_cnt[0]>100)
{
taskthree_cnt[0]=0;
figureisok=1;
}
以上代码就是在stm32判断圆的程序,因为判断只能进行一次所以需要一个标志位taskone_state,Rec_W是矩形的边长其作用是防止圆和矩形发生误判。
if(range(Angle1,Angle2,Angle3)&&(Cir_R<10)&&taskone_state==0&&(Rec_W>50))
{
tasktwo_state=2; //正方形
taskthree_cnt[1]+=1;
if(taskthree_cnt[1]>100)
{
taskthree_cnt[1]=0;
figureisok=2;
}
}
int range(u16 angle1, u16 angle2, u16 angle3)
{
u16 a;
if(angle1 < angle2)
{
a = angle1;
angle1 = angle2;
angle2 = a;
}
if(angle2 < angle3)
{
a = angle2;
angle2 = angle3;
angle3 = a;
}
if(angle1-angle2<=20 ||angle2-angle3<=20)
return 1;
else
return 0;
}
range这个函数是判断三个线段之间的夹角,我实际观察矩形和三角形的线段之间的夹角是有一定区别的,Cir_R 和Rec_W是圆的直径和矩形的宽,作用是防止误判和进一步确定。
if(Length1>10&&Length2>10&&Length3>10&&taskone_state==0&&Cir_R==0&&((Rec_W==0 )&&(Rec_H == 0)))
{
tasktwo_state=3; //三角形
taskthree_cnt[2]+=1;
if(taskthree_cnt[2]>100)
{
taskthree_cnt[2]=0;
figureisok=3;
}
}
Length1,2,3是三条线段的长度,后面的Cir_R,Rec_W是去排除圆和矩形。
拿openmv距离如同用openmv测量尺寸,误差太大,所以买了一个激光测距模块可以高精度测量3米的距离。
提供链接:vl531x激光测距
u16 Real_length(u16 D, u16 P)
{
单位像素点代表的长度 = 0.001198121x激光测得的距离
float K = 0.001198121*(1+(3000*0.55)/D);
length = K*D*P;
if((length <=300)||(length >=400 ))
{
length1 = 375;
}
else
length1 = length;
return length1;
}
u16 Real_len(u16 D, u16 P)
{
float K = 0.001198121,length = 0;
length = K*D*P;
if((length <=300)||(length >=400 ))
{
length2 = 360;
}
else
length2 = length;
return length2;
}