NRF24L01モジュールで堅牢なArduinoワイヤレスメッシュネットワークを構築する
このチュートリアルでは、複数のNRF24L01トランシーバーモジュールで構成されるArduinoワイヤレスネットワークの構築方法を学びます。以下の動画をご覧いただくか、書面によるチュートリアルをお読みください。 例として5つのノードからなるネットワークを作成しました。各ノードはネットワーク内の任意のノードと通信でき、同時に送信機と受信機の両方として動作します。この例は、より大規模なネットワークの構築方法を説明するように設計されており、正確には単一のRFチャネルで最大3125個のモジュールが相互通信可能です。仕組みを見ていきましょう。 前回のチュートリアルでは、NRF24L01モジュールとRF24ライブラリを使用して2台のArduinoボード間でワイヤレス通信を行う方法を学びました。今回はこれに加えてRF24Networkライブラリを使用し、複数のボードが相互通信するArduinoワイヤレスネットワークを簡単に構築できるようにします。ネットワークトポロジーの仕組みは以下の通りです。 1つのNRF24L01モジュールは、同時に最大6つの他のモジュールをアクティブにリスニングできます。 RF24Networkライブラリはこの能力を利用し、1つのノードをベース(親)とし、他のすべてのノードがそのノードまたは別のノードの子となるツリー型トポロジーのネットワークを生成します。各ノードは最大5つの子を持つことができ、これが5階層まで深くなるため、合計3125ノードのネットワークを作成可能です。各ノードには15ビットのアドレスを定義する必要があり、これがツリー内でのノードの位置を正確に示します。 ノードのアドレスは8進数形式で定義できます。マスター(ベース)のアドレスは「00」、ベースの子ノードは「01」〜「05」、ノード01の子ノードは「011」〜「051」というようになります。 なお、ノード011がノード02と通信する場合、通信はノード01とベースノード00を経由する必要があるため、これら2つのノードが常時アクティブでなければ通信は成立しません。 メインの例に進む前に、ライブラリの動作をより理解するために、2台のArduinoボード間のシンプルな通信例を作成します。この例の回路図は以下の通りです。 このチュートリアルに必要なコンポーネントは以下のリンクから入手できます: 最初のArduinoのポテンショメーターを使用して、2番目のArduinoのサーボモーターを制御します。ソースコードを見てみましょう。 まずRF24とRF24Networkライブラリ、SPIライブラリをインクルードします。RF24オブジェクトを作成し、それをRF24Networkオブジェクトに含めます。ノードアドレスを8進数形式で定義します(このノードは00、相手は01)。 setup()では、チャネルとこのノードのアドレスを指定してネットワークを初期化します。 loop()では、常にupdate()関数を呼び出す必要があります。これがネットワーク内のすべてのアクションを処理します。ポテンショメーターの値を読み取り、サーボ制御に適した0〜180の値に変換します。ネットワークヘッダーを作成して送信先アドレスを指定し、write()関数でデータを送信します。第1引数にアドレス情報、第2引数に送信データへのポインタ、第3引数にデータサイズを指定します。 受信側も同様にライブラリとオブジェクトを定義し、このノードのアドレスを01とします。loop()ではwhile()ループとavailable()関数で着信データを常時チェック。データがあればヘッダーを作成し、read()関数でデータを読み取ってincomingData変数に格納。このデータを使って、もう一方のノードのポテンショメーターに合わせてサーボを動かします。 この例を理解したら、メインの例に進み、5台のArduinoが相互通信するワイヤレスネットワークを構築します。ブロック図は以下の通りです。 ベースからポテンショメーターでノード01のサーボを制御し、2つ目のポテンショメーターでノード022のLEDを制御。ボタンでノード012のLEDを制御し、ベースのLEDはノード02のポテンショメーターで制御。さらにノード012の赤外線センサーでノード01のLEDを制御します。これにより、同時に送受信を行う方法や、異なるブランチのノードと通信する方法がわかります。各ノードのArduinoコードを見ていきましょう。 ベース(マスターノード)では、ライブラリとオブジェクトを定義し、マスターがデータを送信するすべてのノードを定義します。loop()ではまず着信データを常時チェック。データがあれば読み取り、LEDの明るさを制御します(このデータはノード02のポテンショメーターから来ます)。ノード02のコードを見ると、setupはほぼ同じですが、データを送信したい正しいアドレス(マスターの00)を割り当てることが重要です。ポテンショメーターの値を読み取り、0〜255のPWM値に変換してマスターに送信します。ここではmillis()関数を使って10ミリ秒間隔でデータを送信しています。 次に、マスターからポテンショメーターデータをノード01に送信してサーボを制御します。 ノード01は2つの異なるノードからデータを受信します。1つはサーボ制御用(マスターから)、もう1つはLED制御用(ノード012の赤外線センサーから)。このような場合、header.from_node属性を使ってデータがどのノードから来たかを判別します。マスターからのデータならサーボ制御に、ノード012からのデータならLED制御に使用します。 ノード012では送受信の両方を行います。赤外線センサーでノード01のLEDを制御し、このノードのLEDはマスターのボタンで制御されます。 最後に、ノード022のLEDはマスターのもう1つのポテンショメーターからのデータで制御されます。 まとめると、すべてが正しく接続され、すべてのノードが常時アクティブであれば、私たちの仕事はノードを正確にアドレッシングすることだけです。裏側の重い処理は、素晴らしいRF24Networkライブラリがすべて引き受けてくれます。 このArduinoプロジェクトをお楽しみいただけたら幸いです。ご質問はコメント欄でお気軽にお尋ねください。概要

