第一篇博客,先做一下自我经历介绍。。本人学生一枚,自2015年接触电路与模电,经过一年的学习开始转战单片机原理。又经过一年的努力,终于考入了一所本科院校的专科专业
。大学在校期间,学习了 AVR STM32 单片机以及uC/OS_II嵌入式系统。但是在之前的学习中本人并没有记录学习的过程,和累积的一些经验。所以在接下来转战控制理论与算法的学习中(其实本人想做导弹精确制导的
)利用此平台,希望各位大牛给予指正和建议。
--------------------------------————————--正事分割线————————————-------------------------------
一、机器人硬件与源码:
做这个其实是源于我和我们同学一起去参加的一个机器人迷宫比赛,机器人是老师从别的一家公司买到的 (你懂的),机器人的主控芯片是STM3210F系列的,非常经典的Cortx-M3内核的芯片。机器人外形如图一:
图一,机器人外形
这个机器人一周有8个红外传反射传感器,但其实一共只用了3个。上面是一个SPI串口的一个串口屏。下面的电机是两个小功率的步进电机。外壳总的来说还挺好看~
机器人出厂代码总的来说就是一个机器人探索迷宫的算法和机器人沿墙走的算法(PID)。因为需要走的迷宫是固定宽度和长度的,所以简单来说,出厂代码里面的探索算法其实就是规定了一个8*8的坐标,让机器人从(0,0)坐标走到(8,8)坐标即可。而机器人在岔路口的转弯优先级是以X轴和Y轴的正方向优先的。
因为我们拿到机器人的时候就已经是比赛前一星期的时间了,所以我也就是把步进电机脉冲的时钟分割系数该小了一点,让机器人跑的快一点。之后就去比赛了。不得不说这比赛的商业化真的是很严重。
二、我突然出现的想法
之前我看过一个视频,应该是一个国际的机器人比赛的视频,视频里面也是迷宫机器人,但是他这个机器人最一开始就伸出一个摄像头应该也是用的图像处理之后识别的最优路线。正巧,在这个比赛通知之前刚好做了一个矩形识别的算法,想了一下虽然我们这个达不到国际的水平但是实现个功能也不成问题的。
三、图像识别处理
要用计算机去模拟机器人找最优路径的前题就是要先把迷宫轨道的图像信息获取到。先以图二轨道为例。
图二
图像处理需要先灰度化,在进行边缘检测。灰度化处理使用MATLAB的rgb2gray函数就可以了。
边沿检测简单的说就是图像在某一局部强度剧烈变化的区域。
强度变化一般分为两种:1、阶跃型变化。2屋顶型变化。
(此处引用duan_hy作者的 边缘检测算方法。
点击打开链接);
处理后的图像
四、迷宫图像信息的等效。
根据我的想法,为了便于处理,边沿检测完成之后就需要把整个迷宫等效成一个17*17的矩阵。因为该迷宫是一个8*8轨道的迷宫。所以等效的思想就是将迷宫的一个格,和迷宫的一个格长度的墙体都看做一个元素。故需要16*16个元素,加上边缘就是17*17个元素。
等效的过程需要X/Y两个方向分别等效。因为两个方向的算法大同小异,故以下就以一个方向为例:
1、首先确定需要检测的图像的行坐标,因为有八个路径,即将整个迷宫横向分为8份即可,下图画出的是需要检测的线,以下简称‘检测线‘。
2、第二步,找到迷宫的左右边缘,之后就是将每个检测线分为16份,然后检测之后去等效想对应 17*17的矩阵即可。下图为示意图
因为我们检测的是行,所以我们在等效为坐标的时候需要每一行中间隔出来一行。检测成功后就是下面这样的
列的检测与行的一样,我就不啰嗦了。下面放一张原迷宫与等效迷宫的对比图
最后,就是写一个能从右下角(0,0)走到左上角(7,7)的算法就可以了。
注意:这里每次是需要走两个像素点的,简单的说就是因为道路和墙壁都是元素,所以每通过一个坐标,即从(0,0)走到(0,1)是走过了两个元素的(一个墙,一个路);
这里我写了一个比较简单的X,Y轴的正方向优先的算法尝试了一下,还是比较成功的。
五、总结
日后笔者后续会将该代码移植到主控芯片为STM32F10X的机器人中进行实际测试。欢迎各位读者给出宝贵的意见。
本人是初学者,初入本行,数学功底有限各位读者见笑了,欢迎指正。
附检测MATLAB代码
page2 = page1;
%%%迷宫转换为坐标点
xsData = zeros(16,16);
xs = zeros(8,599);
h=20;
x=1;
while h<387
for i=1:599
for j=1:5
xs(x,i) = xs(x,i) + page1(h+j,i);
end
for j=1:5
xs(x,i) = xs(x,i) + page1(h+j,i);
end
page2(h,i) = 255;
end
h=h+48;
%%% plot(t,xs);
x = x+1;%%记录下一个检测行
end
%%%以下去处理竖线%%%%%%
sxax = zeros(8,10);%%保存竖线坐标
sxtime = 1;%%竖线坐标技计数
for i=1:8
for j=1:599
if xs(i,j)>2500 %%检测到竖线
sxax(i,sxtime) = j;%%保存竖线坐标
sxtime = sxtime+1;
end
end
sxtime = 1;
end
%%%以下去处理竖线坐标%%%%
axmax = 0;%%最大坐标值
axmin = 500;%%最小坐标值
pagejs = 0;%%图像分割基数
for i=1:8
for k=1:10
if axmax0
if axmin > sxax(i,k)
axmin = sxax(i,k);%%获得改行最小值
end
end
end
pagejs = (axmax - axmin)/16;
for j=1:10
if sxax(i,j) > 0 %%有坐标
xsData(i*2,floor((sxax(i,j)-axmin)/pagejs)+1) = 255;
end
end
a = axmin;%%从最小值 坐标开始划线
while a0 %%白点坐标必须为单数
if xsData(i,j+1)==255 %%检测白点旁的双数坐标
xsData(i,j+1) = 0;%%路径为障碍,表示错误 改正
end
else %%如果不是单数为错误 改正
xsData(i,j)=0;
end
end
end
end
figure;
imshow(xsData);