风筝
发表于: 2018-10-29 11:36:23 | 显示全部楼层

在本篇文章中,我们将学习如何搭建由多个NR24L01收发器模块组成的Arduino无线网络。在本示例中,我们搭建了一个由5个节点组成的网络,每个节点都可以与网络中的任何节点通信,同时它们既可以作为发送器,也可以作为接收器。实际上,该示例采用这种方式设置是解释如何搭建更大网络,或者准确地说,我们可以在单个RF信道上共有3125个模块相互通信。现在让我们来看看它是如何工作的。

Arduino-wireless-network-tutorial-768x432.jpg


在我之前的文章中,我们已经学习了如何使用NRF24L01模块和RF24库在两个Arduino开发板之间进行无线通信。现在除了这个库之外,我们还将使用RF24Network库,它可以轻松地构建一个无线网络,其中许多Arduino开发板相互通信。以下是网络拓扑的工作原理。

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

NRF24L01-can-listen-up-to-6-other-modules-at-the-same-time-768x401.png


RF24网络库利用此能力生成以树形拓扑排列的网络,其中一个节点是基础,所有其他节点是该节点或另一个节点的子节点。每个节点最多可以有5个子节点,这可以达到5级深度,这意味着我们可以创建总共3125个节点的网络。每个节点必须使用15位地址来定义,该地址精确地描述树中节点的位置。

Tree-Topology-Wireless-Netowrk.png

我们实际上可以用八进制格式定义节点的地址。因此,master或base的地址为00,base子地址为01~05,01节点子地址为011~051,依此类推。

注意,如果节点011想要与节点02通信,则通信将必须通过节点01和基节点00,因此这两个节点必须始终是活动的,以便通信成功。

Arduino-Wireless-Netowrk-NRF24L01-Modules-Communication-Channel.png


使用RF24Network库的Arduino无线伺服电机控制

在我们开始本文的的主要示例之前,为了更好地理解库的工作方式,让我们举两个Arduinos相互通信的简单示例。这是此示例的电路图。

Arduino-Wireless-Servo-Motor-Control-Circuit-Diagram.png.png


我们在使用第一个Arduino开发板上的电位计来控制第二个Arduino上的的伺服电机。现在来看看源代码。

以下是电位器侧的代码:

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3. == Example 01 - Servo Control / Node 00 - Potentiometer ==
  4.   by Dejan, www.HowToMechatronics.com
  5.   Libraries:
  6.   nRF24/RF24, https://github.com/nRF24/RF24
  7.   nRF24/RF24Network, https://github.com/nRF24/RF24Network
  8. */
  9. #include <RF24.h>
  10. #include <RF24Network.h>
  11. #include <SPI.h>
  12. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  13. RF24Network network(radio);      // Include the radio in the network
  14. const uint16_t this_node = 00;   // Address of this node in Octal format ( 04,031, etc)
  15. const uint16_t node01 = 01;      
  16. void setup() {
  17.   SPI.begin();
  18.   radio.begin();
  19.   network.begin(90, this_node);  //(channel, node address)
  20. }
  21. void loop() {
  22.   network.update();
  23.   unsigned long potValue = analogRead(A0);  // Read the potentiometer value
  24.   unsigned long angleValue = map(potValue, 0, 1023, 0, 180); // Convert the value to 0-180
  25.   RF24NetworkHeader header(node01);     // (Address where the data is going)
  26.   bool ok = network.write(header, &angleValue, sizeof(angleValue)); // Send the data
  27. }
复制代码

首先,我们需要包括RF24和RF24Network库以及SPI库。然后我们需要创建RF24对象,并将其包含在RF24Network对象中。这里我们需要以八进制格式定义节点的地址,也就是,为此节点定义00,为伺服侧的另一个节点定义01。

setup()函数中,我们需要通过设置此节点的通道和地址来初始化网络。

loop()函数中,我们需要经常调用update()函数,通过该函数发生网络中的所有操作。然后我们读取电位计的值并将其转换为0到180的值,这适用于伺服控制。然后我们创建一个网络数据头,我们在其中分配数据所在节点的地址。最后,使用write()函数将数据发送到另一个节点。这里第一个参数包含地址信息,第二个参数包含将被发送的数据,第三个参数是数据的大小。


