LEGO EV3 通信 开发者套件

1 MINDSTORMS EV3 可编程 brick 的硬件规格

LEGO MINDSTORMS EV3 可编程 brick 是新 LEGO MINDSTORMS 平台内的中央处理单元。可编程 brick 由各种先进的电子设备组成,以实现其广泛的功能。

下面的列表是 EV3 可编程 brick 硬件规格总结。

硬件 规格
主处理器 32-bit ARM9 processor, Texas Instrument AM1808
- 300 MHz
- OS: LINUX
存储器 64 MB DDR RAM
16 MB FLASH
256 KB EEPROM
Micro SD卡接口 SDHC standard, 2 – 32 GB
Bluetooth 无线通信 Bluetooth V2.1 EDR, Panasonic PAN1325 模块
- Texas Instrument CC2550 芯片
- BlueZ Bluetooth 栈
- Primary usage, Serial Port Profile (SPP)
USB 2.0 通信,客户端接口 高速端口 (480 MBit/s)
USB 1.1 通信,客户端接口 全速端口 (12 MBit/s)
4 个输入端口 6 个接口同时支持数字和模拟接口
- 模拟输入 0 – 5 V
- 支持 Auto-ID 扩展设备
- UART 通信
Up to 460 Kbit/s (Port 1 and 2)
Up to 230 Kbit/s (Port 3 and 4)
4 个输出端口 6 个有线接口,支持电机编码器输入
显示 178x128 像素黑白点阵显示器
- 可视区域: 29.9 x 41.1 mm
扩音器 直径,23 mm
6 个按钮用户接口 环绕 UI 灯
电源 6 AA 电池
- 建议使用碱性电池
- 可充电锂离子电池,2000 mAH
链接器 6 线工业标准连接器,RJ-12右侧调节

2 通信接口

这部分将描述不同类型 masters(主机)与 LEGO MINDSTORMS EV3 brick 通信所用的协议。EV3 支持多种通信接口 Bluetooth,USB 和 WiFi。EV3 协议对于所有 3 种传输技术都是相同的。

除了运行用户程序外,VM(虚拟机)还能执行通过上述技术之一发送的直接命令。直接命令由构成常规字节码的小程序组成,有关各字节码的更多详细信息,请参考 LEGO MINDSTORMS EV3 固件开发者套件。这些直接命令(代码片段)与运行的用户程序并行执行。

在组合这些直接命令时要特别小心。在使用危险的代码和结构时没有任何限制(例如,允许直接命令中出现死锁循环)。然而 “普通的” 运行中的程序将继续正常工作 - 只有 VM 的直接命令部分将被这样的死锁循环 “锁死”。

由于头部只为变量分配包含 2 个字节,直接命令仅限于一个 VMTHREAD - 即SUBCALLs 和 BLOCKs 当然是不可能的。

具有数据响应的直接命令可以把返回数据放在全局变量空间中。全局变量空间 “等于” 通信响应缓冲区。直接命令的组成定义了放置结果的偏移量位置(全局变量 0 放在返回缓冲区中偏移量为 0 的位置)。

响应缓冲区(全局变量)中的偏移量必须对齐(第一个对齐到 float/32 位,最后一个对齐到 8 位)。

除了直接命令,EV3 还支持系统命令,这是更通用的术语命令,它们被用于向/从嵌入式 EV3 系统下载和上传数据。

3 系统命令

1
2
#define SYSTEM_COMMAND_REPLY 0x01 // 系统命令,需要应答
#define SYSTEM_COMMAND_NO_REPLY 0x81 // 系统命令,无需应答

系统命令字节:

字节 0 - 1:命令大小,小尾端。命令大小不包含这 2 个字节
字节 2 - 3:消息计数器,小尾端。Forth running counter
字节 4:命令类型。参考上面的定义
字节 5:系统命令。参考下面的定义
字节 6 - n:依赖于字节 5 中给出的系统命令

