×

AI解迷宫机器人

消耗积分:2 | 格式:zip | 大小:7.77 MB | 2023-07-11

王飞云

分享资料个

构建机器人

要构建机器人,我们只需遵循 TI RSLK 基本套件构建说明即可。我们已将它们附在这篇文章的示意图部分。我们对说明所做的唯一更改是我们没有切断 PCB 上的任何连接。TI 提供的说明将帮助您完成除了构建面包板和将面包板放在机器人顶部之外的所有操作。

在将面包板放在机器人顶部之前,请按照本文原理图部分中的面包板原理图将 LED 连接到它上面。以后很难做到这一点,因为电线连接将位于面包板下方。然后,为了将面包板连接到机器人,我们使用透明胶带。您可以使用任何您喜欢的东西,包括套件中提供的螺丝,但胶带很便宜,而且比试图拧穿面包板容易得多。

编程机器人

要对机器人进行编程,必须将其插入计算机上的 USB 端口,并且必须使用电机板(黑板)上的开关关闭电池。然后,在 Code Composer Studio (CCS) 中打开可下载项目后,单击“调试”按钮。这将编译代码并将其加载到机器人上。一旦 CCS 完成加载代码,它就会停止机器人并等待您按下黄色播放按钮来调试机器人。可以,也可以按红色停止键,不用插电就可以使用机器人。

操作机器人

 
pYYBAGOrz2OAAQncAA0zNX88ohA919.png
 

在没有 USB 电源的情况下打开机器人:断开 USB 并确保机器人中有电池。如果您之前拔下了上面显示的 2 根电线,请将它们插入,然后将靠近左轮的电机板(黑板)上的电源开关滑动到打开位置。

左 Launchpad 按钮:告诉机器人解决一个新的迷宫或停止它正在做的任何事情。充当切换按钮。

右 Launchpad 按钮:告诉机器人显示它找到的最短路径。如果迷宫没有完全解决,它将显示目前为止所知道的尽可能多的迷宫。

使用 USB 调试机器人:如果您想在使用机器人时查看控制台输出,请确保您有足够长的微型 USB 电缆让机器人四处漫游;套件中只有一个短的。断开下面所附 TI 构建说明末尾提到的 2 根电源线和地线(如上图所示)。通过 USB 将机器人插入计算机,然后将电机板上的电源开关滑动到打开位置以打开电机。重要的是不要从 USB 运行电机,因为它们的行为与使用电池供电不同。这就是为什么我们断开那 2 根电线并打开电池。

关闭机器人:将电机板(黑板)电源开关拨到关闭位置。然后按下开关旁边的电源按钮关闭机器人。

整体算法

机器人使用具有 4 种可能状态的状态机:停止、运行、获胜和解决。

  • 停止状态:当机器人开启或用户在解决迷宫或显示解决方案的过程中停止机器人时。
  • 运行状态:当它正在解决一个新的迷宫时。
  • 获胜状态:如果它在迷宫中找到了宝藏。
  • 求解状态:当机器人正在显示解决迷宫的最短路径(解决方案)时。

机器人使用 SysTick 计时器通过中断定期读取线传感器。线路传感器无法自行发送中断,因此这是最有效的替代方案。

当机器人第一次进入 main() 函数时,它会初始化所有需要初始化的东西:它的状态、时钟速度、电机、保险杠、线传感器、板载按钮、板载 LED、面包板 LED、定时器 A0、SysTick 定时器, 并中断。然后它进入一个永远运行的 while 循环。

在这个 while 循环中,机器人将线传感器的值保存到一个临时变量中,以防 SysTick 定时器中断激活中间循环并更改全局线传感器变量的值。然后它会根据所处的状态采取不同的行动。

如果机器人处于停止或获胜状态,SysTick 计时器将禁用其中断,然后机器人等待中断,中断可能来自保险杠开关、Launchpad 板上的按钮之一或计时器 A0(稍后讨论并用于面包板上的 LED)。将机器人设置为等待中断将其置于低功耗模式,因此不会浪费电力。

如果机器人处于运行状态,则机器人解决迷宫问题。该算法的详细信息在下面的“迷宫解决算法”部分中进行了解释。

如果机器人处于求解状态,则机器人会显示出最短路径以解决迷宫问题。该算法的详细信息在下面的“最短路径算法”部分中进行了解释。

寻找最短路径的逻辑

 
pYYBAGOrz3GAYtaMAARqKpaw3lk259.png
 

当机器人在执行下面“迷宫解决算法”部分中的算法时,它还需要存储最短路径来解决它正在解决的迷宫问题。为此,使用了一个数组。每次机器人在十字路口转弯(不仅仅是在别无选择的地方转弯)或掉头时,它都会将转弯存储在数组中。然后,如果最后一个转弯不是掉头,它会检查最后 3 个转弯是否可以简化为其他东西。

例如,机器人向左转,然后掉头,然后向左转,可以简化为在那个十字路口直行。因为它是左转后掉头的,显然原来的左转是错误的。

以下是可以简化的模式。“L”= 左,“R”= 右,“S”= 直线,“U”= 掉头。

  • 南 -> R
  • LUL -> S
  • 规则 -> U
  • LUS -> R

迷宫解决算法

当机器人正在解决一个新的迷宫时,该算法就会运行。它由多个 if-else-if-statements 组成,其中只有一个执行。if 语句遵循左偏规则,这意味着机器人总是走它可能走的最左边的路径。

首先,如果线传感器读取全白,这意味着机器人不在一条线上,它可能只是跑出了线。机器人因此转身并重新读取线传感器以获得更新值。它还添加了一个“U”来表示最短路径数组中的掉头。