以下是伺服电机端的代码:

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3.   == Example 01 - Servo Control / Node 01 - Servo motor ==
  4. */
  5. #include <RF24.h>
  6. #include <RF24Network.h>
  7. #include <SPI.h>
  8. #include <Servo.h>
  9. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  10. RF24Network network(radio);      // Include the radio in the network
  11. const uint16_t this_node = 01;   // Address of our node in Octal format ( 04,031, etc)
  12. Servo myservo;  // create servo object to control a servo
  13. void setup() {
  14.   SPI.begin();
  15.   radio.begin();
  16.   network.begin(90, this_node); //(channel, node address)
  17.   myservo.attach(3);   // (servo pin)
  18. }
  19. void loop() {
  20.   network.update();
  21.   while ( network.available() ) {     // Is there any incoming data?
  22.     RF24NetworkHeader header;
  23.     unsigned long incomingData;
  24.     network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data
  25.     myservo.write(incomingData);  // tell servo to go to a particular angle
  26.   }
  27. }
复制代码

在另一侧伺服电机上,我们需要以与前面所述相同的方式定义库和对象。 这里八进制格式的节点地址为01。定义伺服电机地址后,在loop()函数中,使用while()循环和available()函数,我们不断检查是否有数据输入。 如果为true,我们将创建一个网络数据头,通过该数据头接收数据,以及创建一个存储数据的变量。 然后使用read()函数读取数据,并将其存储到incomingData变量中。 最后,我们使用这些数据根据另一个节点的电位器移动伺服电机。

跳转到指定楼层
风筝
发表于: 2018-10-29 14:08:25 | 显示全部楼层

使用多个NRF24L01模块的Arduino无线网络

在理解了上个示例之后,我们可以继续学习本篇文章的主要示例,然后搭建一个由5个Arduino开发板相互通信的无线网络。 以下是该示例的框图。

Arduino-Wireless-Network-with-Multiple-NRF24L01-Modules.png


因此,从基本节点开始,我们将使用电位器控制节点01处的伺服电机,使用第二个电位器,我们将控制节点022处的LED,使用按钮我们将控制节点012处的LED,基本节点的LED将使用节点02处的电位器进行控制。同样使用节点012处的红外传感器,我们将控制节点01处的LED。因此我们可以注意到该示例解释了如何同时发送和接收数据, 以及如何与来自不同分支的节点通信。 我们现在来看看Arduino代码。


基本节点00的代码

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3.           == Base/ Master Node 00==
  4.   by Dejan, www.HowToMechatronics.com
  5.   Libraries:
  6.   nRF24/RF24, https://github.com/nRF24/RF24
  7.   nRF24/RF24Network, https://github.com/nRF24/RF24Network
  8. */
  9. #include <RF24Network.h>
  10. #include <RF24.h>
  11. #include <SPI.h>
  12. #define button 2
  13. #define led 3
  14. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  15. RF24Network network(radio);      // Include the radio in the network
  16. const uint16_t this_node = 00;   // Address of this node in Octal format ( 04,031, etc)
  17. const uint16_t node01 = 01;      // Address of the other node in Octal format
  18. const uint16_t node012 = 012;
  19. const uint16_t node022 = 022;
  20. void setup() {
  21.   SPI.begin();
  22.   radio.begin();
  23.   network.begin(90, this_node);  //(channel, node address)
  24.   radio.setDataRate(RF24_2MBPS);
  25.   pinMode(button, INPUT_PULLUP);
  26.   pinMode(led, OUTPUT);
  27. }
  28. void loop() {
  29.   network.update();
  30.   //===== Receiving =====//
  31.   while ( network.available() ) {     // Is there any incoming data?
  32.     RF24NetworkHeader header;
  33.     unsigned long incomingData;
  34.     network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data
  35.     analogWrite(led, incomingData);    // PWM output to LED 01 (dimming)
  36.   }
  37.   //===== Sending =====//
  38.   // Servo control at Node 01
  39.   unsigned long potValue = analogRead(A0);
  40.   unsigned long angleValue = map(potValue, 0, 1023, 0, 180); // Suitable for servo control
  41.   RF24NetworkHeader header2(node01);     // (Address where the data is going)
  42.   bool ok = network.write(header2, &angleValue, sizeof(angleValue)); // Send the data
  43.   // LED Control at Node 012
  44.   unsigned long buttonState = digitalRead(button);
  45.   RF24NetworkHeader header4(node012);    // (Address where the data is going)
  46.   bool ok3 = network.write(header4, &buttonState, sizeof(buttonState)); // Send the data
  47.   // LEDs control at Node 022
  48.   unsigned long pot2Value = analogRead(A1);
  49.   RF24NetworkHeader header3(node022);    // (Address where the data is going)
  50.   bool ok2 = network.write(header3, &pot2Value, sizeof(pot2Value)); // Send the data
  51. }
