UART 通信协议开源库调研总结

UART 通信协议开源库调研总结

调研日期:2026-08-19

目标场景:两轴/多轴无刷云台内部 Pitch、Yaw、Roll 控制板之间的 UART 通信

核心诉求:轻量、嵌入式友好、商业许可友好、支持可靠分帧/校验,且消息解析后优先采用 handler/listener 注册制 ,避免业务层大量 switch-case


1. 需求背景

云台内部存在两类典型通信需求:

1.1 高频实时数据

例如:

  • IMU / Gyro
  • Encoder
  • 角度
  • 角速度
  • 电机电流
  • 控制误差
  • 时间戳
  • 状态位

特点:

  • 频率高,典型 500 Hz~1 kHz
  • 对低延迟敏感
  • 某一帧丢失后通常无需重传,下一帧即可覆盖
  • 数据结构稳定
  • 应尽量减少编码开销

1.2 控制、配置、参数类数据

例如:

  • PID 参数
  • 滤波参数
  • 电机参数
  • IMU / Encoder 校准
  • 模式切换
  • 保存参数
  • 重启
  • 设备信息
  • 版本信息

特点:

  • 频率低
  • 更重视可靠性
  • 适合请求/响应
  • 关键命令需要 ACK / timeout / retry
  • 参数格式需要一定扩展能力

因此不建议所有业务都使用同一种数据表示方式。


2. 理想的软件结构

希望底层协议库能够将:

text 复制代码
UART 字节流
    ↓
帧解析
    ↓
CRC / Checksum
    ↓
Message Type / ID
    ↓
Handler Registry
    ↓
对应业务函数

最终业务代码类似:

c 复制代码
protocol_register(MSG_AXIS_STATE, axis_state_handler);
protocol_register(MSG_PARAM_SET,  param_set_handler);
protocol_register(MSG_CALIBRATE,  calibrate_handler);

而不是:

c 复制代码
switch (msg->type)
{
    case MSG_AXIS_STATE:
        ...
        break;

    case MSG_PARAM_SET:
        ...
        break;

    case MSG_CALIBRATE:
        ...
        break;
}

注册式设计的主要优势:

  • 协议层与业务层解耦
  • 新增消息无需修改中央 switch
  • 不同功能模块可以自行注册 handler
  • 后期更适合模块化和多人开发
  • 更容易做单元测试
  • 更适合未来扩展 Pitch / Yaw / Roll / Camera / Sensor 等模块

3. 候选开源库比较

项目 主要定位 C/C++ CRC/Checksum Handler 注册 请求/响应 适合高频实时数据 License 结论
TinyFrame 串口消息框架 C ✅ 原生支持 MIT 首选
MIN Protocol MCU 点对点可靠协议 C + Python ⚠️ 可自行加 MIT 第二选择
LwPKT 轻量 Packet Manager C11 ⚠️ 事件机制 ❌/自行实现 MIT 底层很轻,但业务层还需自己做
eRPC Embedded RPC C/C++ transport 负责 自动生成服务 ✅ 很强 ⚠️ BSD-3-Clause 参数/命令很舒服,但实时链路偏重
TinyProto 可靠链路层 C/C++ 有上层机制 GPL 系列,需谨慎 商业闭源固件不优先
microTLV TLV Payload 编解码 C 不推荐用于高频状态 MIT 只适合作为 Payload 层辅助

4. TinyFrame

项目:

https://github.com/MightyPork/TinyFrame

4.1 定位

TinyFrame 是一个专门用于:

  • UART
  • RS232
  • Socket
  • MCU ↔ MCU
  • MCU ↔ PC

的轻量消息框架。

它不仅解决 framing,还直接加入了:

  • Frame ID
  • Message Type
  • Header checksum
  • Payload checksum
  • Listener
  • Request / response
  • Timeout
  • 多消息 session

这正好处于"裸 framing"和"大型 RPC 框架"之间。


4.2 Frame 格式

TinyFrame 的基本格式:

text 复制代码
SOF
ID
LEN
TYPE
HEAD_CKSUM
DATA
DATA_CKSUM

各字段长度可以配置。

其中最重要的是:

text 复制代码
TYPE

可以直接作为业务消息类型。

例如:

text 复制代码
0x01 AXIS_STATE
0x02 SENSOR_SYNC
0x10 PARAM_GET
0x11 PARAM_SET
0x20 CALIBRATE
0x21 SAVE_CONFIG
0x22 REBOOT

4.3 Listener 注册机制

这是 TinyFrame 最符合本项目要求的地方。