如果所有传感器都是黑色的,则机器人位于丁字路口或四向路口。因为机器人偏左,它会走左路,重新读取线传感器以获得更新值,并在最短路径数组中存储一个“L”。在左转之前,机器人向前移动半辆汽车,使车轮与十字路口对齐。它还在左转时保持面包板上的左侧 LED 亮起。

如果机器人找到了宝藏,它会向前移动一点点并重新检查以确保它真的找到了宝藏。如果是,机器人进入胜利状态,停止电机,并设置定时器 A0 使机器人顶部面包板上的 LED 闪烁。

如果有左转弯,机器人会向前移动半辆车,看看是在十字路口还是只是转弯。然后它向左转,同时打开面包板上的左侧 LED,如果它是一个交叉路口而不仅仅是一个转弯,它还会在最短路径数组中添加一个“L”。

如果有右转弯,机器人首先向前移动一点点,然后重新读取线传感器以确保它是右转弯,左转弯不是一个选项。如果左边不是一个选项,它会向前移动汽车的剩余一半并检查直行是否是一个选项。然后它要么直行要么右转。如果它直行,它会在最短路径数组中保存一个“S”。如果它走对了,它会在转弯时打开右侧的面包板 LED。

接下来的 else-if 语句用于简单地沿着一条直线,因为其他特殊条件都不为真。为此,它会找到最外面的线传感器并相应地进行校正。例如,如果最左侧的线传感器检测到黑色,则机器人应通过向左转大量并同时直行来进行纠正。

最短路径算法

当机器人显示通过已解决的迷宫的最短路径时,该算法就会运行。就像迷宫解决算法一样,它由多个 if-else-if 语句组成,每次 while 循环运行时只执行其中的一个。

首先,如果机器人的第一个转弯是掉头,它会向前移动 1 个汽车长度,然后掉头。它需要先向前移动,以便在它转身后线传感器处于一个好的位置。

如果机器人已经展示了目前在迷宫中解决的所有问题,但仍未找到宝藏,则机器人切换到运行状态并开始解决迷宫问题。

如果机器人找到了宝藏,它的行为与它在迷宫解决算法中的行为完全相同。它向前移动了一点点并重新检查以确保它真的找到了宝藏。如果是,机器人进入胜利状态,停止电机,并设置定时器 A0 使机器人顶部面包板上的 LED 闪烁。

如果前方有左转和/或右转弯,这意味着前方有潜在的交叉路口,机器人会首先向前移动半辆车,并检查是否可以直行。然后,它使用它对左、直和右可用性的了解来确定这是一个十字路口还是一个转弯。如果它只是一个转弯,它会跟随转弯。如果是十字路口,它会根据最短路径数组的指示行事。

最后,如果上述 if 语句均不成立,机器人将像在迷宫解决算法中一样简单地沿着这条线走。

循环迷宫

我们的代码使机器人能够通过循环解决迷宫问题,并显示它找到的通往宝藏的路径。然而,它不一定会找到穿过这样一个迷宫的最短路径,因为循环允许通往宝藏的多条路径。

要修改算法以找到带环路的最短路径,机器人需要在移动时跟踪距离或时间,以便识别它已经访问了哪些交叉路口以及它从每个交叉路口行进的方向。它还需要沿着迷宫中的每条线行进,以确保它找到了最短路径。

其他杂项算法

SysTick 计时器/线路传感器:SysTick 计时器设置为每 0.025 秒发送一次中断,此时机器人将读取 8 个线路传感器。为读取线传感器,代码使用 LED 为每个传感器的电容器充电 10µs。接下来,它将线路传感器切换为输入并使电容器放电 800µs。然后读取每个传感器的数字值。最后,LED 被关闭。该算法之所以有效,是因为每个线传感器中的电容器在黑纸和白纸上以不同的速率放电。

定时器 A0/LED 闪烁:定时器 A0 在机器人开启时初始化,但直到机器人顶部面包板上的 1 个或多个 LED 需要开始闪烁时才启动。然后,它通过使用中断调用上次启动时提供给它的函数来处理闪烁适当的 LED。因为定时器A0只是一个16位的定时器,定时器还使用了一个计数器,所以该函数只在每50次中断时调用一次,而不是每次中断都调用一次。

电机:电机使用 PWM(脉冲宽度调制)运行。为了使轮子旋转得更快,它们在更高的时间百分比(每个周期几微秒)内被赋予数字 1 值。当电机需要做某事时,它们会得到一个方向并被阻止休眠。然后根据他们需要的速度为他们提供适当的 PWM 信号。

缓冲开关:缓冲开关在 Launchpad 板上使用低电平有效逻辑和内部上拉电阻。当按下保险杠开关时,会发生中断,使机器人打开绿色 LED,反转,转身 180 度,然后继续解决迷宫。它还向最短路径数组添加了一个“U”。

开始/停止按钮:Launchpad 板上有左右按钮。它们的功能在上一节“操作机器人”中进行了描述。每个按钮在释放时发送中断,而不是在按下时发送中断。这确保了当用户仍在按下按钮时机器人不会突然开始移动。

检查宝藏:作为解决迷宫和显示最短路径算法的一部分,机器人会不断检查是否找到宝藏。它通过寻找一个黑色传感器,然后是一个白色传感器,然后是另一个黑色传感器来检测它是否找到了宝藏。只要存在黑到白和白到黑的过渡,就可以有任意数量的黑白传感器。它不检查黑-白-黑-白-黑,即使宝藏看起来就是这样,因为这需要机器人很好地居中,从而使其不可靠。我们也从未使用黑-白-黑算法和上面“迷宫解决算法”部分中描述的对获胜条件的双重检查得到误报。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'AI解迷宫机器人',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);