16个版本 (6个稳定版)
1.0.5 | 2024年5月30日 |
---|---|
1.0.4 | 2024年5月25日 |
0.1.9 | 2024年3月4日 |
0.1.8 | 2024年1月20日 |
#157 in 嵌入式开发
1,012 每月下载量
用于 nano-mesh-linux-examples
78KB
1K SLoC
嵌入式设备网状网络协议
这是无线网状网络协议。它设计得轻量级,易于移植到多个平台,且易于使用。该协议使用MCU的串行端口与其连接的射频模块进行交互。该协议允许使用任何具有USART接口的射频模块,因此可以使用任何具有USART接口的射频模块和MCU构建网状节点。
MCU - 微控制器计算机单元。 (Arduino, Raspberry Pi, PC等)
节点架构
(Library code runs here)
|
|
V
+----------------+ +-----------------+
| | USART | |
| MCU |<------------>| Radio module |
| | | |
+----------------+ +-----------------+
该协议已在JDY-40射频模块上进行了测试,并可能可以使用具有类似UART接口的射频模块,例如
- JDY-41
- SV-610
- HC-11
- HC-12
- LC12S
- GT-38
- LoRa模块
目标
本项目目标是提供一种易于使用、基于网状架构、适用于低成本、低内存组件的数据传输协议。该协议可用于
- 智能家居
- 远程控制
- 远程监控(遥测)
- 去中心化消息传递
- 等。
工作原理
协议传播数据的方式
该协议以最简单的方式路由数据包。它以类似池塘中波纹扩散的方式传播数据包。这意味着数据包被发送到最近的设备,在设备路由过程中,路由器确定数据包是否到达目的地或需要进一步传输并减少数据包的lifetime
值。一旦在路由过程中lifetime
值达到零,数据包将在路由它的设备中被销毁。
用户通过同一设备中的 send
、send_ping_pong
或 send_with_transaction
方法发送的数据包——绕过路由,直接进入发送队列。因此,即使将 lifetime
设置为 0
,消息仍会在以太网中进行首次传输。从队列中发送数据包发生在调用 update
方法时。
这意味着,用户可以发送消息:
-
将
lifetime
设置为0
,并将数据包传输到以太网,最近的设备将接收它,检查目标是否到达。如果目标已到达,则捕获数据。否则,尝试降低lifetime
值以进一步传输,这将导致数据包因lifetime
结束而被销毁。 -
将
lifetime
设置为1
,并将数据包传输到以太网,最近的设备将接收它,检查目标是否到达。如果目标已到达,则捕获数据。否则,尝试降低lifetime
值以进一步传输,这将导致数据包因相同的理由被销毁。 -
将
lifetime
设置为2
,并将数据包传输到以太网,最近的设备将接收它,检查目标是否到达。如果目标已到达,则捕获数据。否则,尝试降低lifetime
值以进一步传输,这将导致数据包回到以太网,但lifetime
值更小。
协议如何避免数据包重复
在发送数据包时,建议将 ignore_duplicates
参数设置为 true
以防止网络被重复的数据包阻塞。其工作原理如下:一旦中间节点收到设置了 ignore_duplicates
标志的 true
的数据包,
- 它将记住数据包发送者的地址和数据包的 ID,持续一定时间。
- 如果再次发送相同的数据包,节点将忽略它。这导致协议在网络中只传播一次确切的数据包。
特殊用途的数据包,如 Ping-Pong 或事务数据包,默认将 ignore_duplicates
标志设置为 true
。
状态
以下协议功能已经过测试和验证:
- 发送数据。
- 接收数据。
- 发送忽略重复数据包的数据。
- 发送跳数有限的数据。
- 向所有节点广播数据。
- 通过中间节点进行消息传输。
- 发送带有 ping 标志的数据,并接收带有 pong 标志的响应。
- 通过事务发送数据并接收事务完成的数据包。
跨平台兼容性
该网状网络已在同一网络中使用几个 Arduino nano 板和一台 Linux 机器进行了测试。
目前该协议已在以下设备上进行了测试:
- Arduino nano
- Linux(Raspberry PI、桌面)
可能可以移植到以下平台:
- Windows
- Mac
- STM32
- ESP8266
- Raspberry PI pico
移植到其他平台
虽然最初设计为能够在至少 Atmega328p 芯片上运行,但它可以被移植到各种其他平台。平台应当由 embedded-hal
支持。
此外,此协议也欢迎移植到其他平台。为了简化将此协议移植到新平台的过程,将公共行为从实现中移出,使其与其他平台的PlatformMillis和PlatformSerial特质的实现可以互换。因此,库不是平台相关的。
要将协议移植到新平台,您需要实现这两个通用接口。
PlatformSerial
- 用于通过USART与无线电模块通信的接口。PlatformMillis
- 用于追踪时间的接口。
如果您已经为您的平台实现了PlatformSerial
和PlatformMillis
特质,您可以联系此库的开发者,以在此README中包含您实现的链接。联系方式如下:
- Telegram频道: https://t.me/embedded_nano_mesh
- Github: https://github.com/boshtannik 这将有助于该项目的发展。
如果已存在平台的实现,您只需简单地将它们包含到您的项目中即可。1 - 在您的项目中包含 platform-serial
和 platform-millis
。 Cargo.toml
embedded-nano-mesh = "1.0.5"
platform-millis-arduino-nano = { git = "https://github.com/boshtannik/platform-millis-arduino-nano.git", rev = "..." }
platform-serial-arduino-nano = { git = "https://github.com/boshtannik/platform-serial-arduino-nano.git", rev = "..." }
2 - 在您的项目中包含 platform-serial
和 platform-millis
。 src/main.rs
use embedded_nano_mesh::*;
use platform_millis_arduino_nano::{init_timer, ms, Atmega328pMillis};
use platform_serial_arduino_nano::{init_serial, ArduinoNanoSerial};
3 - 使用 PlatformSerial
和 PlatformMillis
实现
/// Send ping-pong example:
match mesh_node.send_ping_pong::<Atmega328pMillis, ArduinoNanoSerial>( ... ) { ... }
/// Send with transaction example:
match mesh_node.send_with_transaction::<Atmega328pMillis, ArduinoNanoSerial>( ... ) { ... }
/// Update example.
let _ = mesh_node.update::<Atmega328pMillis, ArduinoNanoSerial>();
完整的示例如下。
Arduino nano端口。
Arduino nano板的PlatformSerial实现由
Arduino nano板的PlatformMillis实现由
使用示例可以在此处找到
有时代码的二进制文件可能无法适应您的Arduino板内存,为了减小最终二进制文件的大小,建议使用 --release 标志进行编译 - 它增加了优化级别,从而导致二进制文件更小。
Linux端口。
Linux的PlatformSerial实现由
Linux的PlatformMillis实现由
使用示例可以在此处找到
用法
此协议的核心组件是Node
结构,它提供了发送、接收、广播、ping-pong以及带有事务的消息发送等操作的接口。应不断通过调用其update
方法来更新Node
,它 - 执行所有内部工作
- 通过网络路由数据包,转发发送到其他设备的数据包,处理数据包的
lifetime
。 - 处理特殊的如
ping
和pong
数据包,或任何类型的交易。 - 保存通过
receive
方法可用的接收到的数据包。 - 发送处于
send
队列中的数据包。
要初始化一个Node
,您需要向NodeConfig
提供以下值
ExactAddressType
:设置节点池中设备的标识地址。listen_period
:设置以毫秒为单位的时间,确定设备在网络上传送之前将等待多长时间。它防止网络拥塞。
您可以通过在发送消息时配置lifetime
来调节数据包能够进行跳转的数量 - 例如
- 将
lifetime
设置为1将限制消息的传输范围到网络中的最近设备。 - 将
lifetime
设置为10将使数据包能够在被销毁之前通过10个节点。
要将消息发送到网络中的所有节点,您可以使用标准的send
方法发送,并将GeneralAddressType::BROADCAST
作为destination_device_identifier
。每个设备都将GeneralAddressType::BROADCAST
视为自己的地址,将消息作为接收到的消息保留,并将该消息的副本进一步转发。
要将消息发送到网络中的特定设备,您可以使用标准的send
方法,并将GeneralAddressTyp::ExactAddressType(...)
作为destination_device_identifier
。
“回声消息”一词指的是由中间设备重新传输到以太网的重复消息。
接收方法
如果该数据包之前已被此确切设备接收,则receive
方法可选择性地返回包含在PacketDataBytes
实例中的接收数据。
发送方法
send
方法需要以下参数
data
:用于保存消息字节的PacketDataBytes
实例。destination_device_identifier
:一个GeneralAddressType
实例,在使用GeneralAddressType::Exact(...)时指示确切目标设备,在使用GeneralAddressType::BROADCAST时指示接收消息的所有设备。lifetime
:一个LifeTimeType
实例,用于控制消息可以传输多远。filter_out_duplication
:一个布尔标志,用于从网络中过滤掉回声消息。
发送Ping-Pong方法
send_ping_pong
方法向目标节点发送带有“ping”标志的消息,并等待带有“pong”标志的相同消息。如果在ping-pong交换失败时返回错误。以下参数是必需的
data
:一个PacketDataBytes
实例。destination_device_identifier
:一个ExactAddressType
实例,指示确切的目标设备地址。lifetime
:一个LifeTimeType
实例。timeout
:一个ms
实例,指定等待响应的时间长度。
使用事务发送
send_with_transaction
方法发送消息,并处理所有后续工作以确保目标设备已正确接收。如果在事务失败时返回错误。必需的参数是
data
:一个PacketDataBytes
实例。destination_device_identifier
:一个ExactAddressType
实例,指示确切的目标设备地址。lifetime
:一个LifeTimeType
实例。timeout
:一个ms
实例,用于指定响应等待时间。
减少数据包冲突
建议将多个设备的listen_period
值设置为彼此不同,例如
- 设备1 - 230 ms,
- 设备2 - 240 ms,
- 设备3 - 250 ms,这将减少网络同步的机会,从而导致数据包冲突。您可以调整这些值以减少数据包冲突的机会。
注意:网络中节点的数量越多,网络就越稳定。在稳定的网络中,很少需要使用transaction
或ping_pong
发送,除非您发送非常重要的事情。
警告
此协议不提供数据加密。为了保护您的数据免遭窃取,您应独立实现(解/加密)机制。
所有节点必须安装相同版本的协议才能进行通信。对Packet
结构的不同实现,或序列化或反序列化方法将导致通信问题。
注意
在底层,数据被打包到一个 Packet
实例中。如果您需要根据需求自定义数据包,则需要配置 Packet
字段,在 src/Node/packet/config.rs
和 src/Node/packet/types.rs
文件中。同时,序列化和反序列化部分也需要进行更改。
许可证
本项目采用以下许可证
- GNU通用公共许可证,版本3.0 (LICENSE-GPL 或 GPL许可证)
- Apache许可证,版本2.0 (LICENSE-APACHE 或 Apache许可证2.0)
- MIT许可证 (LICENSE-MIT 或 MIT许可证)
您可以选择最适合您偏好的许可证。
贡献
除非您明确指定,否则任何提交给本项目以供包含的贡献,根据Apache-2.0许可证定义,将在两个许可证下双重授权,没有额外条款或条件。
捐赠
您还可以通过以下比特币地址对项目进行捐赠以支持项目:bc1qc50tm0ppj3hh7fecd6d0rv8tdygy8uhe2cemzt
依赖项
~2.5MB
~55K SLoC