D04 - 从零开始的 Firmata 通讯

电子助教:「(大包小包)窝准备好了 (≖‿ゝ≖)✧」

鳕鱼:「东西放下,我们没有要转生。」

电子助教:「说好的香香妹子们呢?(́⊙◞౪◟⊙‵)」

鳕鱼:「别瞎掰好吗」

电子助教:(每天眼前只有一只肥宅鱼,我的电生怎麽这麽歹命 ( ´•̥̥̥ ω •̥̥̥` ))

鳕鱼:「你心里是不是在想甚麽很失礼的事情... (´ー`)」


接下来我们将慢慢研读 Firmata Protocol,并自行设计 Firmata 收发套件。

首先打开 Firmata Protocol 的 Github,并点击「protocol.md」文件。

D04 - Firmata Github.png

此文件便是 Firmata 的基础内容,详细说明 Firmata 之 MIDI 格式、数位类比资料响应等等。

Untitled

我们不要从头开始啃(以免大家都跑光 ...(ˊДˋ;)),循序渐进地一步一步来。

让我们回到 D03 串列埠监控视窗那一串奇怪的文字开始吧。

Untitled

串列通讯传输资料时,都是一个 byte 一个 byte 进行传输,一个 byte 表示 0~255 的数值,意思是不管甚麽文字或符号,都会被转换成 0~255 之间的数值。

数值与字元之前的对照关系就是「ASCII」,每个符号都有自己对应的数值,如下表(图片只包含部分内容):

Untitled

图片来源:wiki - ASCII

中文或其他语系文字则会使用多个 byte 进行表示,详细资料请见连结

意思是「hi」这段文字透过串列通讯传输时会是「104 105」,而 Arduino IDE 的串列埠监控视窗会自动将数值转换成字元,所以 Firmata 的内容看起来会是一堆乱码,因为他并不是传文字字元。

不过我们希望可以直接观察原始数值内容,所以这里要请出另一个工具 — 「AccessPort」。

(其实不下载 AccessPort 也没关系,,因为只用这一次 ( ´∀` ))

下载、解压缩完成後,打开程序,会跑出以下画面:

如果长的不一样,请确认红框选项为「Terminal」

D04 - AccessPort.png

接着按下橘框的「齿轮」按钮,打开设定,并检查红框内的设定是否相符。

「串口」请选择 Arduino Uno 对应的 COM

D04 - AccessPort 设定 (1).png

设定完成後按下确定,AccessPort 会自动开启 Port,这个时候应该会跑出一串数值,如下图。

如果是一串乱码,请确认红框内的 Hex 选项被启用。

D04 - Firmata 启动讯息.png

让我们来好好分析这串数值。

   第一个数值
 ⇙
F9 02 05 F0 79 02 05 53 00 74 00 61 00 6E 00 64 00 61 00 72 00 64 00 46 00 69 00 72 00 6D 00 61 00 74 00 61 00 50 00 6C 00 75 00 73 00 2E 00 69 00 6E 00 6F 00 F7

protocol.md 中搜寻第一个数值「F9」,就会在「Message Types」找到他。

Untitled

可以发现其实前 3 个 Byte 是用来描述协定版本,也就是说:

F9 02 05

意思为:

  • F9:告知回应的数值是 protocol version
  • 02:表示 major version
  • 05:表示 minor version

所以我们可以得出此韧体协定版本为 2.5 版。

接着让我们去除已知意义的数值,接下来的第一个数值是「F0」

F9 02 05 // 协定版本

   接下来的第一个数值
 ⇙
F0 79 02 05 53 00 74 00 61 00 6E 00 64 00 61 00 72 00 64 00 46 00 69 00 72 00 6D 00 61 00 74 00 61 00 50 00 6C 00 75 00 73 00 2E 00 69 00 6E 00 6F 00 F7

一样会在「Message Types」找到「F0」。

Untitled

会发现「F0」为 sysex 的起始值,所以甚麽是「sysex」呢?让我们移驾到「Sysex Message Format」的部分。

Untitled

System exclusive (sysex) messages are used to define sets of core and optional firmata features. Core features are related to functionality such as digital and analog I/O, querying information about the state and capabilities of the microcontroller board and the firmware running on the board. All core features are documented in this protocol.md file. Optional features extend the hardware capabilities beyond basic digital I/O and analog I/O and also provide APIs to interface with general and specific components and system services. Optional features are individually documented in separate markdown files.

从以上文档的说明中,我们可以知道 sysex 表示一种用来描述并定义核心功能与各种 I/O 的讯息格式。

所以我们可以在 SysEx commands 中找到第二个数值「79」的踪影:

Untitled

并在「Query Firmware Name and Version」中找到详细的回应内容说明:

Untitled

大家会注意到里面出现了 LSB、MSB,我们先解释一下这是甚麽,他们分别为:

  • MSB:最高有效位元组(Most Significant Byte)
  • LSB:最低有效位组(Least Significant Byte)

接着探讨一个问题。
分屍位元01
分屍位元02
分屍位元03

将超过 1 bye 的数值拆分成多个 byte 传输,接收时再将数值组装回来即可,具体过程如下:

D04 - 拆分位元.png

接下来根据以下说明:

0  START_SYSEX       (0xF0)
1  queryFirmware     (0x79)
2  major version     (0-127)
3  minor version     (0-127)
4  first char of firmware name (LSB)
5  first char of firmware name (MSB)
6  second char of firmware name (LSB)
7  second char of firmware name (MSB)
... for as many bytes as it needs
N  END_SYSEX         (0xF7)

我们可以得知:

  • F0 为 sysex 起始值
  • 79 为查询韧体命令
  • 接续第 3、4 Byte 都是版本号(刚好对应刚刚「F0」的内容)
  • 剩下的内容每 2 Byte 为一组(LSB、MSB),用来表示 firmware name

所以我们将刚才的数值分类、整理一下,得:

F9 02 05 // 协定版本

F0       // 起始值
79       // 查询韧体命令
02       // major version
05       // minor version

53 00    // firmware name
74 00 
61 00 
6E 00 
64 00 
61 00 
72 00 
64 00 
46 00 
69 00 
72 00 
6D 00 
61 00 
74 00 
61 00 
50 00 
6C 00 
75 00 
73 00 
2E 00 
69 00 
6E 00 
6F 00 

F7       // 结束值

firmware name 的部分,因为 MSB 都是 00,所以数值组合後也等於 LSB,我们接着比对 ASCII 表(注意数值为 16 进位),就可以得出数值表示的字元,得:

F9 02 05 // 协定版本

F0       // 起始值
79       // 查询韧体命令
02       // major version
05       // minor version

53 00    // 53 = S
74 00    // 74 = t
61 00    // 61 = a
6E 00    // 6E = n
64 00    // 64 = d
61 00    // 61 = a
72 00    // 72 = r
64 00    // 64 = d
46 00    // 46 = F
69 00    // 69 = i
72 00    // 72 = r
6D 00    // 6D = m
61 00    // 61 = a
74 00    // 74 = t
61 00    // 61 = a
50 00    // 50 = P
6C 00    // 6C = l
75 00    // 75 = u
73 00    // 73 = s
2E 00    // 2E = .
69 00    // 69 = i
6E 00    // 6E = n
6F 00    // 6F = e

F7       // 结束值

firmware name 的部分合并之後就会得到「StandardFirmataPlus.ino」。

最後总结一下,我们知道原本的那一大串数值其实有两个部分:

// 第一部分
F9 02 05 

// 第二部分
F0 79 02 05 53 00 74 00 61 00 6E 00 64 00 61 00 72 00 64 00 46 00 69 00 72 00 6D 00 61 00 74 00 61 00 50 00 6C 00 75 00 73 00 2E 00 69 00 6E 00 6F 00 F7

第一部分:

  • 版本号:2.5

第二部分:

  • 版本号:2.5
  • 韧体名称:StandardFirmataPlus.ino

以上我们成功迈出看懂 Firmata 的第一步了!

总结

  • 读懂 Firmata 开机讯息
  • 成功取得「版本号」与「韧体名称」

<<:  Day 3 - Array 阵列组合技 (2)

>>:  Day03-资料加工与逻辑整合(methods v.s. computed)

[Day 28] Device Simulation & Remote Debugging

随着网站的手机使用率越来越高,行动版网站渐渐变成标配,为了避免同时需要维护多个网站或是 SEO 被...

Day18:WS 串接 Client & Server

初始化专案 ws 在使用上和 socket.io 其实颇为类似,因此预计实作上会分两个阶段,第一阶段...

实战练习 - 使用 RxJS 实作「自动完成 / 搜寻 / 排序 / 分页」功能

今天我们用实际的例子来练习各种 RxJS operators 的组合运用!在一般的应用程序里面,资料...

[DAY14] 在 Azure Machine Learning 里 Label data(下)

DAY14 在 Azure Machine Learning 里 Label data(下) 我们昨...

[Day27] Tableau 轻松学 - TabPy 除错技巧

前言 相信走到这里,读者应该有办法依需求在 Tableau Desktop 中活用 TabPy。但还...