複数のNRF24L01モジュールによる通信



RF24Networkライブラリを使用したArduinoワイヤレスサーボモーター制御

ポテンショメーター側(ノード00)のコード
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
Example 01 - Servo Control / Node 00 - Potentiometer
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); // 無線をネットワークに含める
const uint16_t this_node = 00; // このノードのアドレス(8進数形式)
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; // このノードのアドレス(8進数)
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); // サーボを指定角度に動かす
}
}複数のNRF24L01モジュールによるArduinoワイヤレスネットワーク

ベース(ノード00)のソースコード
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
Base / Master Node 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); // LEDのPWM調光(ノード02からのデータ)
}
// ===== 送信 =====
// ノード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));
}ノード02のソースコード
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
Node 02 (Child of Master node 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));
}
}ノード01のソースコード
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
Node 01 (Child of Master node 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) { // データがノード00(マスター)からの場合
myservo.write(incomingData);
}
if (header.from_node == 10) { // データがノード012からの場合(8進数の012 = 10進数の10)
digitalWrite(led, !incomingData);
}
}
}ノード012のソースコード
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
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); // マスターのボタンでLED制御
}
// ===== 送信 =====
unsigned long irV = digitalRead(IR); // 赤外線センサー読取
RF24NetworkHeader header8(node01);
bool ok = network.write(header8, &irV, sizeof(irV)); // ノード01へ送信
}ノード022のソースコード
/* Arduino Wireless Network - Multiple NRF24L01 Tutorial
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));
// ポテンショメーターの値に応じて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);
}
}
製造プロセス
- 家庭用の低コストワイヤレスセンサーネットワークを構築
- Raspberry Piで手書き数字認識:TensorFlowとOpenCVを用いたディープラーニング実装
- ArduinoとInfineon 3D磁気センサーで作る無線磁気データ転送
- K30 CO2センサで室内空気質をリアルタイム監視する
- 1SheeldとArduinoで盲ろう者のコミュニケーションを支援する
- スマート貯金箱を作ろう:Arduino Nanoでコインアクセプターを制御
- ArduinoでBluetooth経由でLEDを制御 – シンプルDIYガイド
- DFRobot静電容量式指紋センサーをArduino/ESP8266で使う – 登録・認証・削除の完全ガイド
- USB-MIDI機器をBluetooth LEでiOSに無線接続 ─ Arduinoベースの3つのアダプター設計
- Arduino MegaとNextion HMIで作る高機能ウェザーステーション
- Arduinoベースのヌンチャク操作6自由度ロボットアームキット