亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

概述

在本教程中,我们将学习如何构建一个由多个 NRF24L01 收发模块组成的 Arduino 无线网络。你可以观看下方视频或阅读以下图文教程。

作为示例,我搭建了一个包含 5 个节点的网络,每个节点都能与网络中的任意节点通信,同时可同时作为发射器和接收器工作。此示例的设置方式可扩展为更大规模网络——精确地说,我们可以在单个 RF 信道上让多达 3125 个模块相互通信。下面我们来看看它是如何工作的。

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

在之前的教程中,我们已经学习了如何使用 NRF24L01 模块和 RF24 库实现两块 Arduino 板之间的无线通信。现在,除了该库,我们还将使用 RF24Network 库,它能以简便的方式构建多块板卡互联的 Arduino 无线网络。以下是网络拓扑的工作原理。

多 NRF24L01 模块通信

单个 NRF24L01 模块可同时主动监听多达 6 个其他模块。

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

RF24Network 库利用这一能力生成树形拓扑网络:一个节点为基站(根节点),所有其他节点或为基站的子节点,或为其他节点的子节点。每个节点最多可有 5 个子节点,深度可达 5 层,因此总共可创建 3125 个节点的网络。每个节点必须用一个 15 位地址定义,该地址精确描述了节点在树中的位置。

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

我们可以用八进制格式定义节点地址。基站/主节点地址为 00,基站子节点地址为 01~05,节点 01 的子节点地址为 011~051,以此类推。

注意:若节点 011 要与节点 02 通信,通信必须经过节点 01 和基站节点 00,因此这两个节点必须始终保持活跃,通信才能成功。

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

基于 RF24Network 库的 Arduino 无线舵机控制

在讲解本教程的主要示例前,为更好理解库的工作原理,我们先用两块 Arduino 板通信做一个更简单的示例。以下是该示例的电路图。

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

你可以从以下链接获取本教程所需组件:

我们将使用第一块 Arduino 上的电位器控制第二块 Arduino 上的舵机。现在来看源代码。

电位器端代码(节点 00)

/* Arduino 无线网络 - 多 NRF24L01 教程 == 示例 01 - 舵机控制 / 节点 00 - 电位器 == by Dejan, www.HowToMechatronics.com
Libraries: nRF24/RF24, https://github.com/nRF24/RF24
nRF24/RF24Network, https://github.com/nRF24/RF24Network */
#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>
RF24 radio(10, 9); // nRF24L01 (CE,CSN)
RF24Network network(radio); // 将 radio 加入网络
const uint16_t this_node = 00; // 八进制格式的节点地址
const uint16_t node01 = 01;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node); // (信道, 节点地址)
}
void loop() {
  network.update();
  unsigned long potValue = analogRead(A0); // 读取电位器值
  unsigned long angleValue = map(potValue, 0, 1023, 0, 180); // 转换为 0-180 适合舵机
  RF24NetworkHeader header(node01); // 目标节点地址
  bool ok = network.write(header, &angleValue, sizeof(angleValue)); // 发送数据
}

首先需包含 RF24、RF24Network 和 SPI 库。创建 RF24 对象并将其加入 RF24Network 对象。用八进制定义节点地址:本节点 00,舵机端节点 01。setup 中初始化网络,设置信道和本节点地址。loop 中不断调用 update() 处理网络动作,读取电位器并映射为 0-180,创建网络头指定目标地址,最后用 write() 发送数据。

舵机端代码(节点 01)

/* Arduino 无线网络 - 多 NRF24L01 教程 == 示例 01 - 舵机控制 / 节点 01 - 舵机 == */
#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>
#include <Servo.h>
RF24 radio(10, 9);
RF24Network network(radio);
const uint16_t this_node = 01;
Servo myservo;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node);
  myservo.attach(3); // 舵机引脚
}
void loop() {
  network.update();
  while ( network.available() ) {
    RF24NetworkHeader header;
    unsigned long incomingData;
    network.read(header, &incomingData, sizeof(incomingData));
    myservo.write(incomingData);
  }
}

舵机端同样定义库和对象,地址为 01。loop 中用 while 循环和 available() 检查是否有数据到达,若有则创建头对象和变量存储数据,用 read() 读取并存入 incomingData,最后用该数据驱动舵机转动。

