跳到主内容

FLL 机器人设计和软件编程

FLL 比赛时候的机器人设计并没有一个标准答案, 这个和比赛策略/软件设计强力相关, 而且也是需要迭代进行的.

https://mermaid.ink/img/pako:eNqrVkrOT0lVslJKy8kvT85ILCpR8AmyjslTAIJn66e82Dr7-dppz6cuVdDVtVN4NmfX05krnuza9WLdvhfrFoLFXuxd_2T3tud7pj1f0Q0SqHmxf-2T3YtrUHQr6SjlphblJmamAG2qBpkeo1SSkZqbGqNkBWSmpKYlluaUxCjF5NUClSaWluQHV-YlK1mVFJWm6iiVFqQklqS6ZCamFyXmKlmlJeYUA0VTUzJL8ot8Ia4He6IWAIEIWTc?type=png

所以不要浪费时间去寻找完美的机器人, 能完成任务的就是好机器人.

L.I.T. (52517) 在 2022 年 superpower 这个赛季取得不错成绩, 有不少经验可以分享.

比赛策略和风格

  1. 这个赛季的机器人风格是"小快灵", 非常小, 非常快, 移动非常灵活. 下面是一个完成录像:

  1. 每轮只完成一到两个, 最多三个任务即返回出发点.任务之间误差累计会比较小, 而从出发点重新出发可以进行位置校准. 另外一个好处是, attachment 也可以做得很小, 配合 pinless design (下文详述), 在众多优秀队伍中也是颇有特色. 而且有任务失败, 需要把机器人拿回去, 后面一般没有太多剩余未完成的任务, 不太吃亏.

  2. 在 SD 附近参加了3轮比赛, 基本上比赛之间(2-4 个星期)会把整个比赛完成路线都变掉, 大刀阔斧重新设计. 这个也是因为上面的设计思想, 任务之间更容易合并和修改.

  3. 缺点是 technician 需要大量的练习才能 顺利完成比赛.

Pin-less design

  • pinless desgin 的意思是, attachment 按在 base robot 上就能跑, 随手就能拿下来, 无须额外使用乐高部件来固定.

  • 这个是2021年 All Systems Go (获得 2020 年 Replay 南加冠军) 对 L.I.T. 倾囊相传, 很多成熟的队伍都会使用此类设计.

  • 下面是 L.I.T. 在 2022 年设计的机器人图纸截图, 可以看到 1/2 处两个马达驱动的齿轮位置已经固定, 只要在attachment 的旁边位置放一个竖着的齿轮, 即可把能量传递到 attachment 其他地方. 3/4/5/6 的蓝色pin 可以帮助固定 attachment.

    https://imageclipped.s3-us-west-1.amazonaws.com/7a649af2cc2378b8cf6f54001894069a.png
  • 正如上面所说, 整个比赛被分成了很多小任务, 每个任务都有一到两个 attachment, 所以这次有很多小 attachment. (体积依然很小, 加起来还可以拿到奖励分)

    https://imageclipped.s3-us-west-1.amazonaws.com/f6aec1e686fb8ae80a48f9d8a25f26a6.jpg

mindstorm ev3 vs spike prime

mindstorm ev3 是上一代的乐高机器人, 使用了 ARM9 300MHz 32位处理器, 64M 内存. 可以运行特制的 linux 系统, 功能还是蛮强大的. 缺点是陀螺仪传感器是外接的, 时间久了经常不稳定, 还有 drift 的问题. 默认编程是 wordblock (scratch), 如果运行 Linux 则可以使用 python 等高级编程语言.

Spike prime 是乐高最新一代机器人, 使用的是 ARM Cortex-M4 100MHz 32位处理器, 32M 内存. ARM9 更适用于需要高性能和多任务的系统。Cortex-M4 更适用于低功耗、实时响应的嵌入式应用。 所以 Spike prime 的算力可能比 ev3 略弱一点.

spike prime 的官方编程语言是wordblock / python, wordblock 实际上还是编译成 python 再运行. 所以本质的编程语言并没有太多区别. 使用 (micro) python 这种高级语言当然可以更快实现各种功能, 但这个的前提是学生能够理解 python 的语法, 而且能够用其描述复杂的编程逻辑.

wordblock 和 micro python 基本上可以做到 1:1 对应, 凡是 python 能完成的, wordblock 也一定能完成. 只是遇到复杂的逻辑, python 可能几行就搞定, 但是 wordblock 看上去就一大堆.

