国标的控制指令都是「XML 里塞一个十六进制串」: 云台、要关键帧、重启、拉框放大,四种各有各的参数。 报文只有一百五十字节,但每条都要现拼一段 XML——所以「一秒几十条」就到顶了。
上一节讲「要流」,这一节讲「指挥设备」。 控制是国标里唯一「有副作用」的流程——别的流程错了重来一次,控制错了云台已经转过去了。 所以它最需要「幂等」和「限速」。
一、四种指令各管什么
PTZCmd 是最常用的:一串十六进制,前三个字节是帧头,第四个是方向,后面是速度。
IFrameCmd 是「请求一个关键帧」:
解码器花屏时发一条,让设备立刻出一个 I 帧,画面马上恢复。
这是运维手里最实用的一个工具。
TeleBoot 是远程重启:设备卡死的时候用,但它有风险——重启期间完全不可用。
DragZoom 是拉框放大:给一个矩形坐标,设备自己算云台怎么转、镜头怎么变倍。
注意后三种的参数都是空的:动作完全由 CmdType 表达,参数留空是正常的。
填了反而可能被设备拒掉。
二、为什么报文这么「胖」
一条控制报文一百五十字节,参数只占十几个字符,剩下全是 XML 标签和固定字段。
固定字段有四个不能不写:
CmdType 说明干什么、SN 配对请求、DeviceID 指定设备、参数本身。
所以控制报文的「有效载荷率」不到一成——这是 XML 协议的常态,不是实现问题。
十六进制串还有一层膨胀:七个字节写成十四个字符,长度翻倍。
换来的是「人能读、XML 好装」,代价是白多一倍字节。
这些开销单看都很小,但它们决定了「控制能有多密」:
一秒几十条就到顶,再密就得考虑合并或二进制协议了。
三、重发为什么会让云台转飞
控制指令会重发:网络超时、SIP 重传、平台重试,同一条可能到两次。 连续转动是幂等的:「向左转」到两次,结果还是「向左转」,不会转两倍。 相对位移不是:「向左转十度」到两次,就转了二十度。 绝对定位也不是——虽然结果一样,但中间会多一次抖动。 所以「要不要重发」取决于指令类型,不是取决于网络好不好。 统一加重试是最省事也最容易出错的做法。 正确的做法是「控制指令不自动重试,让用户重按」: 人看得见结果,重按是自然的;程序看不见结果,重试是危险的。
四、动手 Demo:四种控制指令,装进 XML 之后有多长
按真实格式造四条控制报文,量参数长度和整条长度。 再算「重发三次」的代价,以及十六进制串的膨胀率。
body = ('<?xml version="1.0"?>'
"<Control><CmdType>DeviceControl</CmdType>"
"<SN>1</SN><DeviceID>34020000001320000001</DeviceID>"
"<PTZCmd>%s</PTZCmd></Control>" % cmd)
for name, cmd in (("PTZCmd", "A50F0102800000"),
("IFrameCmd", ""), ("TeleBoot", ""),
("DragZoom", "")):
print(name, len(cmd), len(body))
print("7 字节写成十六进制", len("A50F0102800000"), "个字符")
实跑输出:
--------------------------------------------------------------------
四种控制指令,装进 XML 之后有多长
--------------------------------------------------------------------
**国标的控制指令都是「XML 里塞一个十六进制串」**:
**`PTZCmd` 转云台、`IFrameCmd` 要关键帧、`TeleBoot` 重启、`DragZoom` 拉框放大。**
**这一节把这四种各造一条,量它们装进 XML 之后有多长。**
指令 参数长度 整条报文 用途
-----------------------------------------------------------------
**PTZCmd** **14** **154 字节** 向左,半速
**IFrameCmd** **0** **140 字节** 请求一个 I 帧
**TeleBoot** **0** **140 字节** 远程重启
**DragZoom** **0** **140 字节** 拉框放大
四条合计 574 字节
参数本身合计 14 字节,报文合计 574 字节
**参数只有十几个字符,报文却有一百五十字节**——**XML 的标签和固定字段占了大头。**
**所以国标控制「一秒几十条」就到顶了**:**不是算不过来,是每条都要现拼一段 XML。**
**十六进制串还有一个隐形的膨胀**:**七个字节写成 `A50F0102800000` 是十四个字符**,
**长度翻了一倍。**
**好处是「人能读、XML 好装」,坏处是「白多一倍带宽」。**
**注意 `IFrameCmd`、`TeleBoot`、`DragZoom` 三行的参数是空的**:
**它们的动作完全由 `CmdType` 表达**,**参数留空是正常的,不是漏填。**
**填了反而可能被设备拒掉。**
**控制的可靠性靠「重发 + 幂等」**:
一条控制报文一百五十字节,重发三次就是四百五十字节
连续转动可以重发,相对位移不能重发
**所以「要不要重发」取决于指令本身**,**而不是取决于网络好不好。**
**这条规则在写平台代码时最容易被忽略**——**统一加重试,反而会把云台转飞。**
四条报文都在一百四十到一百五十四字节之间,而参数最多的那条也才十四个字符。 标签和固定字段占了九成以上。 所以「国标控制一秒几十条就到顶」不是算力问题,是每条都要现拼一段 XML、现发一个 SIP 报文。 这也是为什么大项目会做「指令合并」——用户拖一下摇杆,不按每帧发,而是每几十毫秒发一条。 十六进制那行是纯粹的膨胀:七个字节变成十四个字符,长度正好翻倍。 它换来的是「人能读」,这在调试时很值钱——抓包一眼就能看出「这是向左、半速」。 最后那句「重发三次四百五十字节」看着不多, 但真正的代价不是字节,是「云台多转了」——这个错误用户一眼就能看见。
30 秒实验
- 算一下:七字节写成十六进制要几个字符?(14 个)
- 想一下:哪几种控制指令不能重发?
- 想一下:
IFrameCmd什么时候用?(花屏时)
常见误区
- 以为「控制报文很小可以狂发」。 一条一百五十字节,一秒几十条就到顶。
- 以为「所有控制都能重发」。 相对位移重发会多转一倍。
- 以为「参数留空是漏填」。 后三种指令参数本来就是空的。
自测三问(点开对答案)
1. 四种控制指令分别是什么? —— **`PTZCmd` 云台、`IFrameCmd` 要关键帧、`TeleBoot` 重启、`DragZoom` 拉框放大**。 2. 哪些指令不能重发? —— **相对位移和绝对定位**;连续转动可以重发。 3. 为什么控制报文的「有效载荷率」不到一成? —— **XML 标签和固定字段占了大头**,参数只占十几个字符。下一节讲报警:设备主动推,平台要接住的不是带宽,是处理能力。
- ☐ (本节完,下一节 10.08.04 报警事件通知和分发)