跳到主要内容

第 6 周

调试与可靠性

查清机器人为什么不听话(是机械、程序还是传感器的问题),并证明它每一次都能跑好。

  • 70 至 85 分钟
  • 任务: 诊断并修好机械、程序和传感器三类问题,然后用三次运行的测试证明机器人是可靠的。

学生要把自己做出来的反应式机器人变得靠得住。他们会明白,调试就是弄清楚实际结果为什么和预期结果不一样,而问题一共分三大类:机械类(某个实体部件出了岔子)、程序类(指令写错了或漏了)和传感器类(读数、阈值或校准不对)。他们要在专门设计的调试任务里练手,认识变量和计数器这两样用来存放和跟踪数值的工具,还要做可靠性试验:把同一件任务做三遍,逐次记录预期与实际,用来证明机器人是真的管用。

这一周结束时,你将能够

  • 把调试解释成:弄清楚实际结果为什么和预期结果不一样
  • 从症状分辨出机械、程序和传感器三类问题
  • 在程序里用变量或计数器来存放或跟踪一个数值
  • 做一次可靠性试验:把同一件任务做三遍,并记录预期与实际
  • 诊断一台不听话的机器人,并说明该怎么修

学习

调试到底是在做什么

每次运行程序,你脑子里都装着两个结果:预期结果(「应该」发生什么)和实际结果(「确实」发生了什么)。两者对得上,机器人就是正常的。对不上,就说明有问题,而调试就是那种查明它们为什么不一致的侦探工作。

会调试的人不会瞎捣鼓机器人:他们把预期和实际摆在一起比对,仔仔细细看症状,并且每次只改一样东西,好弄清楚到底是哪一改起了作用。

例如:预期:在墙前停住。实际:撞上了墙。-> 有问题要查。; 预期:左转。实际:右转了。-> 拿积木块和你的本意对一对。

问题的三大家族

问题一共分三大家族,能叫出是哪一族,事情就成了一半。机械问题是机器人身体上的实体故障:轮子松了、线缆拖在地上、齿轮打滑。程序问题是指令上的错误:数字写错、少了一块积木,或者积木顺序不对。传感器问题是感知上的毛病:读数不好、阈值设成了错误的数值,或者传感器该校准了。

诀窍是先看症状、先猜家族。如果机器人每一次都以完全一样的方式出错,问题多半在程序里。如果它有时好使、有时不好使,那就怀疑是机械上的毛病,或者传感器读数不稳。

例如:机械:轮子松了,机器人往一边偏。; 程序:数字写错了,机器人转了 2 秒而不是 1 秒。; 传感器:距离阈值太小了,机器人怎么也不停。

变量和计数器:存放并跟踪数值

有时候程序需要记住一个数字。变量就是一个有名字的小盒子,里面装着一个值,而这个值在程序运行时可以变。计数器是一种专门用来计数的变量:它从零开始,每发生一次事情就加一,比如机器人每躲开一个障碍物就加一。

变量也用来存放校准值:那些你只测一次、然后保存起来的数字,好让传感器的读数含义正确。把一个值存起来,意味着你以后可以取用它、修改它、核对它,而不用靠猜。

例如:每躲开一个障碍物就加 1 的计数器。; 为白色地板的亮度存下来的一个校准值。; 一个记着循环已经跑了多少圈的变量。

可靠性:用反复试验来证明

只成功过一次的机器人,说不定只是运气好。可靠性指的是一遍又一遍正确完成同一件活儿,而且没有证据你就不能这么宣称。证据就是可靠性试验:你把同一件任务跑好几遍,每一遍都用同样的测试用例,并且每一遍都写下预期结果和实际结果。

如果三次运行都和你的预期一致,那么在这个测试用例上机器人就是可靠的。如果有一次跑得不一样,你就抓到了一个明明摆在眼前却没被发现的问题,而那次失败的运行,正是你需要的线索。