复制代码

因此,在基本节点或主节点,我们需要如前所述定义库和对象,并定义主节点将向其发送数据的所有其他节点。 在loop()函数部分,我们首先不断检查是否有数据传入。 如果有,我们读取数据,将其存储到incomingData变量中,然后使用它来控制LED亮度。 这些数据实际上来自节点02的电位器。如果我们看看它的代码,我们可以注意到设置几乎是一样的。 重要的是将正确的地址分配给我们想要发送数据的位置。 本例中是主地址00。所以在读取电位器值并将其转换为0到255的合适PWM值后,我们将这些数据发送给主机。 我们在这里可以注意到我使用millis()函数以10毫秒的间隔发送数据。


节点02的代码

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3.         == Node 02 (Child of Master node 00) ==   
  4. */
  5. #include <RF24Network.h>
  6. #include <RF24.h>
  7. #include <SPI.h>
  8. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  9. RF24Network network(radio);      // Include the radio in the network
  10. const uint16_t this_node = 02;   // Address of our node in Octal format ( 04,031, etc)
  11. const uint16_t master00 = 00;    // Address of the other node in Octal format
  12. const unsigned long interval = 10;  //ms  // How often to send data to the other unit
  13. unsigned long last_sent;            // When did we last send?
  14. void setup() {
  15.   SPI.begin();
  16.   radio.begin();
  17.   network.begin(90, this_node);  //(channel, node address)
  18.   radio.setDataRate(RF24_2MBPS);
  19. }
  20. void loop() {
  21.   network.update();
  22.   //===== Sending =====//
  23.   unsigned long now = millis();
  24.   if (now - last_sent >= interval) {   // If it's time to send a data, send it!
  25.     last_sent = now;
  26.     unsigned long potValue = analogRead(A0);
  27.     unsigned long ledBrightness = map(potValue, 0, 1023, 0, 255);
  28.     RF24NetworkHeader header(master00);   // (Address where the data is going)
  29.     bool ok = network.write(header, &ledBrightness, sizeof(ledBrightness)); // Send the data
  30.   }
  31. }
复制代码

接下来,我们从主机发送电位器数据到节点01,以控制伺服电机。


节点01的代码

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3.         == Node 02 (Child of Master node 00) ==
  4. */
  5. #include <RF24Network.h>
  6. #include <RF24.h>
  7. #include <SPI.h>
  8. #include <Servo.h>
  9. #define led 2
  10. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  11. RF24Network network(radio);      // Include the radio in the network
  12. const uint16_t this_node = 01;   // Address of our node in Octal format ( 04,031, etc)
  13. const uint16_t master00 = 00;    // Address of the other node in Octal format
  14. Servo myservo;  // create servo object to control a servo
  15. void setup() {
  16.   SPI.begin();
  17.   radio.begin();
  18.   network.begin(90, this_node); //(channel, node address)
  19.   radio.setDataRate(RF24_2MBPS);
  20.   myservo.attach(3);   // (servo pin)
  21.   pinMode(led, OUTPUT);
  22. }
  23. void loop() {
  24.   network.update();
  25.   //===== Receiving =====//
  26.   while ( network.available() ) {     // Is there any incoming data?
  27.     RF24NetworkHeader header;
  28.     unsigned long incomingData;
  29.     network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data
  30.     if (header.from_node == 0) {    // If data comes from Node 02
  31.       myservo.write(incomingData);  // tell servo to go to a particular angle
  32.     }
  33.     if (header.from_node == 10) {    // If data comes from Node 012
  34.       digitalWrite(led, !incomingData);  // Turn on or off the LED 02
  35.     }
  36.   }
  37. }
复制代码

节点01实际上是从两个不同的节点接收数据,一个用于伺服控制,另一个用于来自节点012的红外传感器的LED控制。


