**

基于openmv与51小车的串口通信巡线

新手小菜鸡,写的可能不大行,欢迎大神指正。
硬件连接:我用的是openmv3(注意供电电压端VIN,不然乱接可能会烧坏),P4和P5引脚是RXD和TXD,分别与单片机的TXD,RXD相连接,共地!
这边采用的是line_flowing机器人巡线,相对于直线偏离角度识别个人感觉机器人巡线程序比较稳一点
openmv`import sensor, image, time, math#调用声明
from pyb import UART
另外我这边是用来识别黑线的,需要识别其他颜色的可以通过更改颜色的阈值进行修改!

代码:

import sensor, image, time, math#调用声明
from pyb import UART
# Tracks a black line. Use [(128, 255)] for a tracking a white line.
GRAYSCALE_THRESHOLD = [(0, 64)]
#设置阈值,如果是黑线,GRAYSCALE_THRESHOLD = [(0, 64)];
#如果是白线,GRAYSCALE_THRESHOLD = [(128,255)]


# Each roi is (x, y, w, h). The line detection algorithm will try to find the
# centroid of the largest blob in each roi. The x position of the centroids
# will then be averaged with different weights where the most weight is assigned
# to the roi near the bottom of the image and less to the next roi and so on.
ROIS = [ # [ROI, weight]
        (0, 100, 160, 20, 0.7), # You'll need to tweak the weights for you app
        (0, 050, 160, 20, 0.3), # depending on how your robot is setup.
        (0, 000, 160, 20, 0.1)
       ]
#roi代表三个取样区域,(x,y,w,h,weight),代表左上顶点(x,y)宽高分别为w和h的矩形,
#weight为当前矩形的权值。注意本例程采用的QQVGA图像大小为160x120,roi即把图像横分成三个矩形。
#三个矩形的阈值要根据实际情况进行调整,离机器人视野最近的矩形权值要最大,
#如上图的最下方的矩形,即(0, 100, 160, 20, 0.7)

# Compute the weight divisor (we're computing this so you don't have to make weights add to 1).
weight_sum = 0 #权值和初始化
for r in ROIS: weight_sum += r[4] # r[4] is the roi weight.
#计算权值和。遍历上面的三个矩形,r[4]即每个矩形的权值。

# Camera setup...
sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.GRAYSCALE) # use grayscale.
sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.
sensor.skip_frames(30) # Let new settings take affect.
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
#关闭白平衡
clock = time.clock() # Tracks FPS.

while(True):
    clock.tick() # Track elapsed milliseconds between snapshots().
    img = sensor.snapshot() # Take a picture and return the image.
    uart = UART(3,9600)

    centroid_sum = 0
    #利用颜色识别分别寻找三个矩形区域内的线段
    for r in ROIS:
        blobs = img.find_blobs(GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True)
        # r[0:4] is roi tuple.
        #找到视野中的线,merge=true,将找到的图像区域合并成一个

        #目标区域找到直线
        if blobs:
            # Find the index of the blob with the most pixels.
            most_pixels = 0
            largest_blob = 0
            for i in range(len(blobs)):
            #目标区域找到的颜色块(线段块)可能不止一个,找到最大的一个,作为本区域内的目标直线
                if blobs[i].pixels() > most_pixels:
                    most_pixels = blobs[i].pixels()
                    #merged_blobs[i][4]是这个颜色块的像素总数,如果此颜色块像素总数大于                     #most_pixels,则把本区域作为像素总数最大的颜色块。更新most_pixels和largest_blob
                    largest_blob = i

            # Draw a rect around the blob.
            img.draw_rectangle(blobs[largest_blob].rect())
            img.draw_rectangle((0,0,30, 30))
            #将此区域的像素数最大的颜色块画矩形和十字形标记出来
            img.draw_cross(blobs[largest_blob].cx(),
                           blobs[largest_blob].cy())

            centroid_sum += blobs[largest_blob].cx() * r[4] # r[4] is the roi weight.
            #计算centroid_sum,centroid_sum等于每个区域的最大颜色块的中心点的x坐标值乘本区域的权值

    center_pos = (centroid_sum / weight_sum) # Determine center of line.
    #中间公式

    # Convert the center_pos to a deflection angle. We're using a non-linear
    # operation so that the response gets stronger the farther off the line we
    # are. Non-linear operations are good to use on the output of algorithms
    # like this to cause a response "trigger".
    deflection_angle = 0
    #机器人应该转的角度

    # The 80 is from half the X res, the 60 is from half the Y res. The
    # equation below is just computing the angle of a triangle where the
    # opposite side of the triangle is the deviation of the center position
    # from the center and the adjacent side is half the Y res. This limits
    # the angle output to around -45 to 45. (It's not quite -45 and 45).
    deflection_angle = -math.atan((center_pos-80)/60)
    #角度计算.80 60 分别为图像宽和高的一半,图像大小为QQVGA 160x120.
    #注意计算得到的是弧度值

    # Convert angle in radians to degrees.
    deflection_angle = math.degrees(deflection_angle)
    #将计算结果的弧度值转化为角度值
    A=deflection_angle
    print("Turn Angle: %d" % int (A))#输出时强制转换类型为int
    #print("Turn Angle: %d" % char (A))
    # Now you have an angle telling you how much to turn the robot by which
    # incorporates the part of the line nearest to the robot and parts of
    # the line farther away from the robot for a better prediction.
    #将结果打印在terminal中
    if(-10<=A<=20):
        a=1         #加速直行
    elif(-20<=A<-10):
        a=2         #减速直行
    elif(20<A<=30):
        a=2         #减速直行
    elif(-35<=A<-20):
        a=3         #向左小调整
    elif(30<A<45):
        a=4         #向右小调整
    elif(A<-35):
        a=5         #向左大调整
    elif(A>=45):
        a=6         #向右大调整
    uart.write(str(a))
    print(a)
    time.sleep(10)#延时

51单片机:
小车控制是pwm控制的,具体小车的偏移还是需要自己调试的

#include <reg52.h>
//IO引脚定义:
sbit IN1=P1^0;		
sbit IN2=P1^1;
sbit IN3=P1^2;					  
sbit IN4=P1^3;
sbit IN5=P1^4;		
sbit IN6=P1^5;
sbit IN7=P1^6;
sbit IN8=P1^7;
//以上为电机驱动板输入引脚定义,

sbit LQ_PWM=P0^2;
//sbit LH_PWM=P0^0;
sbit RQ_PWM=P0^3;	   
//sbit RH_PWM=P0^1;
//pwm信号端	   	   
unsigned char Temp;
unsigned int i;
unsigned char pwm_val_left  =0;//变量定义
unsigned char push_val_left =0;// 左电机占空比N/10
unsigned char pwm_val_right =0;
unsigned char push_val_right=0;// 右电机占空比N/10
bit Right_moto_stop=1;
bit Left_moto_stop =1;
unsigned  int  time=0;

//宏定义
#define LQ_go      IN1=0;IN2=1 //左轮前进
#define LQ_back    IN1=1;IN2=0 //左轮后退    
#define LQ_stop    IN1=0;IN2=0	//左轮停止,两个输出1也可以
#define RQ_go    	IN3=0;IN4=1 //右轮前进
#define RQ_back  	IN3=1;IN4=0 //右轮后退
#define RQ_stop  	IN3=0;IN4=0 //右轮停止,两个输出1也可以
#define LH_go      IN5=0;IN6=1 //左轮前进
#define LH_back    IN5=1;IN6=0 //左轮后退    
#define LH_stop    IN5=0;IN6=0	//左轮停止,两个输出1也可以
#define RH_go    	IN7=0;IN8=1 //右轮前进
#define RH_back  	IN7=1;IN8=0 //右轮后退
#define RH_stop  	IN7=0;IN8=0 //右轮停止,两个输出1也可以

#define car_go				LQ_go;RQ_go;LH_go;RH_go;		//小车前进
#define car_back			LQ_back;RQ_back;LH_back;RH_back;	//小车后退
#define car_left			RQ_go;LQ_back;RH_go;LH_stop;		//小车左转弯
#define car_right			LQ_go;RQ_stop;LH_go;RH_stop;		//小车右转弯
#define car_stop			LQ_stop;RQ_stop;LH_stop;RH_stop;	//小车停车

void UsartInit()
{
	TMOD|=0X20;
	SCON=0X50;
	TH1=0XFD;
	TL1=TH1;
	PCON=0X00;
	TR1=1;	
	ES=1;
	EA=1;
}
//全速前行		
 void  High_run(void)   	
{
     push_val_left=9;	 //速度调节变量 0-9。。。9最小,0最大
	 push_val_right=9;
	 LQ_go;RQ_go;
}
//减速前行		
 void  Low_run(void)   	
{
     push_val_left=4;	 //速度调节变量 0-9。。。9最小,0最大
	 push_val_right=4;
	 LQ_go;RQ_go;
}

//左转
void  leftrun(void)
{
    
	 push_val_left=3;	 //速度调节变量 0-9。。。9最小,0最大
	 push_val_right=6;
	 LQ_go;RQ_go;
}
//大左转
void  B_leftrun(void)
{
    
	 push_val_left=3;	 //速度调节变量 0-9。。。9最小,0最大
	 push_val_right=9;
	 LQ_go;RQ_go;
}
//右转
void  rightrun(void)
{
    
 	push_val_left=6;	 //速度调节变量 0-9。。。9最小,0最大
	push_val_right=3;
	LQ_go;RQ_go;
}
//大右转
void  B_rightrun(void)
{
    
 	push_val_left=9;	 //速度调节变量 0-9。。。9最小,0最大
	push_val_right=3;
	LQ_go;RQ_go;
}
/************************************************************************/
/*                    PWM调制电机转速                                   */
/************************************************************************/
/*                    左电机调速                                        */
/*调节push_val_left的值改变电机转速,占空比            */
void pwm_out_left_moto(void)
{  
   if(Left_moto_stop)
   {
    if(pwm_val_left<=push_val_left)
	       {
		     LQ_PWM=1; 
		   }
	else 
	       {
	         LQ_PWM=0; 
		   }
	if(pwm_val_left>=10)
	       pwm_val_left=0;
   }
   else    
          {
           LQ_PWM=0;
		  }
}
/******************************************************************/
/*                    右电机调速                                  */  
void pwm_out_right_moto(void)
{ 
  if(Right_moto_stop)
   { 
    if(pwm_val_right<=push_val_right)
	      {
	       RQ_PWM=1; 		   
		   }
	else 
	      {
		   RQ_PWM=0; 
		  }
	if(pwm_val_right>=10)
	       pwm_val_right=0;
   }
   else    
          {
           RQ_PWM=0; 
	      }
}	

//延时
void Delay(unsigned int t)
{
	while(t--)
	{
	}
}
//入口函数
/*TIMER0中断服务子函数产生PWM信号*/
void timer0()interrupt 1   using 2
{
	TH0=0XFc;	  //1Ms定时
	TL0=0X18;
	time++;
	pwm_val_left++;
	pwm_val_right++;
	pwm_out_left_moto();
	pwm_out_right_moto();
}	
void main(void)
{
	TMOD|=0X01;
	TH0= 0XFc;		  //1ms定时
 	TL0= 0X18;
	TR0= 1;
	ET0= 1;
	EA = 1;
	UsartInit();
	LQ_go;RQ_go; 
	while(1)
	{
		
	}
}


void Usart() interrupt 4
{   
	if(RI)                        //判断是接收中断产生
	{	
		RI=0;                      //标志位清零
		Temp=SBUF;                 //读入缓冲区的值

		if(Temp=='1')				//加速直行
		{
			High_run();
			Delay(100);	
		}
		else if(Temp=='2')			//减速直行
		{
			Low_run();
			Delay(200);
		}
		else if(Temp=='3')
		{
			leftrun();				//向左小调整
			Delay(100);
		}
		else if(Temp=='4')			//向右小调整
		{
			rightrun();
			Delay(100);
		}							
		else if(Temp=='5')			//向左大调整
		{
			B_leftrun();
			Delay(300);
		}
		else if(Temp=='6')			//向右大调整
		{
			B_rightrun();
			Delay(300);
		}
 	}		 
}

`