2017-06-17 21:14:21 cosmispower 阅读数 3279

sobel的数学公式表达

(1)离散表达


(2)矩阵表达


(3)梯度的近似表达(滤波后的灰度值)


背景,在巡线中经常有一些轨迹鉴别的问题存在。如果不想随大流用普通的灰度传感器,又或者路面比较复杂的情况下。可以使用摄像头采集画面,对每一帧进行边界的识别(个人建议因为在巡线小车这样小巧的物体上不能放置电脑,所以采用51单片机或者stm32单片机的小伙伴们可以各帧采样或者隔合适帧采集,毕竟单片机的运算慢。)那么根据上面的公式我们可以得到轨迹的路线。其实还有其他的算法,不过呢,相比sobel算子,其他的算子计算量大,或者对于噪点的处理不佳。比较对于小车来说,先滤波什么的是不存在的,精度没这么高。


在得到轨迹线了之后就要循迹了,那么怎么循迹呢?最简单的是pd算法循迹,pd算法是pid算法除去了积分过程,只留下普通项与微分项。根据论文2,舵机的延时偏转就相当于一个积分过程。

pd算法

舵机PWM占空比=KP*偏心距+KD*偏心距变化率


舵机PWM占空比=KP*偏心距+KD*偏心距变化率+KA ∗V2/R

R为轨道半径;l:为前瞻;h为前瞻离轨道距离如图所示



如果想程序更好自动化水平高,那么可以考虑这样的特殊情况



程序

下面是给出静态图片的sobel轨迹识别的程序(matlab)

%%%%%%%边缘识别与画出中心线%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
imag = imread('D:\广东工业大学机器人学院\数字图像处理\1.jpg');  %读取关键帧,写上你的文件名
imag = rgb2gray(imag);        %转化为灰度图
subplot(1,4,1);imshow(imag);title('原图');
[high,width] = size(imag);   % 获得图像的高度和宽度
U = double(imag);
uSobel = imag;
%%%%%%%sobel边缘检测%%%%%%%
for i = 2:high - 1   %忽略边缘行以防溢出
for j = 2:width - 1
Gx = (U(i+1,j-1) + 2*U(i+1,j) + U(i+1,j+1)) - (U(i-1,j-1) + 2*U(i-1,j) + U(i-1,j+1));
Gy = (U(i-1,j+1) + 2*U(i,j+1) + U(i+1,j+1)) - (U(i-1,j-1) + 2*U(i,j-1) + U(i+1,j-1));
uSobel(i,j) = abs(Gx) + abs(Gy);
end
end
subplot(1,4,2);imshow(im2uint8(uSobel));title('边缘检测后');  %画出边缘检测后的图像
%%%%%%%二值化%%%%%%%
for i = 2:high - 1
for j = 2:width - 1
if uSobel(i,j)<150    %阈值可调
uSobel(i,j)=0;
elseif  uSobel(i,j)>=150   %阈值可调
uSobel(i,j)=255;
end
end
end
subplot(1,4,3);imshow(im2uint8(uSobel));title('threshold');
%%%%%%%画出中心线%%%%%%%
for i = 2:high - 1
k=0;K=[];u=[];
for j = 2:width - 1
if  uSobel(i,j)>=200
k=k+1;
K(k)=uSobel(i,j);
u(k)=j;
end
end
p=length(u);
if p>0;
P=ceil((u(1)+u(p))/2);
uSobel(i,P)=255;
end
end
subplot(1,4,4);imshow(im2uint8(uSobel));title('center line');

效果如图:



参考文献

【1】蒋旭 . 两点算法求智能车赛道曲率 . 新技术新工艺 . 2014 . 32-33

【2】 第九届“飞思卡尔”杯全国大学生智能汽车竞赛技术报告 北京邮电大学 

【3】冈萨雷斯 数字图像处理 第二版 463-470


2019-03-21 17:25:24 weixin_43425544 阅读数 1506

开写

使用51单片机制作一个简单的巡线小车,这个很多人都有制作过,废话不多说,直接上电路图。
Snipaste_2019-03-19_22-06-22.png

模块介绍

