迷宫机器人软件设计
摘 要 人类科技的进步促使机器人技术的智能化水平越来越高。可移动机器人的路径规划是机器人研究中的一个重要领域,得到越来越多研究者的关注,并取得了丰厚的成果。行进方向选择问题是智能机器人控制的关键技术之一,可移动机器人如何在复杂和未知的环境中自主选择路线到达目标地点,并躲避障碍物,是其重要的判断条件之一,也是功能实现的基础。
迷宫机器人是一种基于ARM1138的具备人工智能的小型机器人,可在没有人工干预的情况下,在16×16未知的迷宫中自行完成一系列动作。看似简单的小型机器人,其中却包含了光学、力学、信息科学等多种学科的综合应用,是对机器智能化的实现。本设计从软件设计的角度对迷宫机器人的智能控制做了较有深度的探讨。通过软件编程,实现迷宫机器人的智能控制,完成在16×16的迷宫中,由起点自动探索到终点并探测返回,随后完成冲刺的功能。论文中讲述的重点是迷宫机器人在路径选择中逻辑方面的判断,以及墙壁信息的获取和车身的控制。
关键词:人工智能;迷宫机器人;软件
目录
1绪论 ....................................................... 1
1.1课题的研究背景和发展历程 ............................................ 1
1.2课题研究的目的和意义 ................................................ 1
1.3课题研究的主要内容 .................................................. 1
1.4本章小结 ............................................................ 1 2系统的总体设计 ............................................. 2
2.1系统方案的设计 ...................................................... 2
2.2单片机和开发工具的选择 .............................................. 3
2.2.1单片机的选择 ...................................................... 3
2.2.2开发工具的选择 .................................................... 4
2.3本章小结 ............................................................ 5 3迷宫机器人的软件设计 ....................................... 6
3.1迷宫介绍 ............................................................ 6
3.1.1迷宫的结构 ........................................................ 6
3.1.2起点坐标的确立 .................................................... 6
3.2主要外设的软件设计 .................................................. 7
3.2.1红外传感器的软件控制 .............................................. 7
3.2.2步进电机的软件控制 ................................................ 8
3.3迷宫机器人的姿势矫正 ................................................ 9
3.3.1双板的身姿矫正 ................................................... 10
3.3.2单侧板的身姿矫正 ................................................. 10
3.3.3直角拐弯 ......................................................... 11
3.3.4车身后转 ......................................................... 13
3.4本章小结 ........................................................... 13 4控制方式的实现 ............................................ 14
4.1等高图的制作与偏移量的判断 ......................................... 14
4.2探索法则 ........................................................... 15
4.2.1基本法则 ......................................................... 15
4.2.2中心法则的改良 ................................................... 17
4.3本章小结 ........................................................... 19 5总结与展望 ................................................ 20 参考文献 ................................................... 21 附录 ....................................................... 22
1绪论
1.1课题的研究背景和发展历程
进入21世纪,伴随着电子、信息技术的发展与迅速普及,人们对电子技术的要求也越来越高,智能化、信息化的高尖技术逐步融入人们的日常生活。现如今为满足社会需要,许多人正工作在未知的、恶劣的、高风险的环境下,所以由机器人代替人承担危险、繁重的工作已成为时代发展的必然要求,也体现出以人为本的和谐社会理念,而迷宫机器人技术很好的满足了这一要求,所以受到了各界人士的广泛关注。以迷宫机器人为主题的“电脑鼠走迷宫竞赛”在世界范围内兴起,成为深受高校大学生喜爱的一项电子类竞赛[1]。
1.2 课题研究的目的和意义
人工智能是智能机器人所执行的通常与人类智能有关的功能,如判断、推理、证明、识别、感知、理解、设计、思考、规划学习和问题求解等思维活动。智能化要求具有获取外界信息的能力、演绎推理的能力、学习的能力、自适应能力等[2]。迷宫机器人成功的实现了信息获取、可行路线判断和最优路径选择的功能,很好的突出了其学术价值。同时在实时性、效率性上得很好的体现,是对人工智能的一次很好的应用和发展。选择迷宫机器人这个课题,对人工智能的理解,对人类思维方式与机器编程衔接的理解具有很大的帮助。完善后的迷宫机器人可代替人类在高温、缺氧、有毒、辐射等危险环境下作业,且能在复杂环境中自行探寻目标并安全返回,对火灾现场、外太空等复杂、危险环境下的应用具有很好的前景。迷宫机器人的研制是智能控制领域的新突破,也是学术价值与实际应用价值的一个重要衔接。
1.3课 题研究的主要内容
迷宫机器人拟采用左右双轮驱动控制车身,通过控制左右电机的不同运动状态实现车身的前进、后退、身姿调整和转向。由传感器单元获取周围墙壁信息,并通过嵌入式系统对墙壁信息进行记忆存储、判断最优路径,进而控制电机完成一系列动作。
研究的主要内容有:
1)墙壁信息的获取
2)等高图的制作
3)转角的精确度
4)冲刺的速度和稳定性
1.4本章小结
随着科技的进步,机器人的智能控制已经成为现实,通过简单的逻辑指令的叠加,机器人便可完成复杂的动作。本设计便是通过软件编程,完成迷宫机器人的自动化智能控制。
2系统的总体设计
随着科技的进步和发展,对机器人信息化、自动化和智能化的要求越来越高。迷宫机器人作为智能控制的典型代表,因为其控制理论的先进性和本身的趣味性,越来越受到广大大学生的关注。本设计意在使用简单器件,通过C语言编程控制制作一台能在迷宫中自动完成探索至终点、探索返回和冲刺的迷宫机器人。
2.1系统方案的设计
迷宫机器人是结合光学、信息学等多种学科,以及软硬件综合应用制作出来的一种智能机器人。为实现迷宫机器人在迷宫中的自由行进,需完成墙壁信息的采集、数据的存储、等高图的制作、转角的设置等。因此在软件设计中,将电脑鼠的控制程序主要分成搜索模块、等高图制作模块、转弯模块和冲刺模块等四大模块。本设计采用单片机作为控制芯片,红外传感器作为探测装置,步进电机为驱动设备,制作一款采用双轮驱动的车型迷宫机器人。
迷宫机器人以单片机作为主控制芯片,外部扩展分为传感器、驱动电路、按键电路、电源电路等。框图如图2-1所示。
图2-1 迷宫机器人控制系统框图 迷宫机器人软件设计中,主程序主要包括:初始化、按键等待、探索至终点、
探索返回、冲刺等五个部分。打开电源,单片机启动,开始等待。按键按下后,迷宫机器人开始运行,搜索到达终点后再搜索返回至起点。迷宫机器人根据探测到的迷宫信息自动选择最优路径,以最快速度冲刺到终点后重新返回到起点,然后转身进入再次等待状态。
迷宫机器人运行主程序的流程图如下所示:
图2-2 主程序流程图
2.2单片机和开发工具的选择
2.2.1单片机的选择
单片机自70年代以来就以微处理器及超大规模集成电路技术的发展为重心,以其广泛的应用而得到迅速的发展,现在单片机的功能已经比较完善[3]。由于单片机的迅速发展,基于单片机应用的产品也越来越多。主要的单片机有51系列、ARM系列等。
本设计拟采用拥有32位ARM Cortex-M3内核的LM3S1138作为主控制芯片。它具有50MHZ运行频率,完全可以担负起迷宫机器人的实时性控制。64KB单周期Flash,16KB单周期SRAM,使单片机的功能给加强大[4]。其外设具有7组GPIO,可以很好的实现与外部设备的连接,4个32位Timer,3路全双工UART,6路16位PWM波,8通道,10位ADC等,能够有效实现对外设的控制。单片机内置看门狗定时器,可使芯片可靠运行。
图2-3 LM3S1138引脚图
2.2.2开发工具的选择
IAR Embedded Workbench for ARM(下面简称IAR EWARM)是一个针对ARM处理器的集成开发环境,它包含项目管理器、编辑器、C/C++编译器和ARM汇编器、连接器XLINK和支持RTOS的调试工具C-SPY[5]。将开发工具设置在EWARM环境下,则可以使用C/C++和汇编语言等对嵌入式应用程序进行开发。比较其它的ARM开发环境,IAR EWARM具有入门容易、使用方便和代码紧凑等特点[6]。 在本设计中,软件设计是通过IAR环境下的C语言编程实现。
IAR软件编程实例如下,迷宫机器人软件控制较为复杂,程序内容庞大,为使逻辑较为调理和方便编程,本设计中除主程序之外,另分别设置按键读取、迷宫机器人运行总体控制、传感器、步进电机、坐标、算法等多种子程序文件。通过设置全局变量和程序之间的相互调用,可实现各个程序模块间的协调工作。
图2-4 IAR软件示意图
2.3本章小结
迷宫机器人主要由单片机、光电传感器、步进电机和电源组成,通过电路设计等,将各部分合理的链接到一起,再通过程序控制,使得各器件协调工作。在此基础上,便可以实现迷宫机器人的功能。
3迷宫机器人的软件设计
3.1迷宫介绍
3.1.1 迷宫的结构
正规迷宫的地板为黑色,墙壁为白色,分成16×16的共计256块边长为18cm的方格,每块方格由白色立柱和隔墙分割。除四周边界外,每块隔墙和立柱都可自由拆卸组装,随机组成迷宫。其中隔墙高5cm,厚1.2cm,立柱长1.2cm宽1.2cm,高5cm。
迷宫可以四角处任意一点作为起点,起点必须三面设有墙壁,只在一面留有出口,迷宫机器人起始时朝向出口方向。以迷宫左下角作为原点,以每块方格长度作为一个标准单位,设置迷宫二维坐标,则X、Y轴同时被分为0~15共16个单位长度,则终点坐标为(7,7)(7,8)(8,7)(8,8)四点,迷宫机器人到达四个坐标的任意位置,及算到达终点。
图3-1迷宫例图
3.1.2起点坐标的确立
坐标的设置是迷宫机器人正常探索的基础,只有确定迷宫机器人所处位置的坐标,才能完成等高图的设置,控制机器人按照正确路线行驶至指定位置。而起点坐标与终点坐标的正确设置是完成迷宫机器人冲刺的前提。机器人起始位置的坐标不同,与终点的相对位置也有所不同,所以起点坐标的确立至关重要。
因为机器人是在迷宫四角的任意位置作为起点,所以在起始时,机器人一侧始终有墙壁存在,可根据此点确定起点坐标。在本设计中,迷宫机器人自起点处开始运行,同时检测两侧墙壁信息,若右侧首先探测到出口,则起点坐标默认为(0,0),
若左侧首先探测到出口,则起点坐标默认为(15,0)。
3.2主要外设的软件控制
3.2.1红外传感器的软件控制
迷宫机器人采用IRM8601S红外一体式传感器。该传感器内部的带通滤波器中心频率为38KHZ,所以驱动红外线的载波信号为38KHZ时传感器最灵敏,其调制信号应该为12us的方波,通过调节驱动红外线的载波信号频率可以改变传感器的探测距离。
本设计中迷宫机器人前方共设有五个红外一体传感器,分别探测左方、左前方、前方、右前方、右方共五个方向的墙壁信息。单片机输出PWM波驱动红外传感器的运行,通过更改PWM波的频率,可控制红外发射管的强度,从而实现远近距离的切换探测。左前、右前用于身姿的矫正,防止与墙壁发生碰撞,左、右、前三个 传感器用于探测墙壁信息,判断可行路线。红外传感器的流程图如下所示。
图3-2 红外发射接收一体化程序流程图
红外传感器的发射管以单片机输出的PWM波作为供电电源,红外探测则可通过程序中对PWM波的设置来实现控制。红外光线的发射强度与PWM波的占空比和频率有关,频率越高、占空比越高,其红外发生强度越大。在本设计中,为方便程序的调试,将占空比设定为固定值50%,只通过调节PWM波频率控制红外发射管的强度。
对PWM波的设定和使能程序如下图所示:
图3-3红外发射程序图
3.2.2步进电机的软件控制
步进电机是将电脉冲的信号转变成线位移或角位移的开环控制元件,给电机送一个脉冲信号,电机则转过一个步距角[7]。这一线性关系的存在,加上步进电机只有周期性误差而无累计的误差等特点,使得在速度、位置等控制领域里,用步进电机来操纵变的非常的简单。
步进电机带动车轮的正确运转是迷宫机器人在迷宫中自由行使以及完成各种不同动作的基础。通过软件编程,可实现左右电机的前进、后退、暂停一步和停止四个状态,同时可设置步进电机的前进步数以及最大行驶速度。步进电机也可通过设置运行步数判断行驶距离,在本设计中,迷宫机器人每行驶完一个,步进电机需前进125步。双轮驱动的迷宫机器人,通过对左右步进电机状态与速度的分别控制,则可完成迷宫机器人车身的前进、转弯、后退等复杂动作,实现迷宫机器人在狭窄迷宫中的自由穿梭。电机状态在程序中的控制如表3-1所示。
表3-1 电机状态的程序设置
宏定义
__MOTORSTOP
__WAITONESTEP
__MOTORRUN
__MOTORGOAHEAD
__MOTORGOBACK 取代值 0 1 2 0 1 电机状态 电机停止 电机暂停一步 电机运行 电机前进 电机后退
[8]
3.3迷宫机器人的姿势矫正
迷宫机器人行驶过程中,会因为电压因素、外界光线因素、摩擦力因素等多种无法避免的原因影响其运行效果,造成车身偏移等。若不加以处理,随着行驶距离的增加,偏移量也会累加,会出现碰壁等现象,所以必须在运行过程中自行对以上现象造成的偏移进行校正。机器人的智能化要求能对外界干扰自行作出调整,本设计中迷宫机器人通过红外传感器与步进电机的协调控制实现车身的姿势矫正。迷宫机器人设置为双轮驱动,并通过五个不同方向的红外传感器探测墙壁信息。其实物图如下所示:
图3-4 迷宫机器人实物图
为更直观的展现迷宫机器人的运行方式,在本论文中,采用迷宫机器人简图作为解说对象。如下图所示,简图中只罗列出车身以及五个不同方向的红外传感器和两个由步进电机驱动的车轮。
图3-5 迷宫机器人简图
3.3.1双板的身姿矫正
当机器人左右两边都有挡板时,左前、右前两个传感器以较低频率的PWM波检测两边墙壁距离,若某个传感器探测到墙壁反射的信号,则证明机器人距对应位置的墙壁距离较近,靠近墙壁一侧的车轮快行一步,远离墙壁的车轮慢行一步,完成车身远离墙壁的调整。
图3-6 迷宫机器人双板矫正方式解说图
3.3.2单侧板的身姿矫正
当迷宫机器人检测到只有一侧存在墙壁时,例如图3-5所示情况,机器人只依靠左前方探头探测与墙壁的间距。
迷宫机器人采用双频率判断车身位置[9]。使用低频率PWM波发射红外信号,若检测到反射信号,证明距墙壁距离较近,需要内侧车轮快行一步,外侧车轮慢行一步,调整车身远离。若使用高频率信号未能检测道反射信号,说明与墙壁距离较远,需要外侧车轮快行一步,内侧车轮慢性一步,调整车身向墙壁靠近。
图3-7 迷宫机器人单板矫正方式解说图
3.3.3直角拐弯
迷宫机器人碰到直角需要拐弯时可采用两种方式:原地转弯、弧度转弯。原地转弯为确保转角精度,需车身在拐角处停稳后才可进行,步进电机需进行幅度较大的加速减速过程,这会影响迷宫机器人行驶的速度,且步进电机停止后的重新启动也会消耗不必要的时间。考虑到迷宫机器人的行驶速度,本设计采用转弧度弯的方式。弧度转弯虽然也存在步进电机速度变化的过程,但相对于原地转弯速度变化幅度较小,且电机始终处于运行状态,不存在电机完全静止和重新启动的过程,不仅提高了迷宫机器人的速度,以降低了步进电机的损耗。如图3-6所示,当迷宫机器人进行弧度直角拐弯时,内侧车轮减速,外侧车轮匀速,通过左右两车轮的速度差实现车身行进中的转动。
图3-8 迷宫机器人原地后转解说图
图3-9 迷宫机器人弧度弯解说图
整个转弯过程中,外轮行进步数值和内轮行进步数值的不同会影响到转弯的角度。调试过程中,对迷宫机器人转弯角度与对应两轮行进步数的数据进行了记录。如下表所示:
表3-2 弧度直角拐弯步数设置记录表
外轮行进步数
150
155
155
160
内轮行进步数 30 25 32 36
转弯角度 93° 88° 93° 92°
此数据是以外轮最大速度为50步为参照的,速度越大,外轮造成的“掉步”现象便越明显。所以,每次更改迷宫机器人行驶速度时,其转弯的行进步数也要做出相应的调整[10]。
3.3.4车身后转
当迷宫机器人进入死胡同或到达终点时,为保证后弯中不会碰撞到墙壁,需要在原地完成。迷宫机器人原地后转可通过两个车轮反向转动实现。在本设计中,通过在相同速度条件下,左车轮正转右车轮反转实现。当车身后转完成后,迷宫机器人可倒退几步,通过与迷宫墙壁的碰撞修正车身。
图3-10迷宫机器人原地后转解说图
3.4本章小结
本章重点讲述迷宫机器人运行状态的简单控制,包括光电传感器探测的简单原理和机器人运行中车身的简单动作。通过对各种动作的连贯控制,则可实现机器人在迷宫中的流利运行。
4控制方式的实现
4.1等高图的制作与偏移量的判断
迷宫机器人以较快速度到达指定坐标需要完成等高图的制作[11]。根据已探测到的墙壁信息,以目标点为原点,按照可行路径,根据与原点的距离大小以递增的方式设置等高图。因为转弯时加速减速的过程也需消耗时间,所以等高图设置过程中,须将转弯数作为参考量添加到各个坐标的等高值中。
图4-1 等高图使用流程图
设置三个方向变量确认迷宫机器人的方向,分别设定cDirTemp为相对方向变量、设定GucMouseDir为绝对方向变量和设定cDirTemp2为方向偏移量。当迷宫机器人行驶到一个新的坐标点时,探测周围墙壁信息。以迷宫机器人为参照物,若上方有路时,则将cDirTemp赋值为0,同理,右方有路、下方有路、左方有路时,分别将cDirTemp赋值为1、2、3。若同时存在多条支路,则根据各个方向的等高值进行判断,将等高值最小的方向对应的数字赋值给cDirTemp。
以X、Y坐标为参照物,若迷宫机器人朝向的方向为上,则GucMouseDir被赋值为0,同理,迷宫机器人的朝向为右、下、左,则GucMouseDir对应的值为1、2、3。
迷宫机器人的方向偏移量可根据下列公式进行判断:
cDirTemp2 = (cDirTemp + 4 - GucMouseDir)%4; (4-1)
式4-1通过相对方向与绝对方向之间的关系,计算出与方向选择相关的数据,赋
值给设置的cDirTemp2变量。
根据cDirTemp2的值,可对迷宫机器人运行进行控制。如下表所示:
表4-1 岔路时迷宫机器人的运行状态
变量 取值
0 迷宫机器人运行状态 直行
右转
后转
左转 cDirTemp2 1 2 3
4.2探索法则
探索法则是迷宫机器人在迷宫探索时所遵循的一定规律。按照一定法则探索迷宫可使迷宫探索更加充分,并减少路线的重复探索,节省探索时间。常用的探索法则主要有:左手法则、右手法则、中左法则、中右法则四种基础法则和将以上四种法则综合应用的中心法则[12]。
4.2.1基本法则
左手法则:
当迷宫机器人碰到多条支路的情况时,若左边存在支路,会优先选择左侧探索。若左边不存在支路或左侧支路已探索完成并重新返回到路口时,若前方存在支路,优先探索前方支路。左手法则的探索顺序是:先左,后前,再右。
图4-2 左手法则程序图
右手法则:
当迷宫机器人碰到多条支路的情况时,若右边存在支路,会优先选择右侧探索。若右边不存在支路或右侧支路已探索完成并重新返回到路口时,若前方存在支路,优先探索前方支路。右手法则的探索顺序是:先右,后前,再左。
图4-3 右手法则程序图
中左法则:
当迷宫机器人碰到多条支路的情况时,若前方存在支路,会优先选择前方探索。若前方不存在支路或前方支路已探索完成并重新返回到路口时,若左边存在支路,优先探索左边支路。中左法则的探索顺序是:先前,后左,再右。
图4-4 中左法则程序图
中右法则:
当迷宫机器人碰到多条支路的情况时,若前方存在支路,会优先选择前方探索。若前方不存在支路或前方支路已探索完成并重新返回到路口时,若右边存在支路,优先探索右边。中右法则的探索顺序是:先前,后右,再左。
图4-5 中有法则程序图
中心法则:
中心法则是根据迷宫机器人在迷宫中所处的具体位置,灵活调用其他四种法则,其在五个法则中逻辑较为严谨,便于较快速度探索到终点。在本次设计中,采用中心法则,并进行了一定的改良。
中心法则根据设置的二维坐标,将迷宫分成右上、右下、左上、左下四个部分,当迷宫机器人碰到多条支路的情况时,根据迷宫机器人所在位置的不同,采用不同的探索方式。中心法则始终将指向终点的支路作为优先支路。
当迷宫机器人位于迷宫的右上角时:若机器人方向朝上,则采用左手法则;若机器人方向朝右,则采用右手法则;若机器人方向朝下,则采用中右法则;若机器人方向朝左,则采用中左法则。
当迷宫机器人位于迷宫的右下角时:若机器人方向朝上,则采用中左法则;若机器人方向朝右,则采用左手法则;若机器人方向朝下,则采用右手法则;若机器人方向朝左,则采用中右法则。
当迷宫机器人位于迷宫的左上角时:若机器人方向朝上,则采用右手法则;若机器人方向朝右,则采用中右法则;若机器人方向朝下,则采用中左法则;若机器人方向朝左,则采用左手法则。
当迷宫机器人位于迷宫的左下角时:若机器人方向朝上,则采用中右法则;若机器人方向朝右,则采用中左法则;若机器人方向朝下,则采用左手法则;若机器人方向朝左,则采用右手法则。
4.2.2中心法则的改良
原有的中心法则将整个迷宫分成四个部分,虽然较易寻到终点,但在一些特殊的迷宫地图中,因为其固定的探寻顺序,可能会在接近终点时,因为一条支路的存
在会牵引迷宫机器人行驶向远离终点的方向,这会大大增加迷宫机器人的探索时
间。所以,在原有中心法则的基础上,本设计中做了进一步的改良,在距离终点坐标两个单位长度的方形范围内,增添一个新的坐标区域。
将距离终点两个单位距离的区域命名为中心区域,当探测到中心区域时,若存在多条支路,依然中心法则的探索原则进行迷宫搜索。但当支路走不通或即将行驶出中心区域时,迷宫机器人则优先选择中心区域内的支路探索。这样便令迷宫机器人行驶进中心区域后,始终围绕终点探索,更容易找到进入终点的路线。迷宫区域划分如下图。
图4-6迷宫区域的划分图
中心法则改良后,在绝大多数迷宫条件下,极大的缩短了探索至终点所消耗的时间。很多情况下,全迷宫探索较为繁琐,即使探索出更短路径,但也在探索过程中消耗了大量的不必要的时间。采用改良了的中心法则,当迷宫机器人以最快速度到达终点后,首先判断在已知的迷宫地图中由终点到达起点的等高值,若等高值低于25,则此路线为较短路线,无需再探索迷宫。通过在不同迷宫中多次比较,此种方案更为可行。
迷宫机器人改良后的中心法则在程序设置中,首先对是否是中心区域进行判断,若不在中心区域,根据原有中心法则判断搜索方式。框图如下所示:
图4-7 改良后中心法则框图
4.3本章小结
通过等高图的制作以及探索法则的设定和不断改良,实现了迷宫机器人在迷宫中的灵活运动以及在岔路前进方向的正确判定,迷宫机器人软件设计中的主要逻辑部分成功实现。等高图制作在完成路线记忆的基础上,可实现迷宫机器人以最短路径到达指定地点,省去了探索前进的麻烦。探索法则的设定使迷宫探测有一定的规律可循,可免去不必要的反复探测,节省了探测时间。转弯方向的选择确保了迷宫机器人的基本运行,这三段程序设置,有效的提高了迷宫机器人的效率。
5总结与展望
本文重点讲述了迷宫机器人的软件设计,通过对ARM1138的软件编程,实现逻辑运算和对各种外设的控制,完成迷宫机器人在未知迷宫中自行探索的功能。在迷宫机器人的实验过程中,主要完成的任务有:墙壁信息的探索与存储、转角的设置、等高图的制作以及冲刺过程中较快速度条件下车身稳定性的调整。在设计过程中也遇到了一些难以解决的问题,例如因为轮胎的摩擦力变化造成的步数丢失,尤其是冲刺过程中,特别明显。开始时只能依靠不断清洁轮胎和迷宫地面的灰尘,防止灰尘填充轮胎造成的打滑,后来,通过跟老师的探讨以及不断地网上查找资料,找到了一个有效的解决方案:既是在冲刺过程中,只记录模糊步数,每经过一个路口时,自动对偏移的步数进行修正。这样便有效避免了因步数丢失造成的运行至指定位置过程中,转弯时与墙壁的碰撞。
迷宫机器人的发展空间非常广阔,自行移动机器人是人工智能中极为关键的一步,在未来的科技发展中必会得到更加广阔的应用。
参考文献
[1]Joseph L Jones[美].原魁.邹伟等译.机器人编程技术——基于行为的机器人实战指南.[J]机械工业出版社,2005.13-14
[2]西原主计等[日],牛连强、赵文珍译.机器人c语言机电一体化接口[M].北京:科学出版社,2002.29-30
[3]孙巧榆等.八方向走迷宫算法[J].计算机工程,2004,(1):90-91.
[4]周立功等.Cortex·M3开发指南——基于LM3S8000[M].北京:北京航空航天大学出版社,2005.12-13
[5]张新谊.一种电脑鼠走迷宫的算法[J].单片机与嵌入式系统应用,2007.49-51 [6]关学忠.单片机与TA8435的步进电机细分控制[J].单片机及嵌入式系统应用.2006.26-27 [7]彭小芳;方卫红等,电脑鼠运行的稳定性研究[J]. 现代商贸工业 ,2011,20:284-285 [8]Kenneth A.Reek著,徐波译.C和指针. [J]北京:人民邮电出版社,2003,9.14-15
9-12[9]朱诚;郝丽萍;刘晓培,电脑鼠无线监视平台的设计[J].计算机时代,2011,6:[10]Jean J.Labrosse著,邵贝贝等,译.嵌入式实时操作系统μC/OS-Ⅱ(第二版)[M].北 京.33-34
[11]DAlur,JCrupi,D Malks.”Core J2EE Patterns:Best and opliece wo Practices and Design Strategies”Prentice Hall,2001.3-4
[12]Meehan Joanne,Muir Lindsey.SCM in Merseyside SMEs:Benefits andbarriers.TQM Journal,2008.8-9
附录:
主函数程序:
#include "sys_init.h" #include "Maze.h" #include "suanfa.h" #include "Zlg7289.h" #include "mouse.h"
uint8 GucMouseTask = WAIT; /* 状态机,初始状态为等待 */ uint8 cXdst=0xff,cYdst=0xff; int faze=0,sousuo=0,ok=0,zhongd=0; int __fanhui_sup = 0; int __fanhui_sch = 0; int __fanhui_tostart = 0;
/****************************************************************************** ** Function name: main ** Descriptions: 主函数 ** input parameters: 无 ** output parameters: 无 ** Returned value: 无
******************************************************************************/ main (void) {
uint8 n = 0; /* GmcCrossway[]下标 */ uint8 ucRoadStat = 0; /* 统计某一坐标可前进的支路数 */ uint8 ucTemp= 0; /* 用于START状态中坐标转换 */ mouseInit(); /* 底层驱动的初始化 */ zlg7289Init(); /* 显示模块初始化 */ while (1) {
switch (GucMouseTask) { /* 状态机处理 */ case WAIT: sensorDebug(); voltageDetect(); delay(100000);
if (keyCheck() == true) { /* 检测按键等待启动 */ zlg7289Reset(); /* 复位ZLG7289 */
GucMouseTask = START; } break;
case START: /* 判断电脑鼠起点的横坐标 */ mazeSearch(); /* 向前搜索 */
if (GucMapBlock[GmcMouse.cX][GmcMouse.cY] & 0x08) {
/* 判断电老鼠左边是否存在出口 */
if (MAZETYPE == 8) { /* 修改四分之一迷宫的终点坐标 */ GucXGoal0 = 1; GucXGoal1 = 0; }
GucXStart = MAZETYPE - 1; /*修改电脑鼠起点的横坐标 */
GmcMouse.cX = MAZETYPE - 1; /*修改电脑鼠当前位置的横坐标 */ /* 由于默认的起点为(0,0),现在需要把已记录的墙壁资料转换过来*/ ucTemp = GmcMouse.cY; do {
GucMapBlock[MAZETYPE - 1][ucTemp] = GucMapBlock[0][ucTemp]; GucMapBlock[0 ][ucTemp] = 0; }while (ucTemp--); /*
* 在OFFSHOOT[0]中保存起点坐标 */
GmcCrossway[n].cX = MAZETYPE - 1; GmcCrossway[n].cY = 0; n++;
GucMouseTask = MAZESEARCH; /* 状态转换为搜寻状态 */ }
if (GucMapBlock[GmcMouse.cX][GmcMouse.cY] & 0x02) {
/* 判断电老鼠右边是否存在出口 */
/*
* 在OFFSHOOT[0]中保存起点坐标 */
GmcCrossway[n].cX = 0; GmcCrossway[n].cY = 0; n++;
GucMouseTask = MAZESEARCH; /* 状态转换为搜寻状态*/ } break;
case MAZESEARCH:
ucRoadStat = crosswayCheck(GmcMouse.cX,GmcMouse.cY);
/* 统计可前进的支路数 */
if (ucRoadStat)
中心法则
{ /* 有可前进方向 */
if (ucRoadStat > 1) { /* 有多条可前进方向,保存坐标 */ GmcCrossway[n].cX = GmcMouse.cX; GmcCrossway[n].cY = GmcMouse.cY; n++; }
crosswayChoice(); //中心法则 mazeSearch(); /* 前进一格 */ } else
{ /* 没有可前进方向,回到最近支路*/ while (--n) {
ucRoadStat = crosswayCheck(GmcCrossway[n].cX, GmcCrossway[n].cY);
/* 统计最近支点未走过的方向数 */ if (ucRoadStat) {
objectGoTo(GmcCrossway[n].cX, GmcCrossway[n].cY); if (ucRoadStat > 1) { n++; }
crosswayChoice(); //选择一条支路作为前进方向 现在是以 mazeSearch(); break; }
} //已经探到终点,搜索时的回来 if(GucMapStep[GucXGoal0][GucYGoal0]!=0xff) {
sousuo=0; zhongd=n;
GucMouseTask = FANHUI; __fanhui_sch=1; break; }
if(GucMapStep[GucXGoal0][GucYGoal1]!=0xff) {
sousuo=0; zhongd=n;
GucMouseTask = FANHUI; __fanhui_sch=1; break; }
if(GucMapStep[GucXGoal1][GucYGoal0]!=0xff) {
sousuo=0; zhongd=n;
GucMouseTask = FANHUI; __fanhui_sch=1; break; }
if(GucMapStep[GucXGoal1][GucYGoal1]!=0xff) {
sousuo=0; zhongd=n;
GucMouseTask = FANHUI; __fanhui_sch=1; break; } } break;
/////////////////////////////////////////////////////////////////////////////////////////////////////////// case FANHUI:
ucRoadStat = crosswayCheck(GmcMouse.cX,GmcMouse.cY); /*统计可前进的支路数 */
if (ucRoadStat) { /* 有可前进方向*/
if (ucRoadStat > 1) { /* 有多条可前进方向,保存坐标 */ GmcCrossway[n].cX = GmcMouse.cX; GmcCrossway[n].cY = GmcMouse.cY; n++; }
if(faze==0) frontRightMethod(); //中右法则 else if(faze==1) frontRightMethod(); //中左法则 mazeSearch(); /* 前进一格 */ } else
{ /* 没有可前进方向,回到最近支路*/ while (--n) {
ucRoadStat = crosswayCheck(GmcCrossway[n].cX, GmcCrossway[n].cY);
/* 统计最近支点未走过的方向数 */ /* 若存在未走过的路,则前往该支点,并跳出循环否则继续查找还有未走过的支路。*/ if (ucRoadStat) {
objectGoTo(GmcCrossway[n].cX, GmcCrossway[n].cY); if (ucRoadStat > 1) { n++; }
if(faze==0) frontRightMethod(); //中右法则 else if(faze==1)
frontRightMethod(); //中左法则 mazeSearch(); break;
} else {
sousuo=1; break; } }
if((GmcMouse.cX==0&&GmcMouse.cY==0)||sousuo==1) {
if(faze==0) {
__fanhui_sch=0; __fanhui_tostart = 1;
objectGoTo(GucXStart,GucYStart);//探索完,会到起点。 __fanhui_tostart = 0; GucMouseTask = SPURT; }
else if(faze==1) { ok=0;
objectGoTo(GucXStart,GucYStart); __fanhui_sup=0;
GucMouseTask = SPURT1; } break; } } break; case SPURT:
mouseSpurt(); // 以最优路径冲向终点// ok=1;
__fanhui_sup=1;//TURNSPEED = 90; n=zhongd; faze=1;//修改算法 sousuo=0;
objectGoTo(GucXStart,GucYStart); /* 回到起点 */ mouseTurnback2();
break; default: break; } } }
等高图制作与运动到指定地点:
/****************************************************************************** ** Function name: mapStepEdit
** Descriptions: 制作以目标点为起点的等高图 ** input parameters: uiX: 目的地横坐标 ** uiY: 目的地纵坐标
** output parameters: GucMapStep[][]: 各坐标上的等高值 ** Returned value: 无
******************************************************************************/ void mapStepEdit (int8 cX, int8 cY) {
uint8 n = 0; /* GmcStack[]下标 */ uint8 ucStep = 1; /* 等高值 */ uint8 ucStat = 0; /* 统计可前进的方向数*/ uint8 i,j;
GmcStack[n].cX = cX; /* 起点X值入栈 */ GmcStack[n].cY = cY; /* 起点Y值入栈 */ n++; /*
* 初始化各坐标等高值 */
for (i = 0; i
* 制作等高图,直到堆栈中所有数据处理完毕
*/
while (n) {
GucMapStep[cX][cY] = ucStep++; /* 填入等高值 */
/*
* 对当前坐标格里可前进的方向统计
*/
ucStat = 0;
if ((GucMapBlock[cX][cY] & 0x01) && /* 前方有路 */
(GucMapStep[cX][cY + 1] > (ucStep))) { /* 前方等高值大于计划设定值*/ ucStat++; /* 可前进方向数加1 */
}
if ((GucMapBlock[cX][cY] & 0x02) && /* 右方有路 */
(GucMapStep[cX + 1][cY] > (ucStep))) { /* 右方等高值大于计划设定值*/ ucStat++; /* 可前进方向数加1 */
}
if ((GucMapBlock[cX][cY] & 0x04) &&
(GucMapStep[cX][cY - 1] > (ucStep))) {
ucStat++; /* 可前进方向数加1 */
}
if ((GucMapBlock[cX][cY] & 0x08) &&
(GucMapStep[cX - 1][cY] > (ucStep))) {
ucStat++; /* 可前进方向数加1 */
}
/*
* 没有可前进的方向,则跳转到最近保存的分支点
* 否则任选一可前进方向前进
*/
if (ucStat == 0) {
n--;
cX = GmcStack[n].cX;
cY = GmcStack[n].cY;
ucStep = GucMapStep[cX][cY];
} else {
if (ucStat > 1) { /* 有多个可前进方向,保存坐标 */
GmcStack[n].cX = cX; /* 横坐标X值入栈 */
GmcStack[n].cY = cY; /* 纵坐标Y值入栈 */
n++;
}
/*
* 任意选择一条可前进的方向前进
*/
if ((GucMapBlock[cX][cY] & 0x01) && /* 上方有路*/
(GucMapStep[cX][cY + 1] > (ucStep))) { /*上方等高值大于计划设定值*/ cY++; /*修改坐标*/
continue;
}
if ((GucMapBlock[cX][cY] & 0x02) && /* 右方有路*/
(GucMapStep[cX + 1][cY] > (ucStep))) { /*右方等高值大于计划设定值*/ cX++; /* 修改坐标 */
continue;
}
if ((GucMapBlock[cX][cY] & 0x04) && /* 下方有路 */
(GucMapStep[cX][cY - 1] > (ucStep))) { /*下方等高值大于计划设定值*/ cY--; /* 修改坐标*/
continue;
}
if ((GucMapBlock[cX][cY] & 0x08) && /* 左方有路 */
(GucMapStep[cX - 1][cY] > (ucStep))) { /*左方等高值大于计划设定值*/ cX--; /* 修改坐标 */
continue;
}
}
}
}
运动到指定地点:
void objectGoTo (int8 cXdst, int8 cYdst)
{
uint8 ucStep = 1;
int8 cNBlock = 0, cDirTemp;
int8 cX,cY;
cX = GmcMouse.cX;//电脑鼠当前坐标
cY = GmcMouse.cY;
mapStepEdit(cXdst,cYdst); /* 制作等高图 */
/*
* 根据等高值向目标点运动,直到达到目的地
*/
while ((cX != cXdst) || (cY != cYdst)) {
ucStep = GucMapStep[cX][cY];
/*
* 任选一个等高身值比当前自等高值小的方向前进
*/
if ((GucMapBlock[cX][cY] & 0x01) && /* 上方有路 */
(GucMapStep[cX][cY + 1]
cDirTemp = UP; /* 记录方向 */
if (cDirTemp == GucMouseDir) { /* 优先选择不需要转弯的方向*/
cNBlock++; /* 前进一个方格 */
cY++;
continue; /* 跳过本次循环 */
}
}
if ((GucMapBlock[cX][cY] & 0x02) && /* 右方有路 */
(GucMapStep[cX + 1][cY]
cDirTemp = RIGHT; /* 记录方向 */
if (cDirTemp == GucMouseDir) { /* 优先选择不需要转弯的方向 */ cNBlock++; /* 前进一个方格 */
cX++;
continue; /* 跳过本次循环 */
}
}
if ((GucMapBlock[cX][cY] & 0x04) && /* 下方有路 */
(GucMapStep[cX][cY - 1]
cDirTemp = DOWN; /* 记录方向 */
if (cDirTemp == GucMouseDir) { /* 优先选择不需要转弯的方向*/ cNBlock++; /* 前进一个方格*/
cY--;
continue; /* 跳过本次循环*/
}
}
if ((GucMapBlock[cX][cY] & 0x08) && /* 左方有路 */
(GucMapStep[cX - 1][cY]
cDirTemp = LEFT; /* 记录方向 */
if (cDirTemp == GucMouseDir) { /* 优先选择不需要转弯的方向*/ cNBlock++; /* 前进一个方格*/
cX--;
continue; /* 跳过本次循环 */
}
}
cDirTemp = (cDirTemp + 4 - GucMouseDir)%4; /* 计算方向偏移量*/
if (cNBlock) {
mouseGoahead(cNBlock); /* 前进cNBlock步 */
}
cNBlock = 0; /* 任务清零 */
/*
* 控制电脑鼠转弯
*/
switch (cDirTemp) {
case 1:
switch(GucMouseTask)
{
case MAZESEARCH://探索时,会某点
mouseTurnright();
break;
case FANHUI:
if(__fanhui_sup == 1)
mouseTurnright_nonstop_120();//第一次冲刺,回来
if(__fanhui_sch == 1)
mouseTurnright();//从终点出来,继续按70搜,如果有已探过的则回到某点。 if(__fanhui_tostart == 1)
mouseTurnright_nonstop_100();
break;
case SPURT:
mouseTurnright_nonstop();
break;
case SPURT1:
mouseTurnright_nonstop1();
break;
// default:
// mouseTurnright_nonstop();
// break;
}
break;
// if(GucMouseTask ==)
// mouseTurnright();
// else
// {
// mouseTurnright_nonstop();
// }
case 2:
mouseTurnback();//进入死胡同时,进此。
break;
case 3:
switch(GucMouseTask)
{
case MAZESEARCH://探索时,会某点
mouseTurnleft();
break;
case FANHUI:
if(__fanhui_sup == 1)
mouseTurnleft_nonstop_120();//第一次冲刺,回来
if(__fanhui_sch == 1)
mouseTurnleft();//从终点出来,继续按70搜,如果有已探过的则回到某点。 if(__fanhui_tostart == 1)
mouseTurnleft_nonstop_100();
break;
case SPURT:
mouseTurnleft_nonstop();
break;
case SPURT1:
mouseTurnleft_nonstop1(); break;
}
break;
default:
break;
}
}
/*
* 判断任务是否完成,否则继续前进 */
if (cNBlock) //可能是,最后几个格走这一个函数 {
mouseGoahead(cNBlock);
}
}