CEM5861G-Dashboard 是一个基于 Vue3 开发的 CEM5861G 上位机,可实时可视化雷达数据,同时提供一个用户友好的界面来读取和设置雷达的各种运行参数
在线使用:https://cem.babyfang.cn
附件为离线版,打开 index.html
即可使用
核心组件介绍
App.vue
作为应用的根组件,负责整合所有子组件,并管理它们之间的数据流和事件通信。它维护一些全局状态,如最新接收到的数据、历史图表数据、日志消息以及参数响应等。
SerialPortControl.vue
这是与硬件进行串口通信的核心模块。它封装了 Web Serial API 的所有操作,包括连接、断开、数据读写以及最关键的数据帧解析。
数据帧解析
- 帧头识别:在接收到的字节流中查找帧头
0x55 0xA5
。 - 长度解析:根据帧头后的两个字节解析出整个数据帧的长度。
- 校验和验证:计算接收到数据的校验和,并与帧尾的校验和进行比对,确保数据完整性和正确性。
- 功能码/命令码识别:根据帧的特定字节(功能码、命令码1、命令码2)识别数据帧的类型。
- 雷达主动上报数据帧 (
0x03 0x81 0x00
):解析出目标 ID、状态、距离、速度、角度、信号强度等详细信息。解析后的结构化数据通过data-received
事件发送给App.vue
,最终由DataDisplay
和ChartComponent
使用。 - 雷达响应上位机命令帧 (
0x02
): - 参数配置响应 (
0x02 0x80 xx
):将原始数据字节(例如0x00 0xC8
)提取出来,通过parameter-response
事件发送给App.vue
。 - 控制命令响应 (
0x02 0x20 xx
):恢复默认参数、保存参数到 Flash 等命令的响应,发出command-response
事件。 - 错误处理:处理校验和错误、帧长度不足、未知帧类型等异常情况,并发出日志和 Toast 提示。
ConfigPanel.vue
提供一个用户界面来显示和修改雷达的各项运行参数
使用 parameters
数组定义所有可配置的雷达参数,包括其 key
、 label
、 type
(number/select)、 default
值、对应的读取命令 ( readCmd
)、设置命令前缀 ( setCmdPrefix
) 和接收响应命令 ( receiveCmd
)
readParameter(param)
负责构建并发送指定参数的读取命令到串口setParameter(param)
负责根据用户输入的参数值,构建包含数据和校验和的设置命令,发送到串口。它会根据参数类型(number
或select
) 和dataLength
将数值转换为相应的字节序列(例如,将十进制 200 转换为0x00 0xC8
)
数据处理流程详解
整个项目的数据处理流程可以概括为以下几个关键环节:
1. 串口连接与原始数据接收
-
触发:用户点击
SerialPortControl
中的“连接串口”按钮。 -
过程:
SerialPortControl
调用navigator.serial.requestPort()
请求用户选择串口设备。- 成功后,
port.open()
打开串口连接。 - 获取
reader
和writer
流,并通过reader.read()
开始持续监听传入的原始字节流。
2. 字节流到数据帧的组装与校验
-
模块:
SerialPortControl.vue
的readData
方法。 -
过程:
- 接收到的字节会不断追加到一个
receivedBuffer
(Uint8Array
) 中。 - 循环检查
receivedBuffer
,查找特定的帧头 (0x55 0xA5
)。 - 一旦找到帧头,根据帧头后的数据长度字段 (
receivedBuffer[2] << 8) | receivedBuffer[3]
),计算出完整的帧长度。 - 检查
receivedBuffer
中是否已有足够的数据构成完整帧。 - 如果数据足够,截取完整帧,并计算其校验和。
- 将计算出的校验和与接收到的帧尾校验和进行比对。
- 成功:将完整的、校验和正确的帧传递给
parseFrame
方法进行进一步解析。 - 失败:记录校验和错误或帧格式错误日志,并从
receivedBuffer
中移除当前帧(或只移除一个字节继续查找,以避免死循环)。
- 接收到的字节会不断追加到一个
-
输出:一个或多个完整且校验和正确的二进制数据帧 (
Uint8Array
)。
3. 数据帧的结构化解析
-
模块:
SerialPortControl.vue
的parseFrame
方法。 -
过程:
-
接收一个完整的二进制数据帧。
-
从帧中提取出功能码 (
frame[4]
)、命令码1 (frame[5]
) 和命令码2 (frame[6]
),以及实际的数据部分。 -
根据功能码和命令码判断帧的类型:
-
主动上报数据帧 (
0x03 0x81 0x00
):将数据部分按照雷达协议的定义(例如,距离占 2 字节,速度占 2 字节等)解析成对应的十进制数值、符号数等。 -
命令响应帧 (
0x02
):- 如果是参数配置响应 (
0x02 0x80 xx
),直接提取其数据部分字节(例如[0x00, 0xC8]
),封装成一个对象,并通过parameter-response
事件发送。 - 如果是控制命令响应 (
0x02 0x20 xx
),则根据命令码2判断是哪种控制命令的响应,并根据协议判断响应状态(通常数据部分为0x01
表示成功)。
- 如果是参数配置响应 (
-
-
发出相应的事件 (
data-received
,parameter-response
,command-response
),将解析后的结构化数据或原始数据部分传递给App.vue
。
-
-
输出:
- 结构化雷达目标数据对象(例如
{ distance: 200, speed: 50, ... }
) - 参数响应数据对象(例如
{ functionCode: 0x02, commandCode1: 0x80, commandCode2: 0x03, data: Uint8Array([0x00, 0xC8]) }
) - 控制命令响应状态(例如
{ status: 'SUCCESS', commandName: 'OTA' }
)
- 结构化雷达目标数据对象(例如
4. 数据在组件间的传递与更新
-
模块:
App.vue
作为中央事件总线和数据管理器。 -
过程:
-
App.vue
接收到SerialPortControl
发出的各种事件:data-received
-> 更新latestReceivedData
(ref),并添加到historyChartData
(ref) 数组。parameter-response
-> 更新lastParameterResponse
(ref)。command-response
-> 处理控制命令的响应,触发 Toast 提示。log-message
-> 添加到allLogMessages
(ref) 数组。show-toast
-> 调用showToast
函数显示 Toast。
-
这些
ref
变量的变化会触发 Vue 的响应式系统。
-
5. UI 更新与数据展示
-
模块:
DataDisplay.vue
,ChartComponent.vue
,LogDisplay.vue
,ConfigPanel.vue
。 -
过程:
DataDisplay
接收latestData
prop,当latestData
变化时,其模板会自动更新,显示最新的雷达数据。ChartComponent
接收chartData
prop,当chartData
数组变化时,它会重新渲染或更新图表,展示历史数据趋势。LogDisplay
接收logMessages
prop,当新日志添加时,列表会自动更新。ConfigPanel
中的watch
监听props.parameterResponse
。当lastParameterResponse
在App.vue
中更新时,ConfigPanel
会收到新值。ConfigPanel
内部会根据响应的functionCode
、commandCode1
、commandCode2
找到对应的参数,并解析newResponse.data
中的字节数据(例如0x00 0xC8
会被解析为十进制的 200),然后直接更新parameters
数组中该参数的value
属性(例如matchedParam.value = parsedValue;
)。- 由于
ConfigPanel
模板中的输入框是使用v-model.number="param.value"
绑定到parameters
数组中对象的value
属性,当matchedParam.value
更新时,Vue 的响应式系统会自动检测到这个变化,并自动填充输入框。 - 所有组件发出的
show-toast
事件最终都会被App.vue
捕获,并通过Toastify-JS
库在右上角显示弹出消息。
6. 数据发送与参数设置
-
触发:用户在
ConfigPanel
中点击“读取”或“设置”按钮。 -
过程:
ConfigPanel
根据用户选择的参数和输入的值,结合预定义的命令前缀,构建完整的二进制命令数据包(包括数据字节和校验和)。ConfigPanel
发出send-serial-data
事件,将要发送的Uint8Array
数据传递给App.vue
。App.vue
接收到事件后,调用serialControlRef.value.sendData()
方法,将数据转发给SerialPortControl
。SerialPortControl
的sendData
方法通过writer.value.write(data)
将二进制数据写入串口。
开源
https://github.com/klxf/CEM5861G-Dashboard
本项目使用 Apache License 2.0 许可协议开源,你可以自由使用、修改和分发本项目的代码,但需要遵守该协议的条款。
全部评论