5个模块,逐一介绍。
控制模块,没什么好说的,都知道巡线小车,应该都懂。晶振就不说,P1口接拨码开关,是控制车速。P0口接红外的反馈。P2口控制电机与舵机。
红外模块,识别黑白线,小车自动巡线的前提。红外传感器识别黑白线时输出变压不同,可以以此调整电压来判断小车有无跑偏。
电机模块,控制两个后轮的转动,可以用占空比来调速。
舵机模块,控制小车装弯。
稳压模块,输出稳定5v,确保4个模块稳定工作。

使用讲解

舵机使用

舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前,在高档遥控玩具,如飞机、潜艇模型,遥控机器人中已经得到了普遍应用。
舵机就是使用占空比来控制,在一段20ms的周期中,使用不同的脉冲宽度来控制舵机在0~180度之间转动。

脉冲宽度(20ms) 舵机输出轴转角(单位:度)
0.5ms 0
1ms 45
1.5ms 90
2ms 135
2.5ms 180

由于51单片机没有专门的pwn输出功能,只能自行用定时器设置一个脉冲周期。这只是控制一个舵机,简单。直接上程序。
定时器1初始化设置。

	unsigned int angle=10;	//定义角度
	TMOD = 0x10;		//定时器1工作模式1
	TL1 = 0xd2;		 //定时50us进入中断
	TH1 = 0xff;			
	TR1 = 1;			
	IE=0X88;

中断函数设置,400次为20ms,一个舵机控制周期,motor为舵机信号线位,其中angle=10,就是0.5ms,角度=0,按照上表可以自行设数控制角度,这里说一下,这里是50us一次中断,那换算来就是精度只是5度,angle加一只能是增加5度。如果需要提高精度,可以改变每次中断时间。还有不要设置度数超过180度,这样会损害舵机。

	TL1 = 0xd2;		 
	TH1 = 0xff;
	if(count<angle)
	motor=1;
	else
	motor=0;
	count++;
	if(count>400)
	count=0;

电机使用

电机,是指依据电磁感应定律实现电能转换或传递的一种电磁装置。电机在电路中是用字母M表示,它的主要作用是产生驱动转矩,作为用电器或各种机械的动力源,发电机在电路中用字母G表示,它的主要作用是利用机械能转化为电能。
小时候玩四驱车的时候,把马达拆下来用电池去接的时候,已经知道怎样使用。正接正转,反接就反转。不可能在使用的时候,想他正反转就把线换过来,过于愚蠢。这里使用L298N驱动模块实现这个功能,还增加一个使能端,可以设置来调速。也可以使单片机能驱动电机。一个L298N模块可以控制两个电机。这里介绍一个的使用,另一个同理。

part1 1 0 x 1 0
paet2 0 1 x 1 0
ENA 1 1 0 1 1
舵机 正转 反转 停止 停止 停止

注x表示不管什么情况!
上程序讲解一波:
三个都已经位定义,下面就是电机正转程序,想要反转,就是part1=0;part2=1;ENA=1;

	ENA=1;
	part1=1;
	part2=0;

红外模块使用

这个没有什么说的,按照电路图焊好基本没有什么问题,就还剩下调基准。那个红外传感器有几点注意事项,两个红外传感器之间最好为0.5cm,因为黑线宽度不大,如果,间距太大会造成识别精度下降,小车行驶不稳。红外传感器尽量离黑线,就是地,距离小点,太大会受环境光线影响较大,导致识别出错。还有个人给个建议,传感器离小车远一点,这个可以通过生活场景讲解,司机行驶时,眼睛是往远处看,然后做出判断,传感器就是“眼睛”。所以传感器不要离前轮太近。建议不怕多,再来一个,传感器可以和前轮一起转动,这样小车会稳定点,识别也会增加实时性,小车转动幅度也可以大点。

ok,硬件到此已经完成,那究竟如何使用红外传感器来让小车自动巡线,看看下面程序就基本明白。

void A_TURN()	   //自动转弯
{
	date=P0;
	if(date==0x08|date==0x10|date==0x18)	 //直走
		angle=30;
	else if(date==0x04|date==0x0a)		 //左转5度
		angle=25;
	else if(date==0x20|date==0x30)		 //右转5度
		angle=35;
	else if(date==0x02|date==0x06)		 //左转10度
		angle=20;
	else if(date==0x40|date==0x60)		 //右转10度
		angle=40;
  	else if(date==0x01|date==0x03)		 //左转15度
		angle=15;
	else if(date==0x80|date==0xa0)		 //右转15度
		angle=45;
}
P0.0 P0.1 P0.2 P0.3 P0.4 P0.5 P0.6 P0.7 舵机
1 直走
1 直走
1 1 直走
1 左转5°
1 1 左转5°
1 右转5°
1 1 右转5°
1 左转10°
1 1 左转10°
1 右转10°
1 1 右转10°
1 左转15°
1 1 左转15°
1 右转15°
1 1 右转15°