例如:从同一个起点把「在墙前停住」这件任务跑 3 遍,每一遍都记下来。; 预期三次都是「停住」;实际是「停住、停住、撞上」,说明第 3 次运行有问题。

要认识的词

调试:
弄清楚机器人的实际结果为什么和预期结果不一样,然后把它修好,这整个过程就叫调试。
变量:
程序里一个有名字的存放处,里面的值在程序运行过程中可以改变。
计数器:
一个用来计数的变量:它从某个数字开始,每发生一次事情就加一。
存放的值:
程序放在变量里的一个数字或信息,方便日后取用或修改。
校准值:
你测出来并保存下来的一个数字,好让传感器的读数含义正确,比如白色地板的亮度值。
预期结果:
程序运行正确时「应该」发生的事,也就是你在测试之前作出的预测。
实际结果:
你真的把机器人跑起来之后「确实」发生的事,由你亲眼观察并记录下来。
测试用例:
你为了测试而特意布置出来的一个具体情境,比如「一堵正好在 15 厘米处的墙」。
机械问题:
机器人身体上的实体故障,比如轮子松了、线缆拖在地上,或者齿轮卡死了。
程序问题:
指令上的错误:某个积木块或数字写错了、漏掉了,或者顺序不对。
传感器问题:
感知环节出的岔子:读数不好、阈值不对,或者传感器需要重新校准。
可靠性:
机器人一遍又一遍正确完成同一件活儿的本事,靠反复试验来证明。

注意安全

这一周动手搭建或运行机器人之前,先把这些读一遍。

  • Caution:拧轮子、挪线缆或检查机械部件之前,先把机器人关掉。
  • Caution:运行过程中,让测试区和障碍赛道上别有手、脚和杂物。
  • Note:如果要重做纸质保险杠或模型部件,请使用儿童安全剪刀,并在大人陪同下进行。
  • Note:常常保存你的程序和测试记录,免得刷新浏览器把结果弄丢。

动手做

选择你的路线

这门课你可以用机器人套件、浏览器模拟器,或者不插电、只用家里的材料来上。挑一条就行,随时可以换,你的成果不会丢。

「问题侦探」任务

机器人套件

诊断一台不听话的机器人:判断问题属于机械、程序还是传感器,然后把它修好。

  • 每个任务都先写下预期结果和实际结果。两者之间的差距,就是你要调查的症状。
  • 问一问三大家族的问题:这是实体故障(机械)、指令出错(程序),还是感知不准(传感器)?动手之前先靠症状猜一猜。
  • 每次只改「一样」东西,再跑一遍,并记下实际结果现在是不是和预期一致了。

调试一台不听话的套件机器人

你需要:第 5 周的一台反应式机器人, 「问题侦探」活动纸, 卷尺

步骤

  1. 1请大人或同伴悄悄给一台本来好好的机器人埋一个问题(把轮子拧松、改掉某个积木块里的数字,或者把阈值设坏)。
  2. 2把机器人跑起来,在活动纸上写下预期结果和实际结果。
  3. 3根据症状判断问题属于哪一族,然后按顺序逐个排查最可能的原因。
  4. 4只动你怀疑的那一处,再跑一遍,确认实际结果现在和预期一致了。

做成了是什么样:学生说出正确的问题家族,做出一处有针对性的修改,机器人的实际结果重新和预期一致。

重点看:
  • 预期结果和实际结果都写下来了
  • 正确判断出了问题家族
  • 每次只改了一样东西
  • 修改之后机器人能正常工作

安全:拧轮子或挪线缆之前,先把机器人关掉。 运行过程中,手指要远离转动的部件。

如果不管用

一口气把「所有地方」都改了,结果不知道原因是哪一处
- 把改动一个一个撤回,只留一处;改一样,跑一遍,看是不是就是它。
拿不准问题属于哪一族
- 跑三遍:每次错得一模一样,多半是程序;每次结果都不同,那就指向机械或者不稳的传感器。