L.I.T. 实际碰到的 micro python 问题是, wordblock 有个 broadcast 功能, 可以让几个马达同时工作. 但 micro python 对多线程运行的直接支持还不是很好, 或者需要大量的 hack 才能完成. 对于普通中小学生(包括家长)来说, 没有必要去浪费时间折腾.

软件设计

软件设计是非常精妙的部分. 机器人在场上表现如何, 大家都能看到, 机器人是怎么设计的, 用了什么传感器, 也都不会有什么秘密. 但是大家看不到的是软件部分.

L.I.T. 在 2022 赛季使用的是 spike prime + python + vs code (以及 spike prime 插件).

  • 大部分学生都是8年级, python 语法对他们来说并非难事.

  • 可以使用 git 来记录历史, 方便回溯. (git 也是一个可以终身使用的技能)

  • 使用蓝牙进行下载.

在 Akansas 大学比赛的时候, CCC (来自芝加哥的一只队伍) 给我们现场展示了她们的代码, 非常复杂, 但是异乎寻常的稳定. 她们的机器人只出错过一/两次, 其余所有比赛都是完美完成, 我从来没有在南加州见到如此稳定发挥的机器人. L.I.T. 有幸和 CCC 搭档拿到了联盟赛的冠军, 联盟赛的比赛规则就是淘汰赛, 每次两组 (各两支)队伍, 每组两个机器人同时在场上, 90秒完成所有任务. 几乎所有比赛都是满分, 对手完全没有机会. 我后来采访了她们队, 原来队伍已经有10年历史, 姐姐传妹妹这样带动下来的, 我相信这里面有很多的经验那都是无价之宝.

对于新手队伍, 该如何积累进步呢?

wordblock / python 确实上提供了详尽的接口, 例如往前走50cm. 一些新手队伍直接呼叫这些功能, 当然也能完成任务, 就是完美完成的机会会小一点. 因为这个机器人用了两个轮子, 它们的表现可能是不一样的, 也许左边的偶尔快一点, 最终的结果有时候会偏右一点.

有经验的队伍, 可能会用陀螺仪传感器来校准两个轮子的速度, 这样让机器人尽量保持在一个方向. 再举一个例子, 机器人在场上完成一两个任务之后, 误差的累计就变大了, 这个时候, 假如在前进的时候使用颜色感应器来检测一下黑线, 或者使用旁边的墙来进行一次陀螺仪校准, 都会很有帮助.

所以大家可以创建一些通用的辅助函数, 这样可以代替系统提供的功能, 例如:

GyroStraight

使用陀螺仪来帮助机器人走直线, 用来代替 spike prime 内部的 run_for_degree 函数. 进阶版本可以添加 加速 / 减速 功能.

GyroTurn

使用陀螺仪来辅助转弯, 这样转得更精确. 进阶版本可以考虑超过360转圈引起的硬件计数误差.

在FLL 里面经验很重要, 队伍几年下来积累的这些辅助函数都是将来的宝贵财富. 目前很多队伍还在使用 ev3 并取得很好的成绩, 但是他们成功的真正原因是之前的积累, 而不是刚好选择了某个平台和某个编程语言. 所以新手队伍切勿盲目跟风, 选择适合自己的平台, 苦练内功, 才是长远之道.

好玩的事情 2023Q3

ubuntu for cyberpunk. 这个桌面晚上在窗户上的倒影, 很有赛博朋克的感觉.

imgur ubuntu reflection

回国买了这个国产的拼装玩具, 赛博兔子, 哈哈

imgur cyber rabbit

WFH 的桌面设置, 三个屏幕确实方便很多.

imgur regolith2 desktop x3

Chula Vista 的图书馆

imgur chula vista

SD 的魔幻夜空

imgur SD night

regolith2 平铺桌面管理器

regolith2

  • regolith2 是基于 i3 上提供了更多的配置和打包.
  • 已经配置得非常完备了, 至少符合我的需求. 懒人必备, 不折腾. 😊
    • 例如包含了 rofi / ilia 等呼叫, 状态栏应有尽有.
    • 开箱即用, 我只要稍微修改一下快捷键就好.
  • 优点: 快捷键很多很好用. 几乎可以不用鼠标.
  • 缺点就是需要记住这些快捷键. 很多不常用的就很难记住. 当然 regolith2 可以 win+shift+? 快速呼出参考.
    • 刚好我有一个 macropad, 可以circuit python 编程. 我将其配置为输入一系列的快捷键, 例如, 一键进入 resize 模式, 然后用旋钮来调整窗口大小, 然后一键退出. 上面还有个小屏幕, 这样每次有什么不常用的功能, 我只要看着小屏幕按下去就好, 不用记住太多快捷键了.