多 NRF24L01 模块的 Arduino 无线网络

理解上述示例后,我们进入本教程主示例:构建 5 块 Arduino 互通的无线网络。以下是示例框图。

使用 NRF24L01 模块构建强健的 Arduino 无线 Mesh 网络

从基站出发:电位器控制节点 01 的舵机,第二电位器控制节点 022 的 LED,按钮控制节点 012 的 LED,基站的 LED 由节点 02 的电位器控制;节点 012 的红外传感器控制节点 01 的 LED。这展示了如何同时收发数据,以及如何跨分支通信。下面看各节点代码。

基站 00 源代码

/* Arduino 无线网络 - 多 NRF24L01 教程 == 基站/主节点 00 == by Dejan, www.HowToMechatronics.com
Libraries: nRF24/RF24, https://github.com/nRF24/RF24
nRF24/RF24Network, https://github.com/nRF24/RF24Network */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#define button 2
#define led 3
RF24 radio(10, 9);
RF24Network network(radio);
const uint16_t this_node = 00;
const uint16_t node01 = 01;
const uint16_t node012 = 012;
const uint16_t node022 = 022;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node);
  radio.setDataRate(RF24_2MBPS);
  pinMode(button, INPUT_PULLUP);
  pinMode(led, OUTPUT);
}
void loop() {
  network.update();
  //===== 接收 =====//
  while ( network.available() ) {
    RF24NetworkHeader header;
    unsigned long incomingData;
    network.read(header, &incomingData, sizeof(incomingData));
    analogWrite(led, incomingData); // PWM 调光
  }
  //===== 发送 =====//
  // 节点 01 舵机控制
  unsigned long potValue = analogRead(A0);
  unsigned long angleValue = map(potValue, 0, 1023, 0, 180);
  RF24NetworkHeader header2(node01);
  bool ok = network.write(header2, &angleValue, sizeof(angleValue));
  // 节点 012 LED 控制
  unsigned long buttonState = digitalRead(button);
  RF24NetworkHeader header4(node012);
  bool ok3 = network.write(header4, &buttonState, sizeof(buttonState));
  // 节点 022 LED 控制
  unsigned long pot2Value = analogRead(A1);
  RF24NetworkHeader header3(node022);
  bool ok2 = network.write(header3, &pot2Value, sizeof(pot2Value));
}

基站定义库、对象及所有将发送数据的目标节点。loop 先检查接收数据:若有则读取并用于控制 LED 亮度(数据来自节点 02 电位器)。随后发送三路数据:电位器 A0 控制节点 01 舵机,按钮控制节点 012 LED,电位器 A1 控制节点 022 LED。

节点 02 源代码

/* Arduino 无线网络 - 多 NRF24L01 教程 == 节点 02 (主节点 00 的子节点) == */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
RF24 radio(10, 9);
RF24Network network(radio);
const uint16_t this_node = 02;
const uint16_t master00 = 00;
const unsigned long interval = 10; // ms
unsigned long last_sent;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node);
  radio.setDataRate(RF24_2MBPS);
}
void loop() {
  network.update();
  //===== 发送 =====//
  unsigned long now = millis();
  if (now - last_sent >= interval) {
    last_sent = now;
    unsigned long potValue = analogRead(A0);
    unsigned long ledBrightness = map(potValue, 0, 1023, 0, 255);
    RF24NetworkHeader header(master00);
    bool ok = network.write(header, &ledBrightness, sizeof(ledBrightness));
  }
}

节点 02 每 10ms 读取电位器,映射为 0-255 PWM 值发送给基站 00。

节点 01 源代码

/* Arduino 无线网络 - 多 NRF24L01 教程 == 节点 01 (主节点 00 的子节点) == */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#include <Servo.h>
#define led 2
RF24 radio(10, 9);
RF24Network network(radio);
const uint16_t this_node = 01;
const uint16_t master00 = 00;
Servo myservo;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node);
  radio.setDataRate(RF24_2MBPS);
  myservo.attach(3);
  pinMode(led, OUTPUT);
}
void loop() {
  network.update();
  //===== 接收 =====//
  while ( network.available() ) {
    RF24NetworkHeader header;
    unsigned long incomingData;
    network.read(header, &incomingData, sizeof(incomingData));
    if (header.from_node == 0) { // 来自主节点
      myservo.write(incomingData);
    }
    if (header.from_node == 10) { // 来自节点 012 (八进制 012 = 十进制 10)
      digitalWrite(led, !incomingData);
    }
  }
}