TinyFrame 原生支持三类 Listener:

ID Listener

用于等待某一个具体 Message ID 的响应。

适合:

text 复制代码
PARAM_GET → PARAM_VALUE
SAVE_CONFIG → ACK
CALIBRATE → RESULT

Type Listener

按照 Message Type 注册业务处理函数。

例如概念上:

c 复制代码
TF_AddTypeListener(tf, MSG_AXIS_STATE, axis_state_handler);
TF_AddTypeListener(tf, MSG_PARAM_SET, param_set_handler);
TF_AddTypeListener(tf, MSG_CALIBRATE, calibrate_handler);

这是本项目最需要的机制。

Generic Listener

当没有更具体的 listener 匹配时,用作 fallback。


4.4 Request / Response

TinyFrame 的 Frame ID 可以在 response 中复用,因此:

text 复制代码
Pitch
    ↓
PARAM_GET
ID = 100
    ↓
Yaw
    ↓
PARAM_VALUE
ID = 100

发送端天然知道:

这是对哪一条 request 的回复。

而且 listener 可以带 timeout。

因此大量基础设施无需重新实现。


4.5 优点

  • API 很小
  • 纯 C
  • 适合 STM32
  • 原生 listener 注册机制
  • 自带 request/response
  • 自带 timeout
  • 自带 checksum
  • 无需代码生成器
  • MIT License
  • 容易 fork 后长期维护
  • 非常适合固定点对点 UART 链路

4.6 缺点

最大问题不是架构,而是:

项目较老。

官方 release 很早,后续维护活跃度不高。

因此如果真正用于商业量产产品,不建议完全依赖 upstream。

比较合理的方式:

text 复制代码
Fork TinyFrame
    ↓
冻结一个内部版本
    ↓
精简不需要的功能
    ↓
补齐 Unit Test
    ↓
补 Fuzz Test
    ↓
适配 UART DMA / RingBuffer
    ↓
公司内部长期维护

这反而很适合作为基础设施。


5. MIN Protocol

项目:

https://github.com/min-protocol/min

全称:

Microcontroller Interconnect Network

5.1 定位

MIN 专门用于:

text 复制代码
MCU ↔ MCU
MCU ↔ PC

设计目标就是:

  • 小 MCU
  • 串口
  • 较低资源
  • 高可靠性

官方 reference implementation 包含:

  • Embedded C
  • Python Host

协议本身比 TinyFrame 更像一个"已经定义好的微型标准串口协议"。


5.2 优点

  • 很轻
  • 设计目标就是 MCU
  • C reference implementation
  • PC 端 Python implementation
  • 支持可靠传输机制
  • 协议结构明确
  • MIT License
  • 很适合作为长期冻结的设备内部协议

5.3 不足

相比 TinyFrame:

业务 handler/listener registry 不是它最突出的能力。

如果使用 MIN,建议自己增加一个非常薄的 dispatch table:

c 复制代码
typedef void (*msg_handler_t)(
    const uint8_t *data,
    uint16_t len
);

typedef struct
{
    uint8_t msg_id;
    msg_handler_t handler;
} msg_handler_entry_t;

例如:

c 复制代码
static const msg_handler_entry_t handlers[] =
{
    { MSG_AXIS_STATE, axis_state_handler },
    { MSG_PARAM_SET,  param_set_handler  },
    { MSG_CALIBRATE,  calibrate_handler  },
};

然后:

text 复制代码
MIN frame parser
      ↓
message ID
      ↓
dispatch table
      ↓
handler

仍然可以完全避免 switch-case


6. LwPKT

项目:

https://github.com/MaJerle/lwpkt

6.1 特点

LwPKT 是一个非常轻的 Packet Protocol Manager。

特点包括:

  • C11
  • Platform independent
  • CRC
  • variable payload
  • from / to address
  • command field
  • Packet ready event
  • 适合 UART / USB / RS485 / Ethernet
  • MIT License

相比 TinyFrame,它更偏:

"我帮你可靠地得到一个 packet。"

而不是:

"我帮你构造完整业务消息层。"


6.2 适合场景

如果以后内部总线变成:

text 复制代码
Yaw
Pitch
Roll
Camera
Sensor Board

且需要:

text 复制代码
FROM
TO
CMD
DATA
CRC

那么 LwPKT 很合适。

但是本项目当前只是:

text 复制代码
Pitch ↔ Yaw

且非常重视 handler 注册机制,因此 TinyFrame 更直接。


7. eRPC

项目:

https://github.com/EmbeddedRPC/erpc

License:

BSD-3-Clause

7.1 思路完全不同

eRPC 不再让程序员关注:

text 复制代码
Message ID
Payload
Handler

而是直接定义远程函数。

例如:

text 复制代码
interface Gimbal
{
    setPid(...);
    calibrateEncoder();
    saveConfig();
    reboot();
}

erpcgen 自动生成:

  • Client Stub
  • Server Stub
  • 序列化
  • 反序列化
  • Function Dispatch

于是调用端可以写:

c 复制代码
setPid(...);

看起来就像调用本地函数。


7.2 非常适合

text 复制代码
PARAM_SET
PARAM_GET
CALIBRATE
SAVE
REBOOT
DEVICE_INFO
FW_VERSION

这类低频 RPC。


7.3 不推荐直接用于

text 复制代码
1 kHz Gyro
1 kHz Encoder
1 kHz Motor Current

虽然技术上可以实现,但抽象层和代码生成体系对于本项目的高频轴状态同步略显过度。

因此:

eRPC 很漂亮,但对 Pitch/Yaw 内部高频实时链路不是首选。


8. microTLV 是否还有必要

项目:

https://github.com/marcinbor85/microtlv

它主要解决:

text 复制代码
Tag
Length
Value

的 Payload 编解码。

从当前架构看,不建议所有消息都使用 TLV

原因:

实时数据字段稳定:

text 复制代码
timestamp
encoder
gyro
angle
current
status

如果每一个字段都加:

text 复制代码
TAG + LENGTH

会带来不必要的:

  • 带宽开销
  • CPU 解析开销
  • 数据结构复杂度

9. 推荐的数据分层

9.1 高频实时消息:定长 Binary

例如:

c 复制代码
AxisState
{
    timestamp_us
    seq

    encoder
    gyro_x
    gyro_y
    gyro_z

    angle
    motor_current
    status
}

概念结构:

text 复制代码
TinyFrame
    ↓
MSG_AXIS_STATE
    ↓
Fixed Binary Payload

适合:

text 复制代码
500 Hz
1 kHz

不需要 ACK。

丢了一帧直接等待下一帧。


9.2 参数消息:轻量 TLV / Parameter Value

没必要引入完整 TLV Framework,也可以自己定义一个极薄的统一格式:

text 复制代码
PARAM_ID
TYPE
LENGTH
VALUE

例如:

text 复制代码
PARAM_ID = 0x1010
TYPE     = FLOAT32
LENGTH   = 4
VALUE    = 1.25

这样就已经具备 TLV 的主要扩展能力。


9.3 Command 类:Request / Response

例如:

text 复制代码
CALIBRATE
SAVE_CONFIG
REBOOT
FACTORY_RESET

使用 TinyFrame 的 Message ID + Response Listener:

text 复制代码
Request
    ↓
ID = N
    ↓
执行
    ↓
Response
ID = N

同时支持 timeout。


10. 推荐最终架构

目前最推荐:

text 复制代码
                UART DMA
                    │
                    ↓
              Ring Buffer
                    │
                    ↓
                TinyFrame
                    │
        ┌───────────┴───────────┐
        │                       │
        ↓                       ↓
   Type Listener           ID Listener
        │                       │
        │                 Request/Response
        │
 ┌──────┼────────┐
 ↓      ↓        ↓
State   Param   Command
 │       │        │
Fixed   mini     ACK/Result
Binary  TLV

业务模块:

text 复制代码
protocol/
├── protocol_port.c
├── protocol_registry.c
├── protocol_message.h
├── protocol_param.c
├── protocol_command.c
├── protocol_state.c
└── third_party/
    └── TinyFrame/

11. 建议的消息类型

初期可以控制在很小范围。

text 复制代码
0x01  HEARTBEAT
0x02  AXIS_STATE
0x03  SENSOR_SYNC

0x10  PARAM_GET
0x11  PARAM_SET
0x12  PARAM_VALUE
0x13  PARAM_SAVE

0x20  MOTOR_ENABLE
0x21  CALIBRATE_IMU
0x22  CALIBRATE_ENCODER
0x23  REBOOT

0x30  DEVICE_INFO
0x31  FW_VERSION
0x32  ERROR_STATUS

后续按模块扩展。


12. 高频通信是否需要 ACK

不建议所有消息 ACK。

不 ACK

text 复制代码
AXIS_STATE
GYRO
ENCODER
ANGLE
CURRENT
SENSOR_SYNC

原因:

旧实时数据重传价值很低。


需要确认