macropad

PS: regolith 3 快出来了. 作者很勤快亚.

FLL 经验分享

我想在此分享一些FLL 机器人比赛的教练经验, 特别是常见的问题. 但是不会涉及细节, 例如某个功能代码应该怎么写.

关于 FLL 比赛

目的

我个人认为这个过程是非常锻炼娃的. 如果能认真做完所有事情, 是可以提升思考做事层次的. 如果一开始就冲着拿奖去的, 这个反而会有一定的偶然性.

流程

  • 4月~7月: 可以先准备起来, 熟悉机器人编程. 同时创新项目大方向已经出来, 可以先做一些相关研究.
  • 8月: FLL 会公布本年度的主题, 发布地图.
  • 10月: 有的 FRC / FTC 队伍会组织模拟比赛, 给出一些建议, 能参加还是挺不错的.
  • 11月~12月: 开始比赛, 一般2~3轮.

项目设置

  • 机器人性能 robot performance: 25%. 没错, 大家最看重的机器人比赛, 只有 1/4 的比重. 其实没有那么重要. 你不需要拿到第一才能进军下一轮. (甚至这个项目拿到第一, 但是其他轮的分数太低, 也有可能什么都拿不到, 毕竟很难有说服力. )
  • 机器人设计 robot design: 25%. 5 分钟向裁判讲解自己队的机器人设计.
  • 创新项目 innovative project: 25%. 5 分钟向裁判讲解自己队的创新项目.
  • 团队精神 core value: 25%. 现在没有专门的考核了, 主要查看队员之间的互动. 就是看看又没有团魂了.

误差

  • 很多人一听到乐高, 感觉很容易, 毕竟买一包玩具回家, 照着图纸做, 100% 成功.
  • 然而这个比赛的设置其实在另外一个层次:
    • 机器人的设计是没有图纸的, 需要每个队自己来设计打造.
    • 每年任务不一样, 那就需要用乐高来搭建不同的部件来配合机器人完成, 这个也是需要每个队自己进行设计.
    • 家里的桌子/比赛的桌子/上面布置的任务, 都是由不同的人来完成的, 都有不同的状况. 并不是像计算器一样, 1+1 一定等于 2. 机器人跑出来一定会有__误差__! 这就和实际生活中遇到的问题一样, 并没有简单的解法.
  • 教练的一个任务就是教会队员怎么认识误差, 怎么处理误差, 如何通过一些传感器来校准/减少误差.
    • 举个例子, 颜色传感器可以读取地图上的颜色/光的强度. 但是在不同的地方, 也许是日光灯, 也许是室外, 你读到的值范围就不一样. 机器人在家每次可以判断出到达黑线, 但是在比赛场地, 就是可能找不到黑线, 最后跑迷路了. 有的队会在比赛前进行一次校准, 用机器人在实际地图上读一下各个颜色的值, 然后再比赛.
  • 所以我的感觉是学生要到初中(7/8年级)左右才能更好理解这些工程的内容 (甚至很多家长都无法理解这些, 娃很挫折, 家长在旁边更挫折, 为什么每次跑出来都不一样?!).

scratch vs python

  • 有好几个家长问过我, 是不是用 python 就更加稳健? 不容易有误差? 答案很明显是.
  • scratch 和 python 在本质上等价的, python 能完成的事情, scratch 也能完成, 反之亦然. 这两个都是工具.
  • python 的好处是可以方便进行一些复杂的逻辑计算, scratch 也行, 但是写下来很难阅读.
    • 那对队员的要求就是, 他们要能够操作 python, 并且能够写出复杂的逻辑, 这个需要很多的经验和学习才行.
  • 打个比方, 写文章, 有人写得好, 有人写得差. 为什么我每个字都看得懂, 放在一起就是不対劲呢? 写得好的人, 必然已经打磨过自己的思维和表达, 当写文章的时候, 文字只是一个工具.
  • 同样道理, 如果 scratch 都整不好, 我相信 python 不会成为一个利器, 毕竟真正需要的是如何应对误差的思路.

迭代 (iteration)

  • 学生需要通过迭代来理解误差, 学习新技术.
  • 这个过程非常枯燥, 需要耐得住寂寞.
  • (此处还可以补充1千字, 等俺有空再加上)

