Создание надежной беспроводной Mesh-сети на Arduino с модулями NRF24L01
Обзор
В этом уроке мы научимся создавать беспроводную сеть на Arduino, состоящую из нескольких трансиверов NRF24L01. В качестве примера собрана сеть из 5 узлов, каждый из которых может обмениваться данными с любым другим узлом и одновременно работать как передатчик, так и приёмник. Эта схема масштабируется до 3125 модулей на одном RF-канале. Рассмотрим, как это работает.

В предыдущих уроках мы уже изучали точечную связь между двумя Arduino с помощью библиотеки RF24. Теперь добавим библиотеку RF24Network, которая упрощает построение сети с множеством плат. Сетевая топология имеет древовидную структуру: один узел — базовый (master), остальные — дочерние. Каждый узел может иметь до 5 детей, глубина дерева — 5 уровней, итого максимум 3125 узлов. Адрес каждого узла — 15-битное число в восьмеричном формате, точно описывающее его положение в дереве.


Адреса задаются в восьмеричном формате: базовый узел — 00, его дети — 01–05, дети узла 01 — 011–051 и так далее. Важно: если узел 011 хочет передать данные узлу 02, пакет пройдёт через узлы 01 и 00, поэтому промежуточные узлы должны быть постоянно активны.

Простой пример: управление сервоприводом по беспроводной сети
Для понимания работы библиотеки начнём с двух узлов: потенциометр на узле 00 управляет сервоприводом на узле 01.

Код узла 00 (потенциометр)
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
Example 01 - Servo Control / Node 00 - Potentiometer
by Dejan, www.HowToMechatronics.com
Libraries: nRF24/RF24, nRF24/RF24Network */
#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>
RF24 radio(10, 9); // CE, CSN
RF24Network network(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)); // Отправка
}
Код узла 01 (сервопривод)
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
Example 01 - Servo Control / Node 01 - Servo motor */
#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); // Поворачиваем серву
}
}
Разбор: В setup() инициализируем сеть (канал 90, адрес узла). В loop() вызываем network.update() — это сердце библиотеки, обрабатывающее маршрутизацию. Отправка: создаём заголовок RF24NetworkHeader с адресом получателя и вызываем network.write(). Приём: проверяем network.available(), читаем network.read().
Основной пример: сеть из 5 узлов
Теперь построим сеть из 5 Arduino, где базовый узел управляет периферией, а периферия передаёт данные обратно и между собой.

Сценарий:
- Потенциометр на базовом узле (00) → сервопривод на узле 01.
- Второй потенциометр на базовом узле → 4 светодиода на узле 022.
- Кнопка на базовом узле → светодиод на узле 012.
- Потенциометр на узле 02 → светодиод на базовом узле (ШИМ).
- ИК-датчик на узле 012 → светодиод на узле 01.
Код базового узла 00
/* Base / Master Node 00 */
#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); // Яркость от потенциометра узла 02
}
// === Передача ===
// Сервопривод на узле 01
unsigned long potValue = analogRead(A0);
unsigned long angleValue = map(potValue, 0, 1023, 0, 180);
RF24NetworkHeader header2(node01);
network.write(header2, &angleValue, sizeof(angleValue));
// Кнопка → узел 012
unsigned long buttonState = digitalRead(button);
RF24NetworkHeader header4(node012);
network.write(header4, &buttonState, sizeof(buttonState));
// Второй потенциометр → узел 022
unsigned long pot2Value = analogRead(A1);
RF24NetworkHeader header3(node022);
network.write(header3, &pot2Value, sizeof(pot2Value));
}
Код узла 02 (потенциометр → базовый узел)
/* Node 02 (Child of Master 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; // мс
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);
network.write(header, &ledBrightness, sizeof(ledBrightness));
}
}
Код узла 01 (сервопривод + светодиод от узла 012)
/* Node 01 (Child of Master 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 == 012) { // От узла 012 → светодиод
digitalWrite(led, !incomingData);
}
}
}
Здесь используется header.from_node для определения отправителя.
Код узла 012 (ИК-датчик → узел 01, кнопка от базы → свой светодиод)
/* Node 012 (child of Node 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);
}
// Передача ИК-данных на узел 01
unsigned long irV = digitalRead(IR);
RF24NetworkHeader header8(node01);
network.write(header8, &irV, sizeof(irV));
}
Код узла 022 (4 светодиода от потенциометра базы)
/* Node 022 (child of Node 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));
// Пороговое включение светодиодов
digitalWrite(led1, potValue > 240);
digitalWrite(led2, potValue > 480);
digitalWrite(led3, potValue > 720);
digitalWrite(led4, potValue > 960);
}
}
Заключение
Если все узлы подключены правильно и остаются активными, задача сводится к точной адресации — всю сложную работу по маршрутизации и повторной передаче берет на себя библиотека RF24Network. Это мощный инструмент для создания масштабируемых беспроводных сетей на Arduino.
Производственный процесс
- Построение доступной беспроводной сети датчиков для дома
- Распознавание рукописных цифр на Raspberry Pi с TensorFlow и OpenCV
- Беспроводная передача данных по магнитному полю на Arduino с 3D-сенсором Infineon
- Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
- Устройство для общения глухосліпых людей с помощью 1Sheeld и Arduino
- Умная копилка: управление монетоприёмником на Arduino Nano
- Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
- Интеграция ёмкостного сканера отпечатков DFRobot с Arduino или ESP8266
- USB-BLE MIDI-адаптеры на Arduino: беспроводное подключение инструментов к iOS
- Интерактивный HMI-проект на Nextion с Arduino Mega и датчиками