再往前一步:给同伴的机器人埋一个问题,看他能不能只凭症状就判断出是哪一族。

三次运行的可靠性试验

机器人套件

把同一件任务跑三遍,每一遍都把预期结果和实际结果对照,以此证明机器人是可靠的。

  • 挑一件明确的任务和一个测试用例(每一遍的布置都完全一样)。预期结果只写一次,因为三遍都一样。
  • 把任务跑三遍,两遍之间「什么都不许改」。逐次记下实际结果,并在「一致吗?」栏里标上是或否。
  • 三次都一致,就说明在这个测试用例上它是可靠的。只要有一次不一致,那就是个问题,用「问题侦探」的步骤去追。

在套件机器人上做可靠性试验

你需要:第 5 周的一台反应式机器人, 三次运行测试记录表, 卷尺

步骤

  1. 1挑一件任务,比如「在墙前停住」,每一遍都把墙放在同样的距离上:这就是你的测试用例。
  2. 2写下预期结果:「机器人在碰到墙之前停住」。
  3. 3从完全相同的起点跑三遍,每一遍都记下实际结果和「一致吗?」。
  4. 4如果有哪一遍对不上,就诊断问题属于哪一族并修好,然后三遍重跑。

做成了是什么样:一张填好的三次运行表格;可靠的机器人三遍都和预期结果一致。

重点看:
  • 三遍用的是同一个测试用例
  • 预期结果只写了一次
  • 记录了三个实际结果和对应的「一致吗?」
  • 任何不一致都追查了原因

安全:保持测试区域通畅,并远离转动的部件。 每一遍都把机器人放回同一条起跑线。

如果不管用

三遍下来结果一点点地在漂
- 检查电池和起始位置:电量渐渐不足,正是造成不可靠的一种机械或供电原因。
对上了两次,第三次失手
- 失手那一遍就是你的线索:那一遍刚跑完就立刻检查传感器读数和实体安装。

再往前一步:再加第四遍和第五遍,看看电池越用越少时可靠性还撑不撑得住。

障碍物计数器

机器人套件

用一个变量当计数器,机器人每躲开一个障碍物就加一,最后再把这个存放的值读出来。

  • 开头先把计数器变量设成 0。机器人每感知到并躲开一个障碍物,就给计数器加 1。
  • 这就是一个存放的值:计数器记着一共处理了多少个障碍物,你在最后可以查看它。
  • 先预测赛道上有几个障碍物,再把你的预测和计数器的最终值对照一下。

用套件机器人数一数躲开的障碍物

你需要:第 5 周的一台反应式机器人, 一段短的障碍赛道, 铅笔和纸

步骤

  1. 1在程序开头,把一个叫「障碍物」的变量设成 0。
  2. 2保留一个读取传感器的循环;在「如果有障碍物」那一支里,既转弯躲开,也给「障碍物」加 1。
  3. 3跑完整条赛道,然后显示或读出计数器的最终值。
  4. 4把计数器和你实际摆放的障碍物数量对照一下。

做成了是什么样:计数器的最终值等于机器人真正躲开的障碍物数量。

重点看:
  • 计数器从 0 开始
  • 只有躲开障碍物时才加 1
  • 读出了最终存放的值
  • 把它和真实数量作了对照

安全:机器人行驶时,让赛道上别有手和脚。

如果不管用

计数器数出来太多了
- 机器人对同一个障碍物加了不止一次 1:要保证每检测到一次才计一次数,而不是每绕一圈循环就计一次。
计数器一直停在 0
- 检查加 1 这一步是不是在「如果有障碍物」那一支里面,而不是在外面:这是程序问题。

再往前一步:再加一条规则:计数器到了 3 以后,机器人就停下来并发出完成的信号。

给机器人编程

Build a program from blocks, then run it on the simulator. On the kit path, use the same steps in your robot's app; unplugged, act the blocks out on a floor grid. Your program saves on this device.

障碍物计数器程序