经验

  • 队伍成功需要多年积累. 这几年我也遇到过不少队伍, 有几个队伍我还挺喜欢的, 你能看出他/她们的精神面貌, 接人待物都很成熟稳重, 绝对不是一年两年就能锻炼出来. 换个角度, 如果有学生能坚持这个活动(不被奖项这种东西困扰), 几年下来, 这个学生一定是个优秀的人才.
  • 纪律很重要. 不是所有娃/家长都是很投入很合作, 各种神奇的操作很多. 例如平时不贡献, 最后跳出来抢功劳的. 例如偷偷打游戏还拖别人下水的. 还有家长跳出来说分配不公要抓阄等等. 这个很考验教练的管理能力. 我感觉需要通过几年的人员调整来保留合适的队员, 他们才能自我运作起来.

好玩的事情 2022Q4

当我遛狗的时候, 发现有个邻居家门口的灯很酷炫.

imgur cool light

当我遛狗的时候, 人家在遛小马.

imgur pony

新一代的 marble machine, 安装难度还是有点大的.

imgur marble machine

RPI400 设置的工作台

imgur rpi400

国产咖啡三顿半, 打入美国市场, 味道不错, 就是有点贵.

imgur coffee

Test embed diagrams

embed mermaid

  • nikola 里面可以插入 mermaid 生成的流程图, 但是需要安装 mermaid.min.js, 感觉不是很必要.
  • 可以在 mermaid.live 上生成, 然后插入到这里.

advent of code

Advent of code 2021

  • Advent of code is a coding challenge in December of each year.
  • One puzzle per day from Dec 1 to Dec 25.
  • No programming language limitation.
  • First half questions seems simple and don't need much knowledge of advanced algorithms.
  • I feel the questions are a good exercise for kids to learn python.
  • hence I prepare this notebook that will prepare some knowledge for students in middle school to finish.

set up python editor

  • pycharm
  • mu editor

register github account

  • use github account to login advent of code
  • create a new repo to record the code for advent of code

learn git

# some simple git flow

# check repo status
git status

# add file to commit
git add .
git commit -m "new updates"

# push to github
git push origin

Day 1

In [ ]:
# read input into python
with open("day01_input.txt", "r") as f:
    lines_input = f.readlines() 
    # lines_input is a list of strings, 
    # each string is one line in the input.txt
    lines = [int(a) for a in lines_input]
    # lines is list of list of integer.
    # here we used `list comprehension`. will discuss it later.
In [ ]:
# example of for loop
# suppose we have 3 lists: part1, part2, part3, all have same size of 10
# we want to add first element of all 3 lists, 
# second elements of all 3 lists, etc

output = [] # we need somewhere to put the outputs
for i in range(10):
    o = part1[i] + part2[i] + part3[i]
    output.append(o)
    
# method2: use list comprehension instead of `for loop`
output = [a+b+c for (a, b, c) in zip(part1, part2, part3)]

# another example of list comprehension
l2 = [a*2 for a in l1]
    

Day 3

In [2]:
# binary string to integer
b_str = "0b1001" # add "0b" prefix
i_num = int(b_str, 2)

print("{} == {}".format(b_str, i_num))
0b1001 == 9
In [3]:
# use recursive function to solve problem.
# The benefit is that you only think one step.
# and the final step where it stops and return.

# a good tutorial at: https://realpython.com/python-thinking-recursively/

# example function 
def fibonacci_recursive(n):
    print("Calculating F", "(", n, ")", sep="", end=", ")

    # Base case. This is where the function will stop
    if n == 0:
        return 0
    elif n == 1:
        return 1

    # Recursive case
    else:
        # note the parameters are decreasing
        return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)

Day 15

  • need A* search algorithm.
  • Python Algorithms by Magnus Lie Hetland, p204
In [5]:
from heapq import heappush, heappop

# example of heapq. 
# you can use it get point with least loss at this moment.

#   (loss, (y, x))
a = (12, (9, 10))
b = (8, (3, 4))
c = (1, (1, 1))

loss = []
heappush(loss, a)
heappush(loss, b)
print("initialized heap: {}".format(loss))

least_loss = heappop(loss)
print("current least loss: {}".format(least_loss))
print("heap after pop: {}".format(loss))

heappush(loss, c)
print("heap after push c: {}".format(loss))
initialized heap: [(8, (3, 4)), (12, (9, 10))]
current least loss: (8, (3, 4))
heap after pop: [(12, (9, 10))]
heap after push c: [(1, (1, 1)), (12, (9, 10))]

Day 25

  • not difficult
  • you may want to use copy.deepcopy to keep a copy of map at each move. For example, if we loop from left to right,
    • >..>
    • .>.>
    • should we move the last one? if you look the updated map, it shows vacancy. but we should look at the original map, which shows no move for the last one.
  • it is fun to print frame by frame like animation.

reference

  • I wrote some code for AoC2021, you can find it here