上图程序就是根据上表编写而成,注意空格为0,就是低电平。1为高电平,在黑线上方,根据不同情况舵机不同反应。上图程序是在舵机顺时针转动(小车面向前方,舵机0°在左边,180°在右边)的情况下成立,舵机左右转动幅度不够30°可以酌情改变角度。
主体部分完工,还有调速简单说明,驱动不是有两个使能端,高电平起作用。只要在一个周期内控制电机作用时间,不就完成调速功能。

void adjust_speed()
{
	unsigned int count=600;
	if(P1=0xff)
	{
		for(;count>0;count--)
		{
			if(count>100){
			ENA=1;				   //两个驱动后轮
			ENB=1;
			}
			else 
			ENA=0;
			ENB=0;
		}
	}

	else if(P1=0xcf)
	{
		for(;count>0;count--)
		{
			if(count>300){
			ENA=1;
			ENB=1;
			}
			else {
			ENA=0;
			ENB=0;
			}
		}
	}
	else if(P1=0xbf)
	{
		for(;count>0;count--)
		{
			if(count>500){
			ENA=1;
			ENB=1;
			}
			else {
			ENA=0;
			ENB=0;
			}
		}
	}
}

最后的最后

所有模块的使用与程序样例都已经贴出来,如果还不会,那就是自己的问题,这已经是最详细的教程。最后的整合就不贴出来,自行整合。就是不断重复自动巡线,自行思考,不是很难。
微信图片_20190321172031.jpg

2019-05-23 20:21:34 qq_42995530 阅读数 715

1改了一下ROS小车巡线源程序线的颜色,
lower_yellow=numpy.array([10,10,10])
upper_yellow=numpy.array([255,255,250])
此处的颜色为HSV颜色,具体对应如下:
在这里插入图片描述
2 巡线
巡线时报错如下:
[riki_line.launch]is neither a launch file in package[riki_line_follower]nor is [riki_line_follower]a launch name.
解决办法是:
第一种办法,把摄像头巡线这个功能包放到catkin_ws/src中去,然后再进入catkin_ws,
再编译,catkin_make,最后source devel/setup.bash.
但是按理说这个功能包放在别的目录下也是可以的,这种解决办法总感觉没找到深入的原因,还得继续找。

2018-08-07 19:29:12 li1886477130 阅读数 4576

arduino的智能小车的功能:巡线功能
材料清单:
上文提到的小车一台;
光电对管两个(也可以多个);
杜邦线若干;
我们设定的是当光电对管检测到黑线的时候做出动作。
当左侧传感器检测到黑线时,小车左转;当右侧传感器检测到黑线时,小车右转;当两个传感器都检测到黑线时,小车停止。

#include <Servo.h>

int mL1=6;//左1
int mL2=5;
int mR1=11;//右1
int mR2=3; 
int trac1 = 12; //从车头方向的最右边开始排序
int trac2 = 13; 
Servo s;  //舵机


void setup() {
  Serial.begin(9600);
  s.attach(9);//舵机信号线
  s.write(68);//舵机初始化角度 
  pinMode(mL1,OUTPUT);
  pinMode(mL2,OUTPUT);
  pinMode(mR1,OUTPUT);
  pinMode(mR2,OUTPUT);
  pinMode(trac1, INPUT);
  pinMode(trac2, INPUT);
}