一个把计数器设为 0、用循环读取传感器、每躲开一个障碍物就给计数器加 1 的程序。

就绪

添加积木块

事件与执行

移动

控制

数据

输出

变量与计数器

count

你的程序

  • 重置计数器
  • 前进
第 1 列,第 1 行第 2 列,第 1 行:red 标记red marker at column 2, row 1第 3 列,第 1 行第 4 列,第 1 行:red 标记red marker at column 4, row 1第 5 列,第 1 行第 6 列,第 1 行:red 标记red marker at column 6, row 1Goal zone at column 6, row 1Robot at column 1, row 1
  • 机器人(箭头指向它的朝向)
  • 终点区(虚线框)
  • 彩色标记(圆点)

地图:一片 6 × 1 的网格。 机器人从第 1 列、第 1 行出发,朝向右。 终点区在第 6 列、第 1 行。 有 3 个彩色标记。

就绪.

可以运行了。 · 0 steps

机器人状态

1
1
朝向
前方距离
5
触碰
没有接触
在线上
光线
80
在终点区内
碰撞次数
0
步数
0

机器人在第 1 列、第 1 行,朝向右。 前方距离:5 格。 触碰:没有接触。 在线上:否。 光线:80。 不在终点区内。

日志输出

还没有记录任何内容。

  • Heads up: This program has no safe stop behavior. Add a safe stop so the robot stops when it is done or blocked.

修好坏掉的刹车

这个程序本该让机器人停在墙前的那一格,可它距离判断里的一个数值写错了,导致它停错了地方。先预测问题属于哪一族,改动「重复直到」条件里的那一个数值,然后反复运行直到它停对为止。

就绪

添加积木块

事件与执行

移动

控制

数据

输出

变量与计数器

还没有。

你的程序

  • 重复直到
    • 前进
  • 任务完成
第 1 列,第 1 行第 2 列,第 1 行第 3 列,第 1 行第 4 列,第 1 行第 5 列,第 1 行:墙Goal zone at column 4, row 1Robot at column 1, row 1
  • 机器人(箭头指向它的朝向)
  • 终点区(虚线框)
  • 墙(灰色,带 X)

地图:一片 5 × 1 的网格。 机器人从第 1 列、第 1 行出发,朝向右。 终点区在第 4 列、第 1 行。 有 1 面墙。

就绪.

可以运行了。 · 0 steps

机器人状态

1
1
朝向
前方距离
3
触碰
没有接触
在线上
光线
80
在终点区内
碰撞次数
0
步数
0

机器人在第 1 列、第 1 行,朝向右。 前方距离:3 格。 触碰:没有接触。 在线上:否。 光线:80。 不在终点区内。

日志输出

还没有记录任何内容。

预测

Commit to a guess before you test - then see how close you were. Your predictions save automatically.

怎样验证:把三遍都跑完,记下实际与预期以及「一致吗?」,再把你的预测和真实情况对照。

怎样验证:把可能的原因逐个排查,看看你预测的那一族是不是最终解决问题的那一族。

怎样验证:跑完赛道,读出计数器,再把它和你预测的数字以及真实的障碍物数量对照。

测试与改进

三次运行的可靠性测试

挑一件任务和一个测试用例。预期结果只写一次,然后什么都不改,把同一件任务跑三遍。逐次记下实际结果,以及这一遍对没对上。

要测量的:三遍里,每一遍的实际结果是否和预期结果一致

Run预期结果实际结果一致吗?(是/否)

问题诊断记录

每个调试任务都记下症状、你怀疑的问题家族、你尝试的那一处改动,以及它有没有把差异解决掉。

要测量的:到底是哪一族的问题,以及一处有针对性的改动有没有把它修好

症状怀疑的家族尝试的那一处改动修好了吗?(是/否)

调试任务

Each robot below misbehaves on purpose. Work out whether the bug is mechanical, in the program, or with a sensor - then check the fix.

在原地打转的机器人