节点012的代码

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3.             == Node 012 (child of Node 02)==   
  4. */
  5. #include <RF24Network.h>
  6. #include <RF24.h>
  7. #include <SPI.h>
  8. #define led 2
  9. #define IR 3
  10. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  11. RF24Network network(radio);      // Include the radio in the network
  12. const uint16_t this_node = 012;  // Address of our node in Octal format ( 04,031, etc)
  13. const uint16_t node01 = 01;    // Address of the other node in Octal format
  14. void setup() {
  15.   SPI.begin();
  16.   radio.begin();
  17.   network.begin(90, this_node);  //(channel, node address)
  18.   radio.setDataRate(RF24_2MBPS);
  19.   pinMode(led, OUTPUT);
  20.   pinMode(IR, INPUT);
  21. }
  22. void loop() {
  23.   network.update();
  24.   //===== Receiving =====//
  25.   while ( network.available() ) {     // Is there any incoming data?
  26.     RF24NetworkHeader header;
  27.     unsigned long buttonState;
  28.     network.read(header, &buttonState, sizeof(buttonState)); // Read the incoming data
  29.     digitalWrite(led, !buttonState); // Turn on or off the LED
  30.   }
  31.   //===== Sending =====//
  32.   unsigned long irV = digitalRead(IR); // Read IR sensor
  33.   RF24NetworkHeader header8(node01);
  34.   bool ok = network.write(header8, &irV, sizeof(irV)); // Send the data
  35. }
复制代码

在本段代码中,我们使用header.from_node属性来获取数据来自哪个节点的信息。 如果输入数据来自主设备,我们用它来控制伺服,如果输入数据来自节点012,我们用它来控制LED。

在节点012,我们有发送和接收。 红外传感器控制节点01处的前面提到的LED,这里的LED是来自主机上的按钮的控制。


节点022的代码

  1. /*
  2.   Arduino Wireless Network - Multiple NRF24L01 Tutorial
  3.             == Node 022 (child of Node 02)==   
  4. */
  5. #include <RF24Network.h>
  6. #include <RF24.h>
  7. #include <SPI.h>
  8. #define led1 2
  9. #define led2 3
  10. #define led3 4
  11. #define led4 5
  12. RF24 radio(10, 9);               // nRF24L01 (CE,CSN)
  13. RF24Network network(radio);      // Include the radio in the network
  14. const uint16_t this_node = 022;  // Address of our node in Octal format ( 04,031, etc)
  15. const uint16_t master00 = 00;    // Address of the other node in Octal format
  16. void setup() {
  17.   SPI.begin();
  18.   radio.begin();
  19.   network.begin(90, this_node);  //(channel, node address)
  20.   radio.setDataRate(RF24_2MBPS);
  21.   pinMode(led1, OUTPUT);
  22.   pinMode(led2, OUTPUT);
  23.   pinMode(led3, OUTPUT);
  24.   pinMode(led4, OUTPUT);
  25. }
  26. void loop() {
  27.   network.update();
  28.   //===== Receiving =====//
  29.   while ( network.available() ) {     // Is there any incoming data?
  30.     RF24NetworkHeader header;
  31.     unsigned long potValue;
  32.     network.read(header, &potValue, sizeof(potValue)); // Read the incoming data
  33.     // Turn on the LEDs as depending on the incoming value from the potentiometer
  34.     if (potValue > 240) {
  35.       digitalWrite(led1, HIGH);
  36.     } else {
  37.       digitalWrite(led1, LOW);
  38.     }
  39.     if (potValue > 480) {
  40.       digitalWrite(led2, HIGH);
  41.     } else {
  42.       digitalWrite(led2, LOW);
  43.     }
  44.     if (potValue > 720) {
  45.       digitalWrite(led3, HIGH);
  46.     } else {
  47.       digitalWrite(led3, LOW);
  48.     }
  49.     if (potValue > 960) {
  50.       digitalWrite(led4, HIGH);
  51.     } else {
  52.       digitalWrite(led4, LOW);
  53.     }
  54.   }
  55. }
复制代码

最后,使用来自主机上的另一个电位器的数据来控制节点022处的LED。


因此,总而言之,如果一切正常连接,并且所有节点始终处于活动状态,通过精确寻址节点就可以完成我们的工作,所有繁重的工作都由强大的RF24Network库执行。


以上就是本篇文章的全部内容,希望您能喜欢这篇Arduino文章,并能学到一些新东西。 如果遇到任何问题,请随时在下面进行回复。

回复

使用道具 举报

Sunyang
发表于: 2019-9-29 14:29:29 | 显示全部楼层

您好,非常感谢您的资料。有一个地方不明白,在节点01程序里面要接收00和012的数据分别控制舵机与LED02灯,有一个条件if(header.from_node==10)这个是接收012的数据么?加入01处要接收013的数据应该写if(header.from_node==?)"?"号处填什么啊?另外还有怎么确定接收哪个节点发出的数据?感谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 705 | 回复: 1492



手机版|

GMT+8, 2024-12-4 01:26 , Processed in 0.044241 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表