系统命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define BEGIN_DOWNLOAD 0x92 // 开始文件下载
#define CONTINUE_DOWNLOAD 0x93 // 继续文件下载
#define BEGIN_UPLOAD 0x94 // 开始文件上传
#define CONTINUE_UPLOAD 0x95 // 继续文件上传
#define BEGIN_GETFILE 0x96 // 开始从文件获取字节(在写入文件时)
#define CONTINUE_GETFILE 0x97 // 继续从文件获取字节(在写入文件时)
#define CLOSE_FILEHANDLE 0x98 // 关闭文件句柄
#define LIST_FILES 0x99 // 列出文件
#define CONTINUE_LIST_FILES 0x9A // 继续列出文件
#define CREATE_DIR 0x9B // 创建目录
#define DELETE_FILE 0x9C // 删除
#define LIST_OPEN_HANDLES 0x9D // 列出句柄
#define WRITEMAILBOX 0x9E // 写邮箱
#define BLUETOOTHPIN 0x9F // 把可信的 pin 码传入 brick
#define ENTERFWUPDATE 0xA0 // 重启 brick 进入 Firmware 更新模式

3.1 系统命令应答

1
2
#define SYSTEM_REPLY 0x03 // 系统命令应答 OK
#define SYSTEM_REPLY_ERROR 0x05 // 系统命令应答 ERROR

系统应答字节:

字节 0 - 1:应答大小,小尾端。应答大小不包含这 2 个字节
字节 2 - 3:消息计数器,小尾端。等于直接命令
字节 4:应答类型。参考上面的定义
字节 5:这个应答响应的系统命令
字节 6:系统应答状态 - 错误,信息或成功。参考下面的定义
字节 7 - n:进一步的系统应答字节依赖于系统命令和系统应答状态

系统命令应答状态码:

1
2
3
4
5
6
7
8
9
10
11
12
13
#define SUCCESS 0x00
#define UNKNOWN_HANDLE 0x01
#define HANDLE_NOT_READY 0x02
#define CORRUPT_FILE 0x03
#define NO_HANDLES_AVAILABLE 0x04
#define NO_PERMISSION 0x05
#define ILLEGAL_PATH 0x06
#define FILE_EXITS 0x07
#define END_OF_FILE 0x08
#define SIZE_ERROR 0x09
#define UNKNOWN_ERROR 0x0A
#define ILLEGAL_FILENAME 0x0B
#define ILLEGAL_CONNECTION 0x0C

3.2 向 EV3 可编程 brick 下载数据

下载大文件可能非常耗时,因此文件下载可以以 2 种不同的方式完成。

  1. 以最大可能块下载文件,即尽可能使用最大的数据包大小(总命令大小不包括在内。 Length 字节= 65534字节)。如果总消息大小可以保持在 65534 字节以下,则所有的数据可以放进 开始下载 命令,这将是下载文件最快的方式。这是最快的下载方式,但在这段时间内系统也会被锁定。

  2. 把文件下载分为更小的部分,即一个 开始下载 后面跟着大量的 继续下载 命令,这将增加总的下载时间,但在持续的 继续下载 命令交错间也将给其它命令(更高优先级的)留下空间(时间片)。
    这是下载文件最慢的方式,但可以在 继续下载 消息间交错其他命令。

由于包中没有停止或其它同步字节 - 一个消息一定不能被其它消息打断。即当 brick 已经接收了命令大小(消息的头 2 个字节)时,所有剩余的字节必须无中断地被传送和接收。这个特定消息的应答(来自于 brick)也应该在任何新消息被发送和由 brick 处理前被传送和接收。

下面的例子基于想要给 P-Brick 发送一个文件的主机应用(X3 software)构建:

命令大小,命令类型,开始 D/L,文件大小,文件名 ——>
                       <—— 命令大小,命令类型,句柄
命令大小,命令类型,继续 D/L,句柄,载荷 ——>
                    <—— 命令大小,命令类型
命令大小,命令类型,继续 D/L,句柄,载荷 ——>
                    <—— 命令大小,命令类型
命令大小,命令类型,继续 D/L,句柄,载荷 ——>

