做了几年物联网无线通信,我一直自诩“工程派”,信奉能用就行的原则。前些年一提到LoRa组网,很多人的第一反应就是上LoRaWAN,用现成协议栈,我也一样。直到在几个现场项目里被标准协议的复杂配置和平台依赖折腾得够呛,才慢慢意识到,LoRa本身是一片非常适合跑私有协议的画布,组网方式和协议设计都还有大量文章可做。这篇文章想把LoRa组网的几种主流方式拆开讲清楚,再重点聊聊私有协议从参数设计、帧结构到通信流程的完整落地路径。适合正在做传感器上报、工业采集、园区监控这类低速率、远距离、低功耗场景的工程师参考,尤其是那些不想被LoRaWAN零散概念绕晕的团队。
1. 先把LoRa这个东西掰开看:为什么它很适合私有协议组网
1.1 LoRa的物理层优势,恰恰是私有协议的温床
LoRa用的是一种基于Chirp扩频的调制方式,和FSK那种“信号一来就占上频带”的方式不一样,它把信号扩展到更宽的频带上,接收端通过相关解调把淹没在噪声里的信号捞回来。好处是接收灵敏度可以压到-130dBm这个量级,城市环境里一两公里或者更远都常见,开阔场地甚至能传得更远,当然代价是速率会非常低。
这个物理特性决定了LoRa适合传什么。一段125kHz带宽的信道,如果不做特殊配置,实际有效速率常常只有几千bps。视频、大文件基本别想,传温湿度、水浸、门磁、电表读数这类几十字节的小帧,倒是再合适不过。对私有协议来说,这反而是优势:业务简单,帧设计不需要撑得很胖;功耗可控,节点平时深度睡眠,偶尔醒一次发几个字节就继续睡,电池可以撑很久。
1.2 别急着选协议,先想清楚“谁在听谁说话”
回答LoRaWAN还是私有协议这个问题,不要凭喜好,要看网络的实际需求。每个节点都直接和中心网关通信,流量很小,两种方案都能做,差别只在开发侧重点。如果网络拓扑比较特殊,比如存在中继转发、异频分组、多子网汇聚,或者节点行为需要高度定制,LoRaWAN反而容易束手束脚。再考虑设备成本、量产效率和客户对代码可控性的要求,私有协议几乎就是必选项。
我见过不少团队,一开始引入LoRaWAN,结果连入网流程、密钥管理、区域参数配置都折腾了好几个月。倒不是说私有协议简单,而是它能让你把精力放在自己的业务上,不被通用机制的复杂度淹没。关键是,你得有能力把私有协议设计得足够可靠,并且经过真实现场反复打磨。
2. 四类组网方式逐项拆解:从点对点到混合架构
2.1 点对点直连:最简单,但别把简单当成简陋
点对点是最基础的LoRa组网方式,适合两个固定设备之间传数据,比如水位计和闸房之间、两个车间的联动信号。这种模式下没有中间网络,两台LoRa设备只要工作频率一致、空中参数一致,就能互发数据。直接用透传模块,把串口收到的字节原封不动搬过去,确实省事。
省事不代表不用防护。至少要有应用层帧头、长度和CRC校验。如果没有CRC,无线噪声造成一两个bit翻转,数据悄悄变了设备也不知道。更关键的是,点对点场景里很容易出现“双向同时收发”的错觉。LoRa是半双工,收发同频时不能同时接收和发送。如果不做时分规划,现场就会出现高优先级命令被大量数据包淹没的情况。我习惯的做法是固定主从关系,主站轮询、从站上报,两边都用短帧加ACK,逻辑简单且可靠。
2.2 星型组网:一中心带动一群节点
星型结构是目前用得最多的一种组网方式。网关位于中心,所有节点直接和网关通信,没有节点需要替别人转包。LoRaWAN默认就是这种架构,私有协议也可以照搬。好处很直接:节点功耗容易控制,因为节点只需要和网关这一个目标建立关系;路由逻辑为零;网关可以统一做数据汇聚、报文解析和业务转发;扩容也容易,只要网关覆盖够,边缘加新节点就能上线。
代价是网关单点化,一旦网关硬件出问题或断电,整个区域通信就断了。设计星型网络时,网关的供电、天线位置、故障复位逻辑往往比节点更关键。节点数量增多后,必须提前规划每个节点的时隙或信道,否则大家同时给网关发数据就是相互撞车。我做过一个80个节点的温度采集项目,用单网关星型,把节点分成四组,定时错开上报,实测效果很好。这种分组调度必须写进私有协议里,不能靠运气。
2.3 多跳Mesh组网:看起来很美,踩坑无数
偶尔有人问LoRa能不能做mesh。物理上当然可以,只要模块设置成收发同频,每个节点既能当终端又能当中继,协议上做洪泛转发或者简单路由,就能让边缘节点通过几次跳转到达网关。这套思路在不少无线技术中很成熟,但到了LoRa这里,问题会被放大。
LoRa空中速率只有几千bps,一跳传几十字节就要好几十毫秒,三跳五跳之后延迟叠加,同一个数据包还会被多个邻居重复转发。转发节点不能深度睡眠,因为随时可能被叫醒做中继,功耗直接从微安级跳到毫安级,电池扛不住。我在野外环境监测项目里试过三跳中继,每两分钟上报一次,中间节点的电池三个月就见底,最后换回星型加直连才解决。
所以我的结论是:LoRa mesh只适合节点不必频繁上报、中继路径很短、中继点能外接电源的特定场景,别把它当WiFi替代方案。如果确实要mesh,私有协议里必须做跳数限制、邻居表去重和随机转发时延,这几项都需要一帧一帧调试,工作量不会小。
2.4 混合组网:现实中真正负责的方案
实际项目里,网络往往不是教科书里的纯星型或纯mesh。比如一个大型厂区,有的点位离网关只有300米,有的点位躲在几堵墙后面,有的区域设备密度特别大。这种时候,更好的结构往往是:几个边缘采集器先用RS-485把附近的传感器汇聚起来,再用LoRa星型长传;或者在主网络中,个别盲区节点通过中继转发一次。混合组网在私有协议里很容易实现,因为你可以自己定义帧格式,在数据负载里加一个中继标记,每一跳由节点转发时改写路径字段,网关侧看到的就是完整链路信息。
混合组网的核心不是技术参数,而是工程取舍。要在项目初期把每个点位的距离、遮挡情况、节点密度画出来,估算数据量,再决定哪些位置放中继、哪些位置用RS-485汇聚。我做仓储环境监测时就是混合结构:仓库内传感器走星型,仓库外几个死角点位加了一级中继,整体调试时间比全星型还少,因为省掉了为覆盖死角单独架天线的成本。
3. 私有协议的技术底层:物理层参数和成帧设计
3.1 频率、带宽、扩频因子到底怎么定
先定“在哪说话”。国内LoRa设备一般走高频率区间,比如470-510MHz,这个范围可用连续频点多。组网时至少要规划出业务信道、紧急事件信道和配对升级信道三类。业务信道跑常规数据;紧急事件信道留给报警;升级信道为后面OTA预留。频率规划要结合模块能力和现场环境,不能乱来。
然后是带宽(BW)和扩频因子(SF)。LoRa常用带宽是125kHz、250kHz、500kHz,SF可选7到12。SF越高,接收灵敏度越好,能传得更远,但每一符号携带的信息变少,空中速率下降。低SF适合近距离高吞吐,高SF适合远距离低速率。
空中速率可以用一个经验公式估算:Rb = SF × (BW / 2^SF) × CR,CR是编码率,通常取4/5。举个例子,BW=125kHz、SF=7、CR=4/5时,Rb大约就是 7×125000/128×4/5 = 5468 bps;如果SF调到10,速率会降到几百bps。所以不能拍脑袋定参数,要根据最大覆盖距离和业务数据量反推。距离远就选高SF,帧多就选低SF,二者不可兼得。
3.2 私有协议不只是“帧格式”,是整个通信规则集合
很多人提到私有协议,第一反应是“自定义一个数据包格式,前后几个字节代表什么”,但这只是其中一层。一个能用的私有协议至少要定义物理层参数、MAC层规则、会话层规则和应用层规则四个层面。物理层包括频率、带宽、扩频因子、编码率、CRC开关、前导码长度;MAC层包括设备地址、帧类型、序列号、ACK和重传策略;会话层包括入网、退网、密钥协商、时间同步;应用层才是具体的命令字、数据字段顺序、单位和报警阈值。
只有把这些都写清楚,协议才算真正落地,否则只是临时拼接的一堆字节。最怕的是项目结束后换人接手,看不懂参数含义,或者设备配网时两边参数不一致,怎么调都连不上。我曾经见过一个项目,模块空中速率不一致,两边都收不到数据,排查两天才发现是基础参数没对齐。这个教训非常深刻。
3.3 帧结构设计实例:地址、类型、序号、长度、CRC一个都不能少
下面给一个适用于大多数业务场景的应用层帧结构示例,字段按低字节到高字节排列:
| 字段 | 长度 | 说明 |
|---|---|---|
| 类型 | 1字节 | 区分请求、响应、上报、确认 |
| 版本 | 1字节 | 协议版本号,用于兼容扩展 |
| 源地址 | 2字节 | 当前节点短地址 |
| 目标地址 | 2字节 | 目标节点或网关地址,广播可用0xFFFF |
| 序号 | 1字节 | 发送方每帧递增,用于去重和重传匹配 |
| 长度 | 1字节 | 负载长度,单位字节 |
| 负载 | N字节 | 业务数据 |
| 校验 | 2字节 | 对类型到负载做CRC16校验 |
为什么一定要加序号?LoRa空口有丢包和误码,接收方可能收到重复帧。如果应用层不做去重,传感器数据会被重复入库,后台统计就会错乱。CRC16可以用标准多项式计算,代码成熟,只有十几行。设计私有协议时,建议把版本字段放在类型之后,方便以后扩展。比如类型0x01是V1版本的上报,0x11是V2版本的上报,网关根据版本选择解析逻辑。业务不复杂时,不必一上来就搞TLV格式,先保证能跑,再考虑可扩展。
3.4 如果选择LoRaWAN,私有协议还有没有必要
LoRaWAN解决了很大一部分通用问题:它把物理层之上的MAC、入网、加密、设备生命周期管得清清楚楚,有Class A/B/C三种接收模式,有标准的入网流程,有应用密钥和会话密钥,还支持空中激活和ABP激活。要是项目需要接入现成的物联网云平台,或者设备要卖给多种场景的客户,直接上LoRaWAN能省掉很多自研成本。
但这不代表私有协议没有价值。LoRaWAN是标准化通用协议,要兼顾全球大量场景,配置项多,服务器侧调度复杂。如果项目只在某个区域内部署几十个节点,所有设备固件都是自己的,也不打算接入第三方平台,那么私有协议会让你更有掌控力:想加透传命令就加,想调时隙就调,想加端到端加密也方便。从成本角度看,LoRaWAN的网关和节点要满足特定规范,私有协议用透传模块加MCU自己写就能跑,硬件成本可以压得很低。我的选择逻辑是:规模小、封闭、高度定制,用私有协议;规模大、开放、多厂商互通,用LoRaWAN。二者不是敌人,只是场景不同。
4. 私有协议通信流程:从入网到业务轮询的完整设计
4.1 节点入网注册
节点上电以后,第一件事不是直接发业务数据,而是先入网。原因很简单:网络里可能有很多节点,网关需要知道每个节点的设备ID、版本和射频参数,才能正确调度。入网流程可以设计成三步:节点发送入网请求,负载里带唯一设备ID、硬件版本、固件版本和随机数;网关收到后校验合法性,如果允许接入就为节点分配短地址,并把短地址、网关时间戳、心跳周期放进入网确认帧返回;节点收到确认后校验CRC和内容,保存短地址,进入正常工作状态。
这里有个很容易忽略的点:随机退避。如果几十个节点同时上电,都在同一秒发起入网请求,网关会瞬间收到一堆帧,必然冲突。所以入网请求的发送要加0到5秒的随机延时,然后再重试。重试次数要设上限,比如3次,失败后进入低功耗休眠,等下一个唤醒周期再尝试。网关侧也要实现超时清理,节点连续多天不上报就自动注销短地址,避免地址越积越多。
4.2 上行数据上报的三种模式
上行数据是私有协议里最高频的动作,我用得最多的是三种模式:
- 事件主动上报:传感器检测到变化,比如门磁打开、水浸告警、温度越限,节点立刻被唤醒并发帧。优点是实时性好,缺点是多个节点同时产生事件时冲突概率高。
- 定时周期上报:节点按设定间隔醒来,比如每15分钟发一次温湿度。优点是网关调度好做,缺点是紧急事件可能要等到下一个周期才能出去。
- 网关轮询上报:节点平时深度睡眠,网关按名单逐个发查询命令,节点收到后立即回复。优点是冲突可控,缺点是实时性取决于轮询周期和节点总数。
实际项目里我一般把周期上报和事件上报混用:默认定时上报,数据异常时立刻发事件帧,事件帧走专门信道。这样既保证日常数据完整,也保证报警能尽快送达。
4.3 下行控制命令与确认重传
LoRa是被动接收困难的技术,节点平时睡眠,网关不知道它什么时候醒,下行命令的时序必须设计得很严格。方案一是借鉴LoRaWAN的Class A机制:节点每次上行数据包结束后,打开一个短暂的接收窗口,比如等待500毫秒,网关想下发命令就趁这个窗口发下去,窗口结束节点继续睡。实现简单,缺点是网关不能随便下发实时命令,只能等节点主动上报。
方案二是信标同步:网关定期广播一个同步信标,节点从信标里拿到下一次唤醒时间,到点醒来统一接收网关下发的命令队列。实时性更好,但需要节点和网关都有比较准的时钟,代码复杂度也上去了。不管哪种方案,ACK和重传都必不可少。上行数据帧和下行命令帧都需要确认,接收方收到后立即回ACK。发送方超时未收到ACK,要做指数退避重传,比如重试上限3次,重传间隔逐次加倍。ACK也要带序列号,防止把上一次的确认错配到新数据帧上。
4.4 一帧数据在空口上的完整旅程
把上面这些串起来,实际业务数据的空口生命周期大致是:节点MCU从传感器拿到温度值,拼装业务负载;按协议组帧,填入类型、版本、源地址、目标地址、序号、长度和负载,计算CRC;MCU把整帧交给LoRa模块,以预定频率和扩频因子发送;网关射频解调出数据,检查物理层CRC,错误就丢弃;网关把正确帧通过串口或以太网传给后台,后台根据源地址和序号做去重入库;后台需要下发指令或确认时,在同一路径上回ACK帧或主动下行;节点在接收窗口内收到ACK,清掉对应序号的待确认记录,否则超时重传。
整个过程看起来简单,每一环却都有细节。网关的接收窗口要设置足够长,否则节点帧发完网关还没来得及回ACK,节点就会误以为丢包;节点的接收窗口又不能无限长,否则功耗升高。这类参数最好做成配置项,在调试时根据实际时延调整,不要写死在代码里。
5. 一个实战案例:仓储环境监测的私有LoRa网络
5.1 项目场景与组网拓扑
这个项目是个约一万平方米的仓储区,需要监测温湿度、门磁、水浸和少量烟雾报警。总节点数大约80个,网关放在仓库中央监控室,天线装在屋顶。仓库内部钢结构隔断多,但整体覆盖半径不超过300米。我最后确定用470MHz频段,BW125kHz,SF10。SF10灵敏度高,穿透钢结构更好,速率虽然降到几百bps,但每帧只有十几个字节,完全够用。
网络拓扑选的是星型加局部中继。仓库内部全部直连网关;外围两个小房间因为墙角遮挡严重,专门放了两台中继设备,把几个传感器转一下。中继转发在私有协议里只是上报帧经过中继节点时改写路径字段,几乎没有增加复杂度。
5.2 私有协议具体定义
命令字表列一部分:
| 命令字 | 含义 | 方向 | 负载说明 |
|---|---|---|---|
| 0x10 | 注册请求 | 节点→网关 | 设备ID、版本、随机数 |
| 0x11 | 注册响应 | 网关→节点 | 短地址、心跳周期 |
| 0x20 | 周期数据上报 | 节点→网关 | 温湿度、电量 |
| 0x21 | 周期数据确认 | 网关→节点 | 对应序号 |
| 0x30 | 事件上报 | 节点→网关 | 事件类型和状态 |
| 0x31 | 事件确认 | 网关→节点 | 对应序号 |
| 0x40 | 网关卡查询 | 网关→节点 | 查询命令 |
| 0x41 | 节点数据响应 | 节点→网关 | 查询结果数据 |
每个设备正式上线前都有一个唯一的32位MAC作为设备ID。节点入网后,网关分配一个2字节的短地址,日常通信全部用短地址。这样做的好处是空中帧短、通信效率高,设备ID只在注册阶段出现,也降低被监听的隐私风险。
5.3 网关与节点的状态机设计
节点状态很简单:
| 状态 | 触发条件 | 动作 |
|---|---|---|
| 入网请求态 | 上电 | 随机延时后发0x10 |
| 正常睡眠态 | 收到0x11 | 保存短地址,按周期定时唤醒 |
| 上报态 | 定时唤醒或事件触发 | 组0x20或0x30帧发送 |
| 等待确认态 | 发送完成 | 打开发送后接收窗口,等待ACK |
| 离线休眠态 | 入网重试超限 | 长时间睡眠,等待下次重试 |
网关状态相对集中:常态监听信道,收到帧就解析、校验、入库,然后按目标地址回ACK;后台主动查询时,从查询队列取命令,按目标地址下发0x40,然后等待节点响应,超时则标记该节点查询失败。状态机文档化后,写代码基本就是查着表写,不会临时改逻辑。
5.4 现场效果和参数实测
80个节点分组错峰上报。以一天周期为例,每个节点每天定时上报约48次,每次上行业务帧约18字节,ACK帧约7字节。由于使用SF10和125kHz带宽,实际速率只有几百bps,单帧从发送到ACK结束约300毫秒。把节点分成4组,每组20个,组内再随机分散上报时刻,单次轮询期间信道占用率远低于30%,几乎没有碰撞。
节点采用3.6V锂电池供电,平均待机电流几微安,上报时工作电流几十毫安且持续时间短。按每天上报48次估算,电池用一年以上基本没问题。这个项目的难点其实不在覆盖,而在参数匹配和信令冲突,后面我会专门展开。
6. 这些坑我基本都踩过,写出来给你避雷
6.1 “明明信号很强,就是丢包”的真相
很多项目问题都表现为“网关显示信号强度很高,比如-85dBm,可还是大量丢包”。第一次遇到我也很困惑,后来大多数情况都是三类原因:同一区域存在多个LoRa设备用相同频率和参数,互相干扰;信号强度高不代表信噪比好,周围偶发的干扰脉冲会让LoRa接收机解调不出有效数据;发送速率设得太低,一帧占空时间过长,节点间碰撞概率指数上升。
排查方法很简单:把网络里其他节点全部关掉,用两个设备点对点发数据看丢包率。如果正常,基本就是网络冲突问题;如果仍然异常,检查频率偏移、带宽、扩频因子是否一致。模块固件版本不同导致默认空中参数不一致,也会出现设备之间“互相看不见”的怪现象,所以现场设备最好统一固件基线。
6.2 节点多了以后的重传风暴
私有协议最容易翻车的地方是节点数量增长后,重传次数跟着增长。典型症状是单个节点调试一切正常,50个节点同时上线后,网关收到大量重复帧,后台数据库出现一堆与实时状态不符的旧数据。原因在于很多节点发送失败后等待相同时间再重传,窗口一致,撞了又撞。
解决办法是把重传退避随机化。初始重传延时选择0到2秒之间的随机值,每次重传都用随机退避,避免整齐划一的碰撞。网关侧也要做去重:维护一个已处理帧序号的缓存,凡是重复序号直接丢弃。这样即使空口发生重传,后台数据也不会被污染。
6.3 模块配置里的“隐形参数”最坑
很多人调LoRa只关注频率、功率和串口波特率,但模块里还有几个参数会影响组网。前导码长度不一致可能收不到;空中速率与串口速率要分开理解,串口速率高、空中速率低,数据会在模块内部积压,造成首包时延;CRC开关两端配置不一致会在解调后丢弃数据;部分模块支持跳频模式,不统一开启或关闭,收发也会对不上。发射功率设置太大,近距离节点可能产生谐波干扰相邻信道,整个频段都受影响。
建议团队正式部署前写一份模块参数基线表,所有现场设备按同一基线刷写。调试不要相信“出厂默认”,每次更新固件都检查一遍参数。
6.4 私有协议别忽视加密
LoRa本身有抗击噪声和干扰的设计,但不代表空口数据别人读不出来。用软件无线电设备就能在空中抓到LoRa信号并解调,私有协议如果只传明文数据,等于把传感器信息广播给整个区域的人。后面一旦涉及温度、门禁、设备状态,很容易被同行或别有用心的人拿走分析。
所以即便用私有协议,也要做应用层加密。入网阶段完成密钥协商,后续业务负载使用AES或轻量对称算法加密后再组帧。密钥可以预置在设备里,也可以由网关动态生成并下发。加密会增加几毫秒到几十毫秒的计算时间以及几个字节的扩展,对LoRa这种小帧场景影响很小,值得做。
7. 关于私有协议,最后再分享三点工作心得
7.1 把协议版本管理当成一等公民
私有协议最大的坑是升级后不兼容。现场已经有几十台设备时,你敢不敢改帧格式?如果改,老设备怎么办?所以我从很早开始就在每个帧里加了版本字段,放在帧头部的固定位置,网关先读版本再决定解析方式。这样即使后来在温湿度负载里增加一个电压字段,老设备发来的旧版本帧网关也能正常解析,新设备发来的新版本帧能读到更多辅助数据。
协议文档也要跟着版本走。我习惯用一张表记录命令字、字段含义、字节偏移、单位、允许范围、修改日期和变更原因。项目结束半年后再回头看,能看懂这些表的人才能维护这套系统。别让私有协议成为“开发者在时能用,开发者走了就报废”的黑盒子。
7.2 能维护的私有协议才有价值,别搞一次性代码
有些团队写私有协议只为了应付当前项目,代码里全是魔数、硬编码时延、隐式状态假设。结果项目一交付,后续想加一个查询命令,都要翻开几百行代码找逻辑。与其这样,不如项目初期花一点时间把协议栈抽象成三层:物理层参数配置、链路层帧收发、应用层命令调度。每一层留好接口,后续改业务时不用动底层。
我会在工程代码里把组帧、解析、CRC、重传队列做成独立模块,单元测试也覆盖这些模块。开发时确实多花了一些时间,但省下的是现场排障和后期维护的精力,算下来非常划算。
7.3 别为了“私有”而私有,该用LoRaWAN时果断用
私有协议很好,但不是万灵药。如果项目需要接入多厂商设备,未来设备数量可能翻几倍,或者用户要求平台开放、支持漫游和全球部署,那还是直接上LoRaWAN更靠谱。强行用私有协议去做LoRaWAN本来就很擅长的事,只会把自己困在无穷无尽的自定义开发里。
我的对照标准是:节点数量百级以内、网络封闭、业务固定、需要深度定制,优先私有协议;节点数量大、需要多厂商互通、希望省去大量协议维护成本,优先LoRaWAN。两者也可以并存:一些特殊终端走私有协议,公共终端走LoRaWAN,网关内部跑两套协议栈完成翻译。这个路线我真实测过,效果不错,前提是网关的处理能力和内存要足够。
这套东西做下来,我的体会是:真正做好一套私有LoRa网络,考验的是对物理参数、通信时序和现场链路状态的综合把握。希望这篇内容能帮你少走弯路。后面动手做项目时,建议先画拓扑、再定协议、最后调参数,这个顺序千万别反。