text 复制代码
PARAM_SET
PARAM_SAVE
CALIBRATE
REBOOT
MODE_CHANGE
FACTORY_RESET

这些消息使用:

text 复制代码
Request
 ↓
Response / ACK
 ↓
Timeout
 ↓
Retry

13. 内部协议与外部协议分工

建议明确区分:

text 复制代码
                    云台
                     │
       ┌─────────────┴─────────────┐
       │                           │
       ↓                           ↓
    内部总线                     对外接口
       │                           │
 TinyFrame/UART                MAVLink 2
       │                           │
 Pitch ↔ Yaw               Gimbal Protocol v2
 Roll / Sensor             Parameter Protocol
                           Firmware / Debug

即:

内部

追求:

  • 简单
  • 低延迟
  • 易维护

推荐:

TinyFrame + 固定 Binary + 极简参数 TLV

外部

追求:

  • 标准化
  • 第三方兼容
  • 上位机兼容
  • 产品生态

推荐:

MAVLink 2


14. 最终结论

第一选择:TinyFrame

当前最符合本项目需求。

核心原因不是它"功能最多",而是它恰好具备需要的几个关键能力:

text 复制代码
轻量
+
纯 C
+
Frame
+
Checksum
+
Message Type
+
Message ID
+
Listener Registry
+
Request / Response
+
Timeout
+
MIT

尤其:

Type Listener + ID Listener

非常符合"注册式执行函数"的软件架构目标。


第二选择:MIN Protocol

如果未来更希望采用一个:

"协议规格本身已经定义得比较完整、MCU 和 PC 均有标准 reference implementation"

的方案,可以选择 MIN。

但业务 handler registry 建议自己增加薄薄的一层。


不建议为了 TLV 再引入过多依赖

当前项目建议:

text 复制代码
高频消息 = Fixed Binary
参数     = Param ID + Type + Length + Value
控制     = Request / Response

足够长期扩展。


15. 产品化建议

TinyFrame 虽适合,但项目历史较老。

如果用于商业量产产品,建议:

  1. Fork TinyFrame。
  2. 固定内部版本,不跟随 upstream 自动升级。
  3. 删除项目中不需要的功能。
  4. 做成内部 gimbal_protocol 基础库。
  5. 加完整 Unit Test。
  6. 增加 fuzz / malformed frame 测试。
  7. 增加 UART DMA + RingBuffer adapter。
  8. 增加协议统计:
    • RX packet
    • CRC error
    • timeout
    • lost frame
    • unknown type
  9. 明确定义大小端。
  10. 不直接 memcpy 未对齐 struct。
  11. 明确定义协议版本号。
  12. 为未来 Roll / Camera / Sensor 扩展预留 Message Type 空间。

最终得到的不是"使用 TinyFrame 的代码",而是一套:

公司内部长期维护的 Gimbal Internal Protocol Infrastructure

后续两轴、三轴、体育跟踪云台、摄像机云台都可以复用。


16. 调研项目链接


当前推荐一句话总结

云台内部 UART:优先 TinyFrame,实时数据采用固定二进制 Payload,参数采用轻量 Param-ID/Type/Length/Value,关键命令走 Request/Response + timeout;外部接口继续使用 MAVLink 2。

相关推荐
m4Rk_2 小时前
【论文阅读】Agent 记忆机制(48):Fine-Mem——用细粒度奖励解决长期记忆管理中的奖励稀疏与信用分配
论文阅读·人工智能·学习·开源·github
vipjx12 小时前
2026百度网盘不限速下载指南:PanDownload最新复活版与满速提速方案
开源
小弥儿2 小时前
GitHub今日热榜 | 2026-08-23:终端编码Agent与Skills生态扎堆
学习·开源·github
章老师说3 小时前
壬远 AI 网关 v0.4.0 正式发布:模型定价、RMB 配额与多 Key 路由,让企业级 AI 流量治理再进一步
人工智能·ai·开源·负载均衡·ai-native
冰风漫天3 小时前
我也整个开源的MES系统把玩
开源
dong_junshuai3 小时前
# 每天一个开源项目#76 Skills:23万星的 Agent 工程技能库
开源·github·agent
Databuff3 小时前
两款开源APM工具【skywalking+databuff】组合落地实战
开源·skywalking
程序员差不多先生3 小时前
OpenAI 把 Codex Harness 开源:AI Agent 的“操作系统“之争正式开打
人工智能·开源
北漂燕郊杨哥4 小时前
DotMD:一款基于 Go + Wails 的轻量开源 Markdown 桌面编辑器
golang·开源·编辑器·markdown·md