3.2.1 文件下载

  • 目的文件名路径相对于 “lms2012/sys” 定位
  • 目的目录自动从文件名路径创建
  • 第一个目录名必须是:“apps”“prjs”“tools” (参考 \ref UIdesign)
  • 文件名路径中的第二个文件夹名称必须等于字节码可执行名称

3.2.2 文件上传(文件读取)

  • BEGIN_UPLOADCONTINUE_UPLOAD 在文件上传结束时自动关闭文件句柄。
  • BEGIN_GETFILECONTINUE_GETFILE 当到达 EOF 时不关闭文件句柄
  • CONTINUE_GETFILE 也返回完整的文件大小

3.2.3 目录上传

  • LIST_FILES 只要列表不超过 1014 字节,就可以工作。

3.3 系统命令,通信例子

在下文中,系统命令通信示例的例子将帮助说明接口。

3.3.1 文件下载

下载文件 “../apps/tst/tst.rbf”

   BEGIN_DOWNLOAD:

     向 brick 发送的字节:
     1C00xxxx0192xxxxxxxx2E2E2F617070732F7473742F7473742E72626600  (Hex)
     bbbbmmmmttssllllllllnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn

     bbbb = 消息中的字节数
     mm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     llllllll = 文件长度
     nn.. = 以 0 结束的文件名

     从 brick 接收的字节:
     0600xxxx03920000  (Hex)
     bbbbmmmmttssrrhh

     bbbb = 消息中的字节数
     mm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     hh = 文件句柄

   CONTINUE_DOWNLOAD:
     向 brick 发送的字节:
     xxxxxxxx819300xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  (Hex)
     bbbbmmmmttsshhpppppppppppppppppppppppppppppppppppppppp

     bbbb = 消息中的字节数
     mm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     hh = 文件句柄(在 BEGIN_DOWNLOAD 中返回)
     pp.. = 载荷

     从 brick 接收的字节:
     0600xxxx03930000  (Hex)
     bbbbmmmmttssrrhh

     bbbb = 消息中的字节数
     mm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     hh = 文件句柄

3.3.2 文件上传

   BEGIN_UPLOAD:
     向 brick 发送的字节:
     xxxxxxxx0194xxxxxxx
     bbbbmmmmttssllllnnn…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     llll = 要读取的字节
     nnn… = 文件名,包含路径

     从 brick 接收的字节:
     xxxxxxxx039400xxxxxxxx00xxx
     bbbbmmmmttssrrllllllllhhppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     llllllll = 文件大小
     hh = 文件句柄
     ppp… = 载荷

   CONTINUE_UPLOAD:
     向 brick 发送的字节:
     0700xxxx019500xxxx
     bbbbmmmmttsshhllll…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     hh = 文件句柄
     llll = 要读取的字节

     向 PC 发送的字节:
     xxxxxxxx03950000xxx
     bbbbmmmmttssrrhhppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     hh = 句柄
     pppp.. = 载荷

3.3.3 获取文件内容

用于上传数据记录文件 - 文件句柄只在文件指针到达 EOF 时关闭,且文件不以写模式打开。

   BEGIN_GETFILE:
     向 brick 发送的字节:
     xxxxxxxx0196xxxxxxx
     bbbbmmmmttssllllnnn…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     llll = 最大读取字节数
     nnnn…. = 路径

     向 PC 发送的字节:
     xxxxxxxx039600xxxxxxxx00xxx
     bbbbmmmmttssrrllllllllhhppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     llllllll = 文件大小
     hh = 句柄
     ppp… = 载荷

   CONTINUE_GETFILE:
     向 brick 发送的字节:
     0700xxxx019700xxxx
     bbbbmmmmttsshhllll

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     hh = 句柄
     llll = 最大读取字节数

     向 PC 发送的字节:
     xxxxxxxx039700xxxxxxxx00xxx
     bbbbmmmmttssrrllllllllhhppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     llllllll = 文件大小
     hh = 句柄
     ppp… = 载荷

