AI for Youth Academy 青少年AI研究计划

第一年 · 第09周

第九章:将Python技能应用到LEGO Spike

在第02周,我们通过复制代码并按下运行按钮来执行了第一个Spike Prime程序。从那以后,你在Google Colab中学习了变量、列表、for循环和函数。本周我们将所有这些技能带回到机器人上。你将不再复制代码,而是自己设计和编写程序。

第1部分:回顾——机器人是如何工作的

还记得第02周的第一个程序吗?让我们再看一次:

from hub import port
import runloop, motor_pair

async def main():
    motor_pair.pair(motor_pair.PAIR_1, port.C, port.D)
    await motor_pair.move_for_degrees(motor_pair.PAIR_1, 360, 0, velocity=360)

runloop.run(main())

这个程序做了三件事:

  1. 导入——加载我们需要的库(hubrunloopmotor_pair)。
  2. 配对电机——告诉Hub哪两个端口连着轮子。
  3. 移动——让机器人转动轮子360度。

第2部分:用变量调整机器人

在第02周,我们把数字直接写在代码里。如果想改速度,就得去代码中间找到那个数字然后修改。当程序变长时,这样做很容易出错。

更好的方法:把所有可调参数放在程序最上面,作为变量。这叫做配置块

# ── 配置块 ──
SPEED = 360            # 每秒多少度
DRIVE_DEGREES = 720    # 向前走多远(轮子转的度数)
TURN_DEGREES = 360     # 转弯多少度(轮子转的度数)

现在,当你想让机器人走得更远或更慢时,只需要改变一个地方的数字。

第3部分:用函数封装可重用的动作

在第07周,你写过Python函数来计算误差。现在我们用函数来封装机器人的动作。与其每次都写一长串电机命令,不如把它包装成一个函数:

async def drive_straight(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 0, velocity=SPEED
    )

async def turn_right(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 100, velocity=SPEED
    )

async def turn_left(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, -100, velocity=SPEED
    )

现在你的主程序变得像自然语言一样易读:

async def main():
    motor_pair.pair(motor_pair.PAIR_1, port.C, port.D)

    await drive_straight(DRIVE_DEGREES)
    await turn_right(TURN_DEGREES)
    await drive_straight(DRIVE_DEGREES)

第4部分:用For循环实现重复路线

假设你想让机器人走一个正方形——向前走,右转90度,重复四次。不用循环,你得把同样的代码写四遍:

# 不用循环——重复又无聊!
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)
await drive_straight(DRIVE_DEGREES)
await turn_right(TURN_DEGREES)

for循环,只需要两行:

# 用循环——简洁!
for i in range(4):
    await drive_straight(DRIVE_DEGREES)
    await turn_right(TURN_DEGREES)

多边形挑战

我们可以用一个变量控制边数,让机器人走出任何正多边形:

SIDES = 6  # 改这个数字试试!

for i in range(SIDES):
    await drive_straight(DRIVE_DEGREES)
    await turn_right(360 // SIDES)

第5部分:用列表规划多步任务

如果你的路线不是一个简单的形状呢?比如你需要:向前走500度,右转,向前走300度,左转,向前走700度。你可以把这些步骤存在列表里:

# 每一步:(距离度数, 转弯方向, 转弯度数)
mission = [
    (500, "right", 90),
    (300, "left", 45),
    (700, "right", 90),
]

for step in mission:
    distance = step[0]
    direction = step[1]
    angle = step[2]

    await drive_straight(distance)
    if direction == "right":
        await turn_right(angle)
    else:
        await turn_left(angle)

这和第05周中遍历向量分量的方式完全相同——只不过现在列表里存的是机器人的动作指令!

第6部分:完整程序

让我们把所有内容组合成一个完整的程序。这个程序让机器人走一个正方形:

from hub import port
import runloop, motor_pair

# ── 配置块 ──
SPEED = 360
DRIVE_DEGREES = 720
SIDES = 4

async def drive_straight(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 0, velocity=SPEED
    )

async def turn_right(degrees):
    await motor_pair.move_for_degrees(
        motor_pair.PAIR_1, degrees, 100, velocity=SPEED
    )

async def main():
    motor_pair.pair(motor_pair.PAIR_1, port.C, port.D)

    for i in range(SIDES):
        await drive_straight(DRIVE_DEGREES)
        await turn_right(360 // SIDES)

runloop.run(main())

展望未来

本周你把在Colab里学到的Python技能带到了真实的机器人上——变量、函数、循环和列表都有了实际用途。在接下来的几周里,我们将加入传感器,让机器人能够感知周围环境并做出反应,而不是盲目地按照预设路线行驶。