文档库

NodeHexa UART v2协议

ESP32-S3-CAM-Mini 产品与硬件、快速上手、视觉案例、接口与图传使用说明。
ESP32-S3-CAM-Mini 使用与开发手册

本章依据相机v1.1.0与主控v3.0.1源码。UART为115200、8N1、3.3 V;相机TX=GPIO1、RX=GPIO2,接主控RX=GPIO16、TX=GPIO17。

二进制帧

偏移字节数内容
02帧头A5 4E
21版本02
31消息类型
41flags
52sequence,小端uint16
72JSON载荷字节数N,小端uint16
9NUTF-8 JSON,不带末尾NUL、不带换行
9+N2CRC,小端uint16

总长N+11,N最大512。长度按UTF-8字节数计算,不按汉字个数计算。

CRC为CRC16-CCITT:多项式0x1021、初值0xFFFF,不反射、不作最终异或;覆盖偏移2开始的7+N字节,不含帧头及CRC。可复用源码examples/nodehexa-video/main/uart_protocol.{h,cpp},避免自己拼出不同变体。

类型值名称用途
1HELLO发现和能力声明
2REQUEST配网、档位或运动请求
3RESPONSE对应请求的回执,匹配sequence
4EVENT异步状态、低电量、动作完成
5HEARTBEAT存活查询

现有发送端常用请求/HELLO flags=0x02,主控回执flags=0x01,相机回执为0。接收时应首先按消息类型和序号分流,不因两端flags差异丢弃合法回执。flags不是加密或鉴权字段。

相机解析器相邻字节间隔超过250 ms会放弃未完成帧;错误CRC或超长载荷也会丢弃。UART读取可能只有半帧或同时包含多帧,必须增量解析,不能假定一次read就是一帧。

可校验的停止帧示例

下面是人为构造的REQUEST:flags=0x02、sequence=0x1234、JSON为{"stop":true},载荷13字节,总长24字节。十六进制中的34 12是小端序号,不是两个独立序号。

A5 4E 02 02 02 34 12 0D 00 7B 22 73 74 6F 70 22 3A 74 72 75 65 7D 62 89

将其作为编码器单元测试向量;不要把十六进制字符文本直接作为UART二进制帧发送。

HELLO与主控响应

图传相机发送的载荷结构:

{"device":"camera","deviceId":"aabbccddeeff","firmware":"1.1.0","protocols":[2],"capabilities":["mjpeg","camera_status","wifi_provision","camera_binding_v1"]}

主控RESPONSE包含device=nodehexa、protocol=2、固件信息、能力和power.lowBatteryLatched。纯运动上位机可声明device=generic_host,不冒充camera触发不需要的配网流程。本手册按键实操采用这一方式。

图传相机在未完成主控握手时每2秒HELLO,完成后每10秒HELLO,并每2秒上报cameraStatus。不要把某个HELLO响应当成后续所有请求都成功。

相机配网与档位请求

旧单机兼容载荷:

{"cameraProvision":{"ssid":"robot-network","password":"example-password","streamPort":81}}

绑定模式另外包含bssid、robotId、session。ssid最大32字节,password允许空或8–63字节;bssid为小写十六进制冒号分隔单播MAC,robotId为12个小写十六进制字符,session为32个。绑定请求必须有session。使用主控实际产生的字段,不复制示例身份。

当前相机监听端口固定81,虽然主控载荷带streamPort字段,相机并没有据此改端口。 配网ACK表示已进入处理队列,保存、连接与归属验证结果要看cameraStatus或/status。

{"camera":{"op":"setProfile","profile":"qvga"}}

profile仅接受小写qvga或vga。响应成功表示接受切换,完成以framesize、profilePending及相机状态确认。错误包括invalid JSON、invalid camera request、unsupported request等;不要把错误当成自动重试动作的理由。

运动控制载荷

相机板作为上位机向NodeHexa发送REQUEST,JSON由主控运动入口解析。入门优先使用有边界的动作:

{"sequenceId":1001,"sequence":[{"movementMode":"forward","cycles":1,"speedOverride":0.25}],"append":false}

主控RESPONSE匹配UART sequence;status=success表示已接受。完成后EVENT载荷形如:

{"event":"sequenceComplete","sequenceId":1001}

UART sequence与业务sequenceId是两种编号:前者关联报文回执,后者关联动作完成。 不能用收到ACK代替等待动作完成。sequence数组允许1–5段,主控队列最大8段;append=false覆盖已有动作队列,不能与另一个遥控源同时争用。

停止请求:

{"stop":true}

连续基础控制中movementMode是bitmask:1待机、2前进、8后退、16左转、32右转;高级动作含cycles/steps/distance/angle等字段时建议使用字符串,避免数字索引与bitmask歧义。首次实验不要使用无限连续前进。

ACK丢失时不要盲目重发运动请求,当前实现不能假定有业务去重保障。可记录故障并发stop;即使stop发送失败,也禁止产生下一动作。拔断串口后上位机无法保证stop送达,因此实操用有限周期动作,并保留机器人实体断电手段。

低电量与链路状态

主控HELLO和HEARTBEAT响应包含低电量锁存字段;EVENT可能报告lowBattery。收到低电量时终止策略,不尝试关闭保护来继续动作。当前主控把外设在线状态与收到的v2帧关联,离线判定不是运动指令租约:不要假定UART断线会自动停止任意连续运动。

旧版主控还支持$开头、换行结尾的JSON文本,但新图传相机解析器只实现v2。本教程统一用v2,新代码不在同一链路上混发两种协议。