3.3.4 列出文件和目录

   LIST_FILES:

   新行分隔列表的格式为:

   如果是文件:
   MD5SUM 的 32 chars (hex) + space + 8 chars (hex) 的文件大小 + space + 文件名 + 新行

   如果是目录:
   目录名 + / + 新行

     向 brick 发送的字节:
     xxxxxxxx0199xxxxxxx
     bbbbmmmmttssllllnnn…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     llll = 最大读取字节数
     nnn…. = 路径名

     向 PC 发送的字节:
     xxxxxxxx0399xxxxxxxxxxxxxxx
     bbbbmmmmttssrrllllllllhhnnn…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     rr = 返回状态
     llllllll = 列表大小
     hh = 句柄
     nnn.. = 新行分隔列表

   CONTINUE_LIST_FILES:
     向 brick 发送的字节:
     0700xxxx019Axxxxxx
     bbbbmmmmttsshhllll

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     hh = 句柄
     llll = 最大读取字节数

     向 PC 发送的字节:
     xxxxxxxx039Axxxxxxx
     bbbbmmmmttssrrhhppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 命令类型
     ss = 系统命令
     rr = 返回状态
     hh = 句柄
     ppp… = 载荷

3.3.5 关闭文件句柄

   CLOSE_FILEHANDLE:
     向 brick 发送的字节:
     xxxxxxxx019800xxxxxxxxxxxxxxxx
     bbbbmmmmttsshhpppppppppppppppp

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     hh = 句柄
     ppp… = 哈希

     向 PC 发送的字节:
     0500xxxx039800
     bbbbmmmmttssrr

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     rr = 返回状态

3.3.6 创建目录

   CREATE_DIR:
     向 brick 发送的字节:
     xxxxxxxx019Bxxxxxx…
     bbbbmmmmttsspppppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     pp = 以 null 结尾的字符串,其中包含了要创建的目录的完整路径

     向 PC 发送的字节:
     0500xxxx039Bxx
     bbbbmmmmttssrr

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     rr = 返回状态

3.3.7 删除一个文件

   DELETE_FILE:
     向 brick 发送的字节:
     xxxxxxxx019Cxxxxxx…
     bbbbmmmmttsspppppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     pp = 以 null 结尾的字符串,其中包含了要删除的文件的完整路径

     向 PC 发送的字节:
     0500xxxx039Cxx
     bbbbmmmmttssrr

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     rr = 返回状态

3.3.8 获取打开句柄的列表

   LIST_OPEN_HANDLES:
     向 brick 发送的字节:
     xxxxxxxx019D
     bbbbmmmmttss

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令

     向 PC 发送的字节:
     xxxxxxxx039Dxxxxxx….
     bbbbmmmmttssrrpppp….

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     rr = 返回状态
     pppp = 用于指示句柄是否处于 busy 状态的位

3.3.9 写邮箱

   WRITEMAILBOX:
     向另一个 brick 发送的字节:

     邮箱名称必须以 0 结尾,同时名称长度必须是剔除结尾的 0 的字符数!

     xxxxxxxx819Exxxxxxxxxxxxxxxxxxxx
     bbbbmmmmttssllaaaaa…LLLLppp…

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     ll = 名称长度
     aaa… = 名称
     LLLL = 载荷长度
     ppp… = 载荷

     从另一个 brick 接收的应答:
     无效

3.3.10 设置 Bluetooth PIN 码

   BLUETOOTHPIN:

     出于安全的原因,这个命令只能通过 USB 发送,且应该被格式化为:

       Bluetooth 地址一定不能包含冒号
      
Bluetooth MAC 地址是 0 结尾的字符串类型
      * Bluetooth pin 码是 0 结尾的字符串类型

     向 brick 发送的字节:
     0E00xxxx019F06xxxxxxxxxxxx04xxxx
     bbbbmmmmttssllaaaaaaaaaaaaLLpppp

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     ll = MAC 长度
     aaa… = PC 的 MAC 地址
     LL = pin 长度
     ppp… = pin 码

     向 PC 发送的字节:
     0F00xxxx039Fxx06xxxxxxxxxxxx04xxxx
     bbbbmmmmttssrrllaaaaaaaaaaaaLLpppp

     bbbb = 消息中的字节
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令
     rr = 返回状态
     ll = MAC 长度
     aaa… = PC 的 MAC 地址
     LL = pin 长度
     ppp… = pin 码

