第二部分 编程基础 | 第8章:寻迹机器人
在本章中,我们将使马里奥依靠传感器来沿着亮色背景上的一条暗色线移动,我们称之为寻迹机器人(Line-Following Robot)。寻迹机器人是机器人编程中非常经典的案例。
简单了解机器人导航
通过编程来实现机器人导航最简单的方式是让其沿着一条预先设定好的轨迹线移动。寻迹机器人可以利用摄像头识别来沿着地面上的一条线移动,或是利用金属探测器来沿着嵌入在路面里的金属线移动。事实上,在乐高工厂中就有类似的机器人。
马里奥通过将传感器向下放置,可以沿着地面上预先设定好的线移动。马里奥的传感器可以发出光线,并检测物体表面返回的光线。你可以在浅色地面上放置深色线条,或者深色地面上放置浅色线条。无论哪种方式,线条颜色和地面颜色必须有足够的对比度。
选择模块
已经有人证明,所有的程序都可以只利用三种结果完成,分别是顺序结构、循环结构、选择结构。前两种结构我们已经学习过了,现在让我们了解下选择结构。选择结构首先会给出一个条件判断,根据不同的判断结果,执行不同的程序。

黄色调色板里的选择模块,如上图所示,根据模块左侧的判断条件,当判断结果为真时,执行后面上方的程序,当结果为假时,执行后面下方的程序。
为了更好地理解条件判断结果的值,我们先来了解下逻辑值的概念,一般也称之为布尔值(Boolean Values)。
理解数据类型
在乐高Boost编程中会用到两种数据类型:数字和逻辑值。数字类型的数据之前在电机模块、传感器模块的使用中已经接触过了,比如电机的速度值,就是一个-100到100之间的数字。而逻辑值只有两个结果,真(√)和假(×)。例如,判断条件为:传感器探测到的距离小于等于5?如果探测到的距离为3,那么返回结果就是真(√)。

在模块中,数字类型的输入用半圆表示,而逻辑值类型的输入用三角型表示,如上图所示。
比较模块
比较模块用来比较两个数字,并返回一个为真或者为假的逻辑值。你可以在灰色的数学模块中找到他们。
比较模块的输入值,可以是常数(常数是指固定不变的数值),也可以是传感器的输出结果等,例如,你可以将传感器的输出结果与某个条件进行比较。下面是一些比较模块及其返回值的示例。

关于全部比较模块的详细介绍,参见 https://www.legofind.com/archives/1618
寻迹版本的马里奥

将马里奥上的传感器朝向地面(如上图所示),以便为寻迹做好准备。
单选择模块寻迹
想象一下让机器人沿着轨迹标识的明暗边界处行进,如下图所示。这种情况下,当机器人行进时,如果检测到的颜色是背景亮色,则机器人向着暗色轨迹线的方向移动(下图A),反过来,如果检测到的颜色是轨迹线的暗色,则机器人向着背景亮色的方向移动(下图B),最终的行进结果如下图C所示,会沿着轨迹线的边界处“之”字式曲折前进。

上述思路的伪代码如下:
- 无限循环开始
- 如果传感器检测到暗色
- 向右侧转向
- 否则
- 向左侧转向
- 如果传感器检测到暗色
- 返回无限循环开始处
用乐高BOOST编程实现上述伪代码,结果如下图所示。

正如上图中你看到的,程序中使用了选择模块,来决定机器人是左转还是右转。程序中利用一个小于比较模块来对传感器探测的光线强度进行判断。比较模块中的数值5(上图序号2所示),我们称之为门槛值,用于区别传感器在背景色和轨迹线上获得的光线强度值。
上图中序号5的环境光线强度指示器模块用来实时显示传感器探测到的光线强度值,设置这个模块可以帮助你进行程序调试。
乐高BOOST传感器会探测物体返回的光线强度,返回值从0(最暗)到10(最亮)。将传感器探头对准轨迹线和背景色的边界处,将此事传感器得到的光线强度值设置为门槛值。通常情况下该值设为5即可,如果不行,可以尝试修改这个门槛值。
通信延迟的问题
当你测试上面程序的时候,你会发现马里奥的移动会有一些卡顿,这是因为每次移动后定时限移动基底转向模块会有一个刹车动作。要使机器人移动的更加顺滑,你可以尝试使用驱动基底移动转向模块(无时间限制)来代替,将转向调整时间间隔设置为0.1秒钟,如下图所示。

理论上,上面的程序没问题,但实际中却无法正常工作,原因就是乐高BOOST APP所在的智能设备和BOOST集线器之间的蓝牙通信延迟太大了。过大的延迟导致传感器的信息读取和电机的控制指令发送都过晚,从而使机器人无法正常工作,如下图所示。

