**
基于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);
}
}
}
`