3.3.11 强制 EV3 可编程 brick 进入 Firmware 升级模式

这个命令用于强制 brick 进入 Firmware 升级模式。这个命令将不发送任何响应回主机。关闭(关机)Linux OS 时,不会更新文件系统。

   ENTERFWUPDATE:

     向 brick 发送的字节:
     0400xxxx81A0
     bbbbmmmmttss

     bbbb = 消息中的字节数
     mmmm = 消息计数器
     tt = 消息类型
     ss = 系统命令

4. 直接命令

1
2
#define DIRECT_COMMAND_REPLY 0x00 // 直接命令,需要应答
#define DIRECT_COMMAND_NO_REPLY 0x80 // 直接命令,无需应答

直接命令字节:

字节 0 - 1:命令大小,小尾端。命令大小不包含这 2 个字节
字节 2 - 3:消息计数器,小尾端。Forth running counter
字节 4:命令类型。参考上面的定义
字节 5 - 6:使用压缩格式保留(分配)全局变量和局部变量(在字节 5 和字节 6 的 2 个 lsb 中保留全局变量,在字节 6 的高 6 位中保留本地变量) - 见下文:
字节 7 - n:单个命令或复合命令的字节代码(即多个命令组合为一个小程序)

局部的 = “l”, 全局的 = “g”

1
2
3
Byte 6: Byte 5:
位号: 76543210 76543210
变量大小: llllllgg gggggggg

gg gggggggg 全局变量保留 0 – (2^10 – 1) 0..1023 字节
llllllxx 局部变量保留 0 – (2^6 – 1) 0….63 字节

4.1 直接应答

1
2
#define DIRECT_REPLY 0x02 // 直接命令应答 OK
#define DIRECT_REPLY_ERROR 0x04 // 直接命令应答 ERROR

直接应答字节:

字节 0 - 1:应答大小,小尾端。应答大小不包含这 2 个字节
字节 2 - 3:消息计数器,小尾端。与直接命令相同
字节 4:应答类型。参考上面的定义
字节 5 - n:响应缓冲区,即命令为全局变量保留的字节内容。即如果命令保留 64 字节,这些字节将被放在应答包的字节 5 到 68。

4.2 直接命令,通信示例

下面的直接命令通信的例子将帮助更详细地说明接口。使用的高层的宏说明如下。

更高层的参数编码:

为了使使用参数编码更简单,而使用了 “bytecodes.h” 中定义的一些宏(关于参数编码也可以参考 “LEGO MINDSTORMS EV3 - Firmware Developer Kit” 文档中第 9 页 - 3.4 参数编码),所示的范围被编码为有符号数。

LCS Long variable type Length bytes STRING zero terminated
LC0(v) Short constant(value) single byte +/- 31
LC1(v) Long constant(value) one byte to follow (2 bytes) +/- 127
LC2(v) Long constant(value) two bytes to follow (3 bytes) +/- 32767
LC4(v) Long constant(value) four bytes to follow (5 bytes) +/- 2147483647
LV0(i) Short LOCAL variable(adr) single byte at adr +/- 31
LV1(i) Long LOCAL variable(adr) one byte to follow at adr (2 bytes) +/- 127
LV2(i) Long LOCAL variable(adr) two bytes to follow at adr (3 bytes) +/- 32767
LV4(i) Long LOCAL variable(adr) four bytes to follow at adr (5 bytes) +/- 2147483647
GV0(i) Short GLOBAL variable(adr) single byte at adr +/- 31
GV0(i) Long GLOBAL variable(adr) one byte to follow at adr (2 bytes) +/- 127
GV0(i) Long GLOBAL variable(adr) two bytes to follow at adr (3 bytes) +/- 32767
GV0(i) Long GLOBAL variable(adr) four bytes to follow at adr (5 bytes) +/- 2147483647