如上图描述的一样,由于通信延迟过大,在收到新的指令前,机器人已经驶离轨迹线,导致寻迹失败。即便是将机器人的移动速度降至最低,也不能保证完全克服该问题。
利用选择模块来改进寻迹程序
在前面的程序中,我们通过查看传感器的光线强度检测值是否在门槛值5以下,来判断机器人是否检测到暗色的轨迹线。现在,我们加入一个灰色区域检测,这个灰色区域是传感器在介于暗色轨迹线和亮色背景色之间时所探测到的颜色(因为传感器的检测区域是一个小范围的区域,而不是一个点,所以会将既有暗色又有亮色的一个小范围的区域识别为灰色)。换句话说,如果传感器检测到灰色,那么说明已经到达轨迹线与背景色之间的边界地带,此时便可告知马里奥停止转向并直线前进,这样可以让马里奥更快的寻迹。
针对三种条件(亮色、暗色、灰色)的判断,我们需要用到两个选择模块,下面是伪代码:
- 无限循环开始
- 如果传感器检测到暗色
- 向右侧转向
- 否则
- 如果传感器检测到亮色
- 向左侧转向
- 否则
- 直行
- 如果传感器检测到亮色
- 如果传感器检测到暗色
- 返回无限循环开始处
BOOST编程实现如下图所示。

第一个选择模块用来判断传感器是否探测到暗色的轨迹线,如果是,则利用最上面的电机模块让马里奥驶离轨迹线;如果否,则会进入到第二个选择模块,来判断传感器是否检测到亮色背景色,如果是,利用中间的电机模块让马里奥驶向轨迹线,如果否,说明传感器的光线强度检测值介于5至7之间,说明马里奥在灰色区域,此时利用最下方的电机模块让马里奥直行。
监视传感器读数
可以通过在画布空白处任意位置单独放置一个环境光线强度指示器模块,来对传感器读数进行实时监控。你也可以将它放置在比较模块里,如下图所示(A代表传感器在暗色轨迹线的位置,B代表在边界的位置,C代表在亮色背景处的位置)。

你可以利用起监视作用的环境光线强度指示器模块,来进行调试。将你的机器人传感器分别对准轨迹线、空白背景以及他们的分界线,来看看传感器的返回值有什么变化。
等待自定义条件
前面的程序中我们讲到利用距离触发模块,来等待传感器探测到的距离小于某个值时触发程序执行。如果我们想利用其它条件来触发程序执行该怎么办?比如当距离值大于某个值。这时我们就需要用到条件“真”等待模块(如下图所示)。该模块会暂停程序执行,直到其判断条件变为真。

回到刚才的问题,如果我们想在传感器探测距离大于某个值时触发程序执行,那么就可以利用上面介绍的 “真”等待模块来实现,如下图所示。

在上图中,左上角的距离等待模块A,会暂停程序执行,并连续查询传感器的距离检测值读数,直至满足参数的设置要求(小于等于4,也就是小于5,因为传感器的距离检测值只包含整数)。我们也可以利用一个 “真”等待模块来实现相同的功能,如上图B所示。利用一个小于逻辑运算模块,来将左侧传感器的实时读数,和右侧的设定值(5)来比较,如果传感器读数小于5,则小于逻辑运算模块会返回“真”,从而触发后续程序执行。在学会并理解上面的程序后,我们就可以灵活的利用不同的逻辑运算模块,来实现自定义条件判断。上图C程序,就是实现当传感器距离大于4时,触发后续程序执行。
利用自定义条件触发程序执行
比如,你想在某个逻辑条件为“真”时,触发程序执行,那么你就可以使用条件真启动模块,如下图所示。

对于我们前面用到的,当探测器探测到的距离小于等于4时,触发程序执行,我们就可以利用条件真启动模块来实现相同的功能,如下图A和B所示。同时,利用条件真启动模块,我们可以自定义程序执行的触发条件,因此更为灵活。下图C便是设置当检测距离大于4时,触发后续程序执行。

颜色比较
当传感器读取到的颜色与指定颜色一致时,利用颜色等待模块和颜色触发模块可以触发后续程序执行。下图给出了颜色等待模块(A)和颜色触发模块(B)以及他们的等效程序。你也可以利用其他逻辑比较模块来实现更多的颜色逻辑触发条件。比如,你可以用一个不等于比较模块,来设定触发条件为当检测到的颜色不为红色时,触发程序执行。

颜色有关的几个模块,需要指定或返回具体的颜色,而不是数字,然而,这里面的几种颜色,实际上也是用数字来表示的,具体如下:
0=无色,1=黑色,3=蓝色,5=绿色,7=黄色,9=红色,10=白色。
你可以利用等于逻辑模块和不等逻辑模块来判断传感器读取到的颜色与指定的颜色相同还是不同。但是设定传感器读取到的颜色小于指定颜色,这样是不可以的。下面是利用“真”等待模块来实现程序暂停执行直到传感器检测不到颜色为止的例子。

当条件为真时重复执行一组动作
条件“真”循环模块(如下图所示)将重复执行所包含的程序,只要其判断条件为真。你可以考虑下利用这个模块可以实现哪些有趣的功能。