void loop() {
  tracing();
}
void motorRun(int cmd)
{
  switch(cmd){
    case FORWARD:
      Serial.println("FORWARD"); //输出状态
      analogWrite(mL1,30);
      analogWrite(mL2,LOW);
      analogWrite(mR1,30);
      analogWrite(mR2,LOW);
      break;
     case BACKWARD:
      Serial.println("BACKWARD"); //输出状态
      analogWrite(mL1,0);
      analogWrite(mL2,40);
      digitalWrite(mR1,LOW); 
      analogWrite(mR2,40);
      break;
     case TURNLEFT:
      Serial.println("TURNLEFT"); //输出状态
      analogWrite(mL1,0); 
      analogWrite(mL2,0);
      analogWrite(mR1,60);
      analogWrite(mR2,0);
      break;
     case TURNRIGHT:
      Serial.println("TURNRIGHT"); //输出状态
      analogWrite(mL1,50);
      analogWrite(mL2,0);
      analogWrite(mR1,0);  
      analogWrite(mR2,0);
      break;
     default:
      Serial.println("STOP"); //输出状态
      digitalWrite(mR1,LOW);
      digitalWrite(mL1,LOW);
      digitalWrite(mR2,LOW);
      digitalWrite(mL2,LOW);
  }
}
void tracing()
{
  int data[4];
  data[2] = digitalRead(12);
  data[3] = digitalRead(13);

  if(!data[2] && !data[3])  //左右都没有检测到黑线
  {
    motorRun(FORWARD);
  }

  if(data[2])  //左边检测到黑线
  {
    motorRun(TURNLEFT);
  }

  if(data[3])  //右边检测到黑线
  {
    motorRun(TURNRIGHT);
  }

  if(data[2] && data[3])  //左右都检测到黑线是停止
  {
    motorRun(STOP);
    while(1);
  }
}

除此之外,我们还可以使用多个光电对管来进行检测,以此来减少车子的搬动幅度。
ccd巡线也是一个不错的选择。

2019-11-13 10:37:47 qq_37760746 阅读数 150

树莓派python+opencv颜色识别、跟随、巡线小车

首先树莓派必须安装opencv。

import numpy as np
import cv2
import RPi.GPIO as GPIO
GPIO.setwarnings(False)  #Echo G21(input)  #trig G20                    
GPIO.setmode(GPIO.BCM)
GPIO.setup(22,GPIO.OUT)
GPIO.setup(27,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(18,GPIO.OUT) 
GPIO.setup(23,GPIO.OUT)
pwma=GPIO.PWM(18,100)
pwmb=GPIO.PWM(23,100)
pwma.start(100)
pwmb.start(100) 
blue_lower = np.array([100,43,46])
blue_upper = np.array([124,255,255])  
cap = cv2.VideoCapture(0) 
pwma.ChangeDutyCycle(0)
GPIO.output(22,1)
GPIO.output(27,0)
pwmb.ChangeDutyCycle(0)
GPIO.output(25,True)
GPIO.output(24,False)
cap.set(3, 320)  #x160
cap.set(4, 240)   #y120
while 1:
    ret, frame = cap.read()
    frame = cv2.GaussianBlur(frame, (5, 5), 0)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, blue_lower, blue_upper)

    mask = cv2.erode(mask, None, iterations=2)
    mask = cv2.GaussianBlur(mask, (3, 3), 0)
    res = cv2.bitwise_and(frame, frame, mask=mask)

    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

    if len(cnts) > 0:
    
        cnt = max(cnts, key=cv2.contourArea)
        (x, y), radius = cv2.minEnclosingCircle(cnt)
        cv2.circle(frame, (int(x), int(y)), int(radius), (255, 0, 255), 2)
	print(int(x), int(y))
	if int(x)>160:
		pwma.ChangeDutyCycle(30)
		GPIO.output(22,1)
		GPIO.output(27,0)
		pwmb.ChangeDutyCycle(30)	
		GPIO.output(25,0)
		GPIO.output(24,1)
      	else:
		pwma.ChangeDutyCycle(30)
		GPIO.output(22,0)
		GPIO.output(27,1)
		pwmb.ChangeDutyCycle(30)
		GPIO.output(25,1)
		GPIO.output(24,0)
    else:
	pwma.ChangeDutyCycle(0)
	GPIO.output(22,1)
	GPIO.output(27,0)
	pwmb.ChangeDutyCycle(0)
	GPIO.output(25,True)
	GPIO.output(24,False)
        pass
    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)
    cv2.imshow('res', res)
    if cv2.waitKey(5) & 0xFF == 27:
        break	
cap.release()
cv2.destroyAllWindows()

一以下为颜色参照参数设置在这里插入图片描述

巡线传感器

阅读数 3062

openmv 飞机巡线

阅读数 2890

没有更多推荐了,返回首页