节点 01 同时接收来自基站(舵机控制)和节点 012(LED 控制)的数据,通过 header.from_node 判断来源并分别处理。

节点 012 源代码

/* Arduino 无线网络 - 多 NRF24L01 教程 == 节点 012 (节点 01 的子节点) == */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#define led 2
#define IR 3
RF24 radio(10, 9);
RF24Network network(radio);
const uint16_t this_node = 012;
const uint16_t node01 = 01;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node);
  radio.setDataRate(RF24_2MBPS);
  pinMode(led, OUTPUT);
  pinMode(IR, INPUT);
}
void loop() {
  network.update();
  //===== 接收 =====//
  while ( network.available() ) {
    RF24NetworkHeader header;
    unsigned long buttonState;
    network.read(header, &buttonState, sizeof(buttonState));
    digitalWrite(led, !buttonState);
  }
  //===== 发送 =====//
  unsigned long irV = digitalRead(IR);
  RF24NetworkHeader header8(node01);
  bool ok = network.write(header8, &irV, sizeof(irV));
}

节点 012 既接收基站按钮数据控制本地 LED,又发送红外传感器数据给节点 01 控制其 LED。

节点 022 源代码

/* Arduino 无线网络 - 多 NRF24L01 教程 == 节点 022 (节点 02 的子节点) == */
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#define led1 2
#define led2 3
#define led3 4
#define led4 5
RF24 radio(10, 9);
RF24Network network(radio);
const uint16_t this_node = 022;
const uint16_t master00 = 00;
void setup() {
  SPI.begin();
  radio.begin();
  network.begin(90, this_node);
  radio.setDataRate(RF24_2MBPS);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
}
void loop() {
  network.update();
  //===== 接收 =====//
  while ( network.available() ) {
    RF24NetworkHeader header;
    unsigned long potValue;
    network.read(header, &potValue, sizeof(potValue));
    // 根据电位器值点亮 LED
    if (potValue > 240) digitalWrite(led1, HIGH); else digitalWrite(led1, LOW);
    if (potValue > 480) digitalWrite(led2, HIGH); else digitalWrite(led2, LOW);
    if (potValue > 720) digitalWrite(led3, HIGH); else digitalWrite(led3, LOW);
    if (potValue > 960) digitalWrite(led4, HIGH); else digitalWrite(led4, LOW);
  }
}

节点 022 接收基站第二电位器数据,根据阈值控制 4 个 LED 亮灭。

总结:若硬件连接正确且所有节点保持活跃,我们只需精确寻址节点,所有繁重的网络路由工作都由强大的 RF24Network 库自动完成。

希望你喜欢这个 Arduino 项目并学到了新知识。欢迎在评论区提问。

制造工艺

  1. 打造低成本家庭无线传感器网络:Arduino + 树莓派 + Xively 物联网平台
  2. 树莓派手写数字识别:TensorFlow 与 OpenCV 实战部署
  3. 基于 Infineon 3D 磁传感器的 Arduino 无线磁通讯实验
  4. K30 CO₂ 传感器:室内空气质量实时监测
  5. 基于 1Sheeld 与 Arduino 的盲聋人士沟通辅助系统
  6. 智能存钱罐:Arduino Nano 控制硬币识别器实现余额显示
  7. Arduino + HC-05 蓝牙控制 LED:MIT App Inventor 手机 App 开发全攻略
  8. DFRobot 电容指纹传感器 (ID809) 接入 Arduino/ESP8266 完整教程
  9. USB-BLE 无线 MIDI 适配器三种方案:让乐器无线连接 iOS 设备
  10. 基于 Arduino Mega 与 Nextion 显示屏的交互式气象站
  11. Arduino Mega 驱动 Wii Nunchuk 控制 6 自由度机械臂
  12. 智能无线开关控制器:Arduino + 433MHz 远程操控墙壁开关