4.2.1 在 EV3 brick 上启动程序 “Demo”

加载并运行一个应用字节码文件。这个示例也展示了复合的直接命令 - 即在一个单独的包中的两个或更多直接命令。这里我们加载字节码镜像:“../prjs/BrkProg_SAVE/Demo.rpf” 进 slot 1 - 用户 slot。后面紧接着是启动slot 1 中的程序的命令。记住这是一个组合命令,且不能交错。备注: 文件扩展名是 “rpf” 而不是 “rbf”。文件是内建的 “on-brick program file”。

向 brick 发送的字节:

opFILE,LC0(LOAD_IMAGE),LC2(USERSLOT),LCS,’.’,’.’,’/‘,’p’,’r’,’j’,’s’,’/‘,
‘B’,’r’,’k’,’P’,’r’,’o’,’g’,
‘,’S’,’A’,’V’,’E’/‘,’D’,’e’,’m’,’o’,’.’,’r’,’p’,’f’,0,GV0(0),GV0(4),opPROGRAM_START,
LC0(USER_SLOT),GV0(0),GV0(4),LC0(0)

指令 说明
opFILE 文件有关的操作码
LC0(LOAD_IMAGE) 命令被编码为单字节常数
LC2(USER_SLOT) 用户 slot(1 = 程序 slot)被编码为单个常量字节
LCS 编码:后面是字符串(以 0 结尾)
“../prjs/BrkProg_SAVE/Demo.rpf” 文件路径和名称。“..” 是 “从当前目录移到上一级目录”
0x00 上面的字符串的结尾 0
GV0(0) 在全局变量偏移 0 处返回镜像大小。偏移量被编码为单个字节。
GV0(4) 在全局变量偏移 4 处返回镜像地址。偏移量被编码为单个字节。
opPROGRAM_START 操作码
LC0(USER_SLOT) 用户 slot(1 = 程序 slot)被编码为单个字节常量
GV0(0) 镜像大小位于全局变量偏移 0 处。
GV0(4) 镜像地址位于全局变量偏移 4 处。
LC0(0) 调试模式(0 = 普通)被编码为单个字节常量

30000000800800C008820100842E2E2F70726A732F42726B50726F675F534156452F44656D6F2E7270660060640301606400
bbbbmmmmtthhhhccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccCCCCCCCCCC

bbbb = 消息中的字节数为 48,不包含包长度字节
mmmm = 消息计数器
tt = 命令类型 - 直接命令无需应答
hhhh = 头部 – 变量分配。
cc/CC = 字节码
hhhh = 10 个最低有效位是全局变量的个数,6 个最高有效位是局部变量的

4.2.2 以电源 50 向前启动电动机 B&C 3 转,并在目的地制动

这个例子使用了特殊的 OUTPUT_STEP_SPEED 电动机命令。这个命令在电动机列表中为电动机设置了速度((setpoint))。命令包含加速和减速部分。特别是减速对于更精确地到达最终目的地非常有用。电动机在 3 转(3 * 360 度)结束后制动。

opOUTPUT_STEP_SPEED,LC0(LAYER_0),LC0(MOTOR_A + MOTOR_B),LC1(SPEED_50),LC0(0),LC2(900),LC2(180),LC0(BRAKE)

指令 说明
opOUTPUT_STEP_SPEED 操作码
LC0(0) Layer 0 - 被编码为单个字节常量
LC0(MOTOR_A + MOTOR_B) 电动机 B & C (电动机列表)被编码为单个字节常量
LC1(SPEED_50) 速度 50% 被编码为单个字节常量
LC0(0) 没有 STEP1,即从开始全速 - 编码为单个字节常量
LC2(900) 2.5 周(900 度) STEP2 - 被编码为两个字节
LC2(180) 0.5 周(180 度) STEP3 为了更精确的到达目的地 - 被编码为两个字节
LC0(BRAKE) 制动(1)- 被编码为单个字节常量

向 brick 发送的字节:

1200xxxx800000AE000681320082840382B40001
Bbbbmmmmtthhhhcccccccccccccccccccccccccc

bbbb = 消息中的字节数为 21,不包含包长度字节
mmmm = 消息计数器
tt = 命令类型 - 直接命令无需应答
hhhh = 头部 – 变量分配。
cc/CC = 字节码
hhhh = 10 个最低有效位是全局变量的个数,6 个最高有效位是局部变量的

4.2.3 读取传感器端口 3 上的光传感器值

这个直接命令将读取连接在 brick 的输入端口 3 上的光传感器。模式被显式地设为模式 0(零)即光传感器(0 – 100 pct.)的本地模式 0。返回值是一个32 位 float,编码为 SI 0-100 pct。

默认的 32 位浮点数(SI 0-100 pct)。

opINPUT_DEVICE,LC0(READY_SI),LC0(LAYER_0),LC0(SENSOR_PORT_3),LC0(DO_NOT_CHANGE_TYPE),LC0(MODE_0),LC0(ONE_DATA_SET),LCO(GLOBAL_VAR_INDEX0)

指令 说明
opINPUT_DEVICE 输入相关的操作码
LC0(READY_SI) 命令(READY_SI)被编码为单个字节常量
LC0(LAYER_0) Layer number (0 = 这个特定 brick) 被编码为单个字节常量
LC0(SENSOR_PORT_3) 连接到端口 3 ((1-4 / 0-3 内部的)上的传感器被编码为单个字节常量
LC0(DO_NOT_CHANGE_TYPE) 如果设置为 0 (零) - 不改变类型 - 被编码为单个字节常量
LC0(MODE_0) 模式 0 - 被编码为单个字节常量
LC0(ONE_DATA _SET) 数据集的个数(模式 0 只有 1 个(pct))- 被编码为单个字节常量
LC0(GLOBAL_VAR_INDEX0) 把返回值放在全局变量的索引 0 (零)处 - 被编码为单个字节常量

向 brick 发送的字节:

0D00xxxx000400991D000200000160
BbbbmmmmtthhhhCCCCCCCCCCCCCCCC

bbbb = 消息中的字节数为 13,不包含包长度字节
mmmm = 消息计数器
tt = 命令类型 - 直接命令需要应答
hhhh = 头部 – 变量分配。这 4 个字节在全局变量中保留
CC/cc/CC/cc = 字节码
hhhh = 10 个最低有效位是全局变量的个数,6 个最高有效位是局部变量的

4.2.4 读取连接到端口 1 的光传感器为 COLOR

这个直接命令将读取连接在 brick 的输入端口 1 上的光传感器。模式被显式地设为模式 2 “COLOR 模式”。传感器将返回一个 0 - 8(包含)之间的值,即传感器前的物体的颜色。返回值是 32 位浮点数,编码为 0-8。

opINPUT_DEVICE,LC0(READY_SI),LC0(LAYER_0),LC0(SENSOR_PORT_1),LC0(DO_NOT_CHANGE_TYPE),LC0(MODE_2),LC0(ONE_DATA_SET),LCO(GLOBAL_VAR_INDEX0)

指令 说明
opINPUT_DEVICE 输入相关的操作码
LC0(READY_SI) 命令(READY_SI)被编码为单个字节常量
LC0(LAYER_0) Layer number (0 = 这个特定 brick) 被编码为单个字节常量
LC0(SENSOR_PORT_1) 连接到端口 1 ((1-4 / 0-3 内部的)上的传感器被编码为单个字节常量
LC0(DO_NOT_CHANGE_TYPE) 如果设置为 0 (零) - 不改变类型 - 被编码为单个字节常量
LC0(MODE_2) 模式 2 - 被编码为单个字节常量
LC0(ONE_DATA _SET) 数据集的个数(模式 0 只有 1 个(pct))- 被编码为单个字节常量
LC0(GLOBAL_VAR_INDEX0) 把返回值放在全局变量的索引 0 (零)处 - 被编码为单个字节常量

向 brick 发送的字节:

0D00xxxx000400991D000000020160
BbbbmmmmtthhhhCCCCCCCCCCCCCCCC

bbbb = 消息中的字节数为 13,不包含包长度字节
mmmm = 消息计数器
tt = 命令类型 - 直接命令需要应答
hhhh = 头部 – 变量分配。这 1 个字节在全局变量中保留
CC/cc/CC/cc = 字节码
hhhh = 10 个最低有效位是全局变量的个数,6 个最高有效位是局部变量的

4.2.5 在 level 2 播放 1 Kz 音调 1 秒

opSOUND,LC0(TONE),LC1(2),LC2(1000),LC2(1000)

指令 说明
opSOUND 声音相关的操作码
LC0(TONE) 命令(TONE)被编码为单个字节常量
LC1(2) 声音 leve2 被编码为 1 个常量字节
LC2(1000) 频率 1000 Hz 被编码为 2 个常量字节
LC2(1000) 持续时长 1000 ms 被编码为 2 个常量字节

向 brick 发送的字节:

0F00xxxx8000009401810282E80382E803
Bbbbmmmmtthhhhcccccccccccccccccccc

bbbb = 消息中的字节数为 15,不包含包长度字节
mmmm = 消息计数器
tt = 命令类型 - 直接命令无需应答
hhhh = 头部 – 变量分配。
cc/CC = 字节码
hhhh = 10 个最低有效位是全局变量的个数,6 个最高有效位是局部变量的

4.2.6 在屏幕上展示一幅图片

清除屏幕,并在屏幕上的坐标 (x = 0, y= 50) 处绘制 bmp 图片 “mindstorms.rgf”。首先屏幕由 FILLWINDOW 子命令清除,然后 bmp 图片文件由子命令 BMPFILE 加载。在 UPDATE 子命令发出之前屏幕上什么都不会发送。

opUI_DRAW,LC0(FILLWINDOW),LC0(BG_COLOR),LC2(0),LC2(0),opUI_DRAW,LC0(BMPFILE),LCO(FG_COLOR),LC2(0),LC2(50),LCS,’u’,’i’,’/‘,’m’,’i’,’n’,’d’, ‘s’,’t’,’o’,’r’,’m’,’s’,’.’,’r’,’g’,’f’,0,opUI_DRAW,LC0(UPDATE)

指令 说明
opUI_DRAW 绘制相关的操作码
LC0(FILLWINDOW) 命令(FILLWINDOW)被编码为单个字节常量
LC0(BG_COLOR) 颜色设置背景颜色 - 即清除屏幕被编码为单个字节常量
LC2(0) 起始 y(0 表示整个屏幕)被编码为单个字节常量
LC2(0) 结束 y(0 表示整个屏幕)被编码为单个字节常量
opUI_DRAW 绘制相关的操作码
LC0(BMPFILE) 命令(BMPFILE)被编码为单个字节常量
LC0(FG_COLOR) 颜色设置前景颜色被编码为单个字节常量
LC2(50) 起始 y 坐标 50 被编码为 2 个字节
LC2(0) 起始 x 坐标 0 被编码为 2 个字节
LCS 编码:字符串(以 0 结尾)
“ui/mindstorms.rgf” 文件路径和名称
0 字符串的 0 结尾
opUI_DRAW 绘制相关的操作码
LC0(UPDATE) 命令(UPDATE)“执行所有的图形操作” 被编码为单个字节常量

向 brick 发送的字节:

2C000000800000841300820000820000841C018200008232008475692F6D696E6473746F726D732E726766008400
BbbbmmmmtthhhhCCCCCCCCCCCCCCCCCCccccccccccccccccccccccccccccccccccccccccccccccccccccccccCCCC

bbbb = 消息中的字节数为 44,不包含包长度字节
mmmm = 消息计数器
tt = 命令类型 - 直接命令无需应答
hhhh = 头部 – 变量分配。
CC/cc/CC/cc = 字节码

hhhh = 10 个最低有效位是全局变量的个数,6 个最高有效位是局部变量的

原文

坚持原创技术分享,您的支持将鼓励我继续创作!