一台本该笔直向前开的机器人,却在原地打转,一圈一圈地转个不停,就好像一个轮子往前、另一个轮子往后。

症状:两个电机都在转,机器人却在原地旋转而不是往前走,而且每一遍都朝同一个方向转。

提示:盯着轮子看:两个都在转,但方向相反,而且什么都没松。想一想其中一个电机是怎么接线或怎么设置的,别去想那些行驶指令。

查看解决办法

解决办法:把接反的那个电机的接线换过来(或者把那一个电机的方向设置翻过来),让两个轮子一起往前转。再跑一遍,确认机器人现在是笔直向前,而不是原地打转。

可能的原因

  1. 1有一个电机接反了,所以它的轮子转错了方向。
  2. 2有一个电机的方向设置和另一个是反的。
  3. 3两个电机是镜像安装的,程序却把它们当成朝同一个方向来驱动。

那堵它不肯停下的墙

一台机器人本该往前开,等距离传感器说墙近了就停下,可它却一头撞上墙,还一个劲儿往前顶,从来不停。

症状:每一遍机器人都不停:实际结果就是撞车,尽管程序里确实写着一条停止指令。

提示:传感器读得好好的,停止积木块也在。把循环里那个比较条件大声念出来:随着墙越来越近,那个本该让机器人停下的条件,究竟有没有变成真过?

查看解决办法

解决办法:把比较运算符反过来(或者把它两边互换),好让距离变小时停止条件变成真。再跑一遍,确认机器人在墙前停住了。

可能的原因

  1. 1比较写反了:它在距离「大于」某值时才停,而不是「小于」,所以机器人越靠近,这个条件反而永远不成立。
  2. 2比较式的两边写反了。
  3. 3用错了运算符(本该是 < 却写成了 >),让停止条件永远触发不了。

数过头的计数器

一台机器人开过三个标记,本该报出 3,却报了一个像 47 这样的大数。

症状:计数器的最终值比真实物体的数量大得多:它每绕一圈循环就往上涨,而不是每个物体只涨一次。

提示:一边开一边盯着计数器往上跳。它是每个物体加 1 一次,还是每绕一圈循环就加一次,哪怕前面根本没有新的物体?

查看解决办法

解决办法:在开头把计数器清零,并把「加 1」挪到检测到「新」物体的那个条件里面。再跑一遍,确认最终计数和真实的物体数量一致。

可能的原因

  1. 1「加 1」写在了「我看见物体了吗?」这个判断的外面,所以每绕一圈都会计数。
  2. 2每一遍开始时都没有把计数器清零。
  3. 3机器人在同一个物体旁边待了好几圈,每一圈都把它数了一遍。

一到亮处就失灵的循线机器人

一台循线机器人昨天跑得好好的。今天换到一个明亮得多的房间,它每次都径直开出线外,而程序压根没动过。

症状:机器人对线视而不见,完全不修正方向,尽管同样的代码在昨天的光线下修正得好好的。

提示:代码和昨天一模一样;变的是房间。今天把线上和线外的实时光线数值都读一读,再把这两个数和程序里的阈值比一比。

查看解决办法

解决办法:读出今天线上和线外的光线数值,在两者正中间挑一个新阈值,把这个校准值存下来,再跑一遍。机器人应该又能循线了。

可能的原因

  1. 1光线阈值是照着昨天那个更暗的房间校准的,现在不适用了。
  2. 2更强的光线把所有读数都抬到了阈值以上,于是「在线上」这个判断永远不成立。
  3. 3传感器没有针对今天的光线条件重新校准。

永远跑不完的机器人

一台机器人本该往前开、躲开几个障碍物,然后在终点停下,可它一直开、一直躲,永远不结束,就算已经到了终点也不停。

症状:机器人从来不结束程序:它没完没了地重复着躲避加行驶的行为,一直不停。

提示:躲避这件事本身是好使的。问题在于机器人永远出不了那个循环。找一找出口:有没有哪个条件能在到达终点后结束这个循环?

查看解决办法

解决办法:给它加一个出口:用一个在终点结束的「重复直到」,或者一句「如果到了终点就停」,让循环有机会结束。再跑一遍,确认机器人一到终点就停下。

可能的原因

  1. 1这段行为被放进了一个没有出口的无限循环里。
  2. 2某个「重复直到」的条件永远不可能变成真。
  3. 3到达终点时既没有「安全停车」,也没有「任务完成」。

代码没毛病,却还是往一边跑偏

一台机器人的程序是对的,也没改过(上周它还是直着走的),可现在只要一往前开就往一边打弯,哪怕是一段又短又没有障碍物的路。

症状:机器人不走直线,每一遍都朝同一边跑偏,虽说代码一个字都没改。

提示:它每一遍都以同样的方式出错,可上周就已经证明程序是对的。动代码之前,先看看机器人的机身和轮子,或者模拟环境里的路面和安装设置。

查看解决办法

解决办法:别动代码。把两个轮子重新装好、拧紧,清掉任何拖地的线缆或碎屑(模拟环境里则把路面和对齐设置复位)。再跑一遍,确认它又能走直线了。

可能的原因

  1. 1某个轮子或车轴松了,或者没完全插到位。
  2. 2有一根线缆或某个部件在一侧拖着地面,或者有个轮子蹭到了车架。
  3. 3在模拟器里,某项路面或对齐设置让一侧发生了打滑。

刹得太晚的那一脚

一台机器人用距离传感器在墙前刹车。慢速时它停得干干净净,可一旦提速就冲过头撞到墙上,而阈值一模一样没变过。

症状:高速时机器人停得太晚,撞上了墙;低速时同一个程序却能及时停住。

提示:慢的时候够用的阈值,快起来就不够了:两次读数之间机器人跑得更远。想一想速度和刹车阈值是怎样互相配合的,而且每次只改其中一个。

查看解决办法

解决办法:每次只改一样:要么把行驶速度降下来,要么把距离阈值调大好让它更早刹车。用目标速度再跑一遍,确认它能及时停住。

可能的原因

  1. 1高速时机器人在两次读数之间跑得更远,所以一个贴得很近的阈值触发得太晚。
  2. 2阈值是照着比现在更慢的速度调出来的。
  3. 3传感器读取的频率太低,在这个速度下来不及发现墙。

知识检测

回答这几题,检验一下你能否按家族给问题定性,并证明一台机器人是可靠的。

  1. 1. 诊断一下最可能是哪一类问题。

    一台循线机器人昨天还好好的。今天它每次都径直冲过了那条线,可代码根本没改过。今天房间亮得多。

  2. 2. 什么是调试?

  3. 3. 一台机器人上周还走直线。它的程序没改过,可现在每一遍都往一边打弯。这最可能属于哪一族问题?

  4. 4. 什么是计数器?

  5. 5. 在可靠性试验里,「预期结果」指的是什么?

  6. 6. 在可靠性试验里,为什么要把同一件任务跑三遍?

已答 0 / 6

反思

你的反思会自动保存。

下周预告

下周我们要把可靠性用起来:规划一次完整的自主任务,让机器人自己安全地跑完全程。

  • 保存好你的三次运行测试记录和「问题侦探」表:可靠的行为正是下周那项任务的基础。
  • 想一想有什么活儿,是你的机器人能从头到尾自己做完、不需要任何人操控的。
  • 给你的套件充好电、把模拟器加入收藏夹,或者把你的纸板机器人和赛道准备好。

完成第 6 周

完成以下内容,即可结束本周并解锁下一周:

  • 每一族至少诊断并修好一个问题,并记录症状和解决办法 (not done yet)
  • 完成一次三次运行的可靠性试验,并记录预期与实际 (not done yet)
  • 用一个计数器变量跟踪躲开的障碍物 (not done yet)
  • 知识检测至少答对 5 题中的 4 题 (not done yet)
  • 写下你的反思 (not done yet)