1.前言:

之前在实验室参加了2020电赛,我选的是G题,测量平面物体的形状,尺寸,距离,便想分享一下自己的一些经验和总结一下教训。

G题我只会用OPENMV来做,要测2-3米所以买了个新的openmv和变焦镜头。

在这里插入图片描述

2.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

3.stm32处理数据

其实判断形状很简单,在stm32处理数据的时候就有一些细节需要注意。

3.1 圆

圆其实很好判断,直径有值或者直径的值大于一定数字即可,但是有时候会把圆判断成矩形或者把矩形判断成圆,这与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是矩形的边长其作用是防止圆和矩形发生误判。

3.2 矩形

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是圆的直径和矩形的宽,作用是防止误判和进一步确定。

3.3三角形

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是去排除圆和矩形。

4. 测量距离

拿openmv距离如同用openmv测量尺寸,误差太大,所以买了一个激光测距模块可以高精度测量3米的距离。
提供链接:vl531x激光测距

5.测量尺寸

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;
}