无线电

远距离的交互感觉像魔法。

如果你是一个精灵、巫师或是独角兽,魔法可能有用,但这样的事情只存在于故事里。

然而,还有比魔法更好的东西:物理学!

无线交互都是关于物理学的:无线电波(一种类似于可见光的电磁辐射)具有某种属性(例如它们的振幅,相位或脉冲宽度),可由发射机解调,从而使得信息可以被编码并因此传播。当无线电波遇到电导体(即天线)时,会产生交流电,从中可以提取电波中的信息并将其转换为原来的形式。

层层相叠

要是你还记得的话,网络是一层一层建立起来的。

网络最基本的要求是通过某种连接使得信号能从一个设备传送到另一个设备。 在我们建立网络的教程中,我们使用了连接引脚I/O的电线。多亏了无线电模块,我们可以不用电线,而是运用上面提到的物理学作为设备之间的隐性连接。

网络堆栈中的下一层也不同于建立网络教程中示例的内容。 通过连接电线的例子,我们使用数字开关来发送和读取来自引脚的信号。 在micro:bit内置的无线电中,信号最小的有用组成部分是一个字节。

字节

一个字节是(通常)由8个位组成的信息计量单位。位是最小的信息单位,因为它的状态只能是开或关两个(on or off)。

字节的工作方式很像算盘:字节中的每个位置就像一个算盘中的一列—它们代表的是关联数字。在算盘中,这些通常是千,百,十和个位(用英国的说法)。在一个字节中,它们是128,64,32,16,8,4,2和1。以位(开/关信号)通过无线电传播,被接收方重新组合为字节。

你发现规律了吗?(提示:基数是2。)

通过添加与“on”状态下字节中的位置相关的数字,可以表示0和255之间的数字。下面的图像显示了从0到32,五个位的工作方式:

../_images/binary_count.gif

若就255个数字其中每一个数字(由一个字节编码)所代表的东西(比如一个字符)达成一致,那么我们就可以每次发送一个字符/字节。

有趣的是,人们已经考虑到 这一点 ~ 用字节编码和解码信息很常见。这大约相当于有线网络示例中的摩尔斯电码 “协议” 层。

你可以在 CS unplugged 网站找到一系列对儿童及教师有帮助的很棒的 “所有与字节相关的信息(all things bytes)” 说明。

寻址

无线电的问题是不能直接传输给某个人,有合适天线的任何人都可以收到你传输的信息。 因此,能够区别谁应该接收播出的信息很重要。

micro:bit内置无线电解决这个问题的方式非常简单:

  • 可以将无线电调到不同的频道(编号0-100)。这与小孩用的对讲机工作方式完全相同:每个人都会收听同一个频道,每个人都会听到其他人通过该频道播放的内容。 与对讲机一样,如果使用相邻频道,则可能会出现干扰。
  • 无线电模块允许指定两条信息:地址和组。地址就像邮寄地址,而组就像该地址处的特定收件人。 关键是无线电会过滤掉它接收到的与 你的 地址和组不匹配的信息。 因此,预先定义好应用程序即将使用的地址和组是很重要的。

当然,micro:bit仍然在接收其他地址/组的传播信息,重要的是你不必担心这些将会被过滤掉。尽管如此,如果有人足够聪明,无论目标地址/组是什么,他都可以读取 所有的无线网络流量。在这种情况下, 必须 使用加密通信手段,这样的话,只有我们预期的接收人才能真正获取传播信息。 密码学是一个引人入胜的学科,但不幸的是,超出了本教程的范围。

萤火虫

这是一只萤火虫:

../_images/firefly.gif

它是一种利用生物发光向同伴发送信号(无需电线)的虫子。这是当它们互相发送信号时的样子:

../_images/fireflies.gif

BBC有一段有关萤火虫的 相当漂亮的在线视频

我们将使用无线电模块创建类似于一群萤火虫互相发送信号的东西。

首先 import radio (引用radio)使其功能可以用于你的Python程序。 然后调用 radio.on() 函数打开无线电。由于无线电程序耗电且占内存,所以 来决定何时启用它(当然也有 radio.off() [用于关闭无线电]函数)。

在这一点上,无线电模块配置了合理的默认值,以使其与可能面向BBC micro:bit的其他平台兼容,可以控制上面讨论的许多功能(例如频道和寻址)以及用于广播信息的功率量和传入消息队列将占用的RAM量。API文档包含你配置无线电所需的所有信息。

假定我们对默认值很满意(默认值不需要修改),发送信息最简单的方式如下:

radio.send("a message")

该示例运用 send 函数简单播出字符串”a message”。对于接收信息来说更容易:

new_message = radio.receive()

随着信息被接收,它们被置于信息队列中。``receive``函数以字符串的形式从队列中返回最旧的信息,为新传入的信息留出空间。 如果信息队列被填满,则新传入的信息将被忽略。

这就是它的全部!(无线电模块也足够强大,你可以发送任何类型的数据,而不仅仅是字符串。请参阅API文档了解它是如何工作的。)

掌握了这些知识后,制作micro:bit萤火虫就变得很简单:

# A micro:bit Firefly.
# By Nicholas H.Tollervey. Released to the public domain.
import radio
import random
from microbit import display, Image, button_a, sleep

# Create the "flash" animation frames. Can you work out how it's done?
flash = [Image().invert()*(i/9) for i in range(9, -1, -1)]

# The radio won't work unless it's switched on.
radio.on()

# Event loop.
while True:
    # Button A sends a "flash" message.
    if button_a.was_pressed():
        radio.send('flash')  # a-ha
    # Read any incoming messages.
    incoming = radio.receive()
    if incoming == 'flash':
        # If there's an incoming "flash" message display
        # the firefly flash animation after a random short
        # pause.
        sleep(random.randint(50, 350))
        display.show(flash, delay=100, wait=False)
        # Randomly re-broadcast the flash message after a
        # slight delay.
        if random.randint(0, 9) == 0:
            sleep(500)
            radio.send('flash')  # a-ha

上面引用的事件会发生在事件循环中。首先,它会检查按钮A是否被按下,如果是,则使用无线电发送信息“闪(flash)”。然后它使用 radio.receive() 从信息队列中读取信息。如果有信息,它会随机进行短时间的休息(以使显示更有趣),并使用 display.show() 为萤火虫发光设置动画。最后,为了让事情变得激动人心,它会选择一个随机数,这样它就有1/10的机会将“闪”信息重新传递给其他任意设备(这就使得萤火虫在多个设备间闪光成为可能)。如果它决定重播,那么在再次发送“闪”信号之前,会等待半秒钟(所以最初的闪光信息有机会消失)。因为这段代码被包含在 while True 代码块中,所以它会循环回到事件循环的开始,并且永久地重复这个过程。

最终的结果(使用一组micro:bit)应该看起来像这样:

../_images/mb-firefly.gif