Взаимодействие nRF24L01 с Arduino: удаленное управление серводвигателем

Добавлено 31 декабря 2019 в 04:46

В то время как интернет вещей (IoT), межмашинное общение и тому подобное становятся всё более популярными, потребность в беспроводной связи становится всё более востребованной, и всё больше машин/устройств общаются друг с другом в облаке. Разработчики используют множество систем беспроводной связи, таких как Bluetooth Low Energy (BLE 4.0), Zigbee, ESP43 Wi-Fi модули, RF модули 433 МГц, Lora, nRF и т.д., и выбор посредника зависит от типа приложения, в котором она используется.

Одним из популярных беспроводных посредников для локальной сети является nRF24L01. Эти модули работают на частоте 2,4 ГГц (диапазон ISM) со скоростью передачи данных от 250 кбит/с до 2 Мбит/с, что является легальным во многих странах и может использоваться в промышленных и медицинских приложениях. Также утверждается, что при наличии соответствующих антенн эти модули могут передавать и принимать сигналы на расстоянии до 100 метров между ними. Интересно! Итак, в этом уроке мы узнаем больше об этих модулях nRF24L01 и о том, как связать их микроконтроллерной платформой, такой как Arduino. Мы также поделимся некоторыми решениями для часто возникающих проблем при использовании этого модуля.

Взаимодействие nRF24L01 с Arduino: удаленное управление серводвигателем
Взаимодействие nRF24L01 с Arduino: удаленное управление серводвигателем

Знакомство с RF модулем nRF24L01

Модули nRF24L01 являются приемопередающими модулями, то есть каждый модуль может отправлять и принимать данные, но поскольку они полудуплексные, в какой-либо момент времени они могут либо передавать, либо принимать данные. Модуль содержит микросхему nRF24L01 от Nordic semiconductors, которая отвечает за передачу и прием данных. Микросхема обменивается данным с помощью интерфейса SPI и, следовательно, может легко взаимодействовать с любыми микроконтроллерами. С Arduino всё становится намного проще, так как для нее доступны библиотеки. Распиновка стандартного модуля nRF24L01 показана ниже.

Распиновка модуля nRF24L01
Распиновка модуля nRF24L01

Рабочее напряжение модуля составляет от 1,9 В до 3,6 В (как правило, 3,3 В). Модуль потребляет очень маленький ток, составляющий всего 12 мА при нормальной работе, что делает его эффективным при использовании с аккумуляторами, и, следовательно, он может работать даже от элементов питания размером с монету. Несмотря на то, что рабочее напряжение составляет 3,3 В, большинство выводов толерантны к 5 В и, следовательно, могут напрямую подключаться к 5-вольтовым микроконтроллерам, таким как Arduino. Еще одним преимуществом использования этих модулей является то, что каждый модуль имеет 6 каналов связи (pipeline). Это означает, что каждый модуль может связываться с 6 другими модулями для передачи и приема данных. Это делает данный модуль пригодным для создания сетей с топологиями «звезда» и «ячеистая» в приложениях IoT. Кроме того, они имеют широкий диапазон адресов из 125 уникальных идентификаторов, поэтому в закрытом пространстве мы можем использовать 125 таких модулей, не мешающих друг другу.

Взаимодействие nRF24L01 с Arduino

В этом руководстве мы узнаем, как связать nRF24L01 с Arduino, управляя серводвигателем, подключенным к одной плате Arduino, путем изменения потенциометра, подключенного к другой плате Arduino. Для простоты мы использовали один модуль nRF24L01 в качестве передатчика и один в качестве приемника, но каждый модуль может быть отдельно запрограммирован для передачи и приема данных.

Принципиальная схема подключения модуля nRF24L01 к Arduino приведена ниже. Для разнообразия я использовал UNO для приемной части и Nano для предающей части. Но для других плат Arduino, таких как Mini и Mega, логика подключения остается неизменной.

Приемная часть: подключение модуля nRF24L01 к Arduino Uno

Приемная часть: подключение модуля nRF24L01  Arduino Uno. Схема соединений
Приемная часть: подключение модуля nRF24L01 Arduino Uno. Схема соединений
Приемная часть: подключение модуля nRF24L01  Arduino Uno. Собранный макет
Приемная часть: подключение модуля nRF24L01 Arduino Uno. Собранный макет

Как было сказано ранее, nRF24L01 взаимодействует с помощью интерфейса SPI. Для связи через SPI на Arduino Nano и UNO используются выводы 11, 12 и 13. Следовательно, мы подключаем выводы MOSI, MISO и SCK от nRF к выводам 11, 12 и 13 соответственно. Выводы CE и CS настраиваются пользователем, здесь я использовал выводы 7 и 8, но вы можете использовать любые выводы, изменив программу. Модуль nRF питается от вывода 3,3V на Arduino, что в большинстве случаев работать будет. Если нет, то можно попробовать отдельный источник питания. Помимо интерфейса nRF, я также подключил серводвигатель к выводу 7 и запитал его через вывод 5V на Arduino. Аналогично схема передатчика показана ниже.

Передающая часть: подключение модуля nRF24L01 к Arduino Nano

Передающая часть: подключение модуля nRF24L01  Arduino Nano. Схема соединений
Передающая часть: подключение модуля nRF24L01 Arduino Nano. Схема соединений
Передающая часть: подключение модуля nRF24L01  Arduino Nano. Собранный макет
Передающая часть: подключение модуля nRF24L01 Arduino Nano. Собранный макет

Соединения для передатчика точно такие же; кроме того, я использовал потенциометр, подключенный через выводы 5V и GND к Arduino. Выходное аналоговое напряжение, которое изменяется от 0 до 5 вольт, подается на вывод A7 Arduino Nano. Обе платы питаются через порт USB.

Работа с беспроводным приемопередающим модулем nRF24L01+

Однако для того, чтобы наш nRF24L01 работал без проблем, мы могли бы рассмотреть следующие вещи. Я долгое время работал с этим nRF24L01+ и изучил следующие моменты, которые могут помочь вам избежать препятствий. Вы можете попробовать это, когда модули не работают в нормальном режиме.

  1. Большинство модулей nRF24L01+ на рынке являются поддельными. Самые дешевые, которые мы можем найти на Ebay и Amazon, являются худшими (не волнуйтесь, с помощью нескольких ухищрений мы можем заставить их работать).
  2. Основная проблема – источник питания, а не ваш код. Большинство примеров кода в интернете работают правильно.
  3. Обратите внимание, что модули, которые промаркированы как NRF24L01+, на самом деле это Si24Ri (да, это китайский продукт).
  4. Клоны и поддельные модули будут потреблять больше энергии, поэтому разрабатывайте свою схему питания не на основе технического описания nRF24L01+, поскольку Si24Ri будет иметь высокое потребление тока, около 250 мА.
  5. Остерегайтесь пульсаций напряжения и скачков тока, эти модули очень чувствительны и могут легко выйти из строя (я пока поджарил 2 модуля).
  6. Добавление пары конденсаторов (10 мкФ и 0,1 мкФ) между Vcc и Gnd модуля помогает очистить питание, и это работает с большинством модулей.

Тем не менее, если у вас есть проблемы, напишите в комментариях.

Программирование nRF24L01 для Arduino

Использовать эти модули с Arduino очень просто благодаря доступной готовой библиотеке, созданной maniacbug на GitHub. Нажмите на ссылку, чтобы загрузить библиотеку в виде zip-каталога, и добавьте её в Arduino IDE с помощью Скетч (Sketch) → Подключить библиотеку (Include Library) → Добавить ZIP библиотеку (Add .ZIP library). После добавления библиотеки мы можем начать программирование для проекта. Мы должны написать две программы, одна для передающей части, а другая для приемной части. Однако, как я уже говорил ранее, каждый модуль может работать как и передатчик, и приемник. Обе программы приведены в конце страницы, в коде передатчика будет закомментирован код приемника, а в программе приемника будет закомментирован код передатчика. Вы можете использовать его, если хотите, чтобы в вашем проекте модуль работал в обоих режимах. Работа программы описана ниже.

Как и во всех программах, мы начинаем с включения заголовочных файлов. Поскольку nRF использует протокол SPI, мы включили заголовочный файл SPI, а также библиотеку, которую только что загрузили. Библиотека servo используется для управления серводвигателем.

#include <SPI.h> 
#include "RF24.h"
#include <Servo.h>

Далее идет важная строка, в которой мы указываем выводы CE и CS. На нашей принципиальной схеме CE подключен к выводу 7, а CS – к выводу 8.

RF24 myRadio (7, 8);

Все переменные, которые связаны с библиотекой RF, должны быть объявлены как составная структура. В данной программе переменная msg используется для отправки и получения данных от RF модуля.

struct package
{
  int msg;
};
typedef struct package Package;
Package data;

Каждый RF модуль имеет уникальный адрес, используя который можно отправлять данные на соответствующее устройство. Поскольку у нас здесь только одна пара, мы устанавливаем адрес, равный нулю, как на передатчике, так и приемнике, но если у вас несколько модулей, вы можете установить ID на любую уникальную строку, состоящую из шести цифр.

byte addresses[][6] = {"0"};

Затем внутри функции void setup() мы инициализируем RF модуль и настраиваем его на работу в диапазоне 115, который свободен от шума, а также настраиваем модуль для работы в режиме минимального энергопотребления с минимальной скоростью 250 кбит/с.

void setup()
{
  Serial.begin(9600);
  myRadio.begin();
  myRadio.setChannel(115);               // диапазон 115 выше WiFi сигналов
  myRadio.setPALevel(RF24_PA_MIN);       // минимальная выходная мощность
  myRadio.setDataRate( RF24_250KBPS ) ;  // минимальная скорость
  myservo.attach(6);

  Serial.print("Setup Initialized");
  delay(500);
}

Функция void WriteData() записывает переданные ей данные. Как говорилось ранее, nRF имеет 6 различных каналов, в которые мы можем записывать и считывать данные, здесь мы использовали 0xF0F0F0F066 в качестве адреса для записи данных. В приемной части для получения данных мы должны использовать тот же адрес в функции ReadData().

void WriteData()
{
  myRadio.stopListening();              // Остановить прием и начать передачу
  myRadio.openWritingPipe(0xF0F0F0F066);// Отправить данные на этот 40-разрядный адрес
  myRadio.write(&data, sizeof(data));
  delay(300);
}

Функция void WriteData() считывает данные и помещает их в переменную. Снова из 6 различных каналов, используя которые мы может считывать и записывать данные, здесь мы использовали 0xF0F0F0F066 в качестве адреса для чтения данных. Этот означает, что передатчик другого модуля записал что-то по этому адресу, и, следовательно, мы читаем это что-то с того же адреса.

void ReadData()
{
myRadio.openReadingPipe(1, 0xF0F0F0F0AA); // С какого канала считывать, 40-разрядный адрес
  myRadio.startListening();               // Остановить передачу и начать прием
  if ( myRadio.available())
  {
    while (myRadio.available())
    {
      myRadio.read( &data, sizeof(data) );
    }
    Serial.println(data.text);
  }
}

Помимо этих строк, в программе используются другие строки для считывания положения потенциометра и преобразования этого показания в значение в диапазоне от 0 до 180 с помощью функции map и отправки его на приемный модуль, где мы соответствующим образом управляем сервоприводом.

Беспроводное управление серводвигателем с помощью nRF24L01

Тестовый макет для проекта
Тестовый макет для проекта

Когда вы будете готовы, загрузите программы передатчика и приемника (приведены ниже) на соответствующие платы Arduino и подайте на них питание через USB порт. Вы также может запустить монитор последовательного порта для обеих плат, чтобы проверить, какое значение передается, и что принимается. Если всё работает должным образом, когда вы поворачиваете ручку потенциометра на стороне передатчика, то сервопривод на другой стороне должен вращаться соответствующим образом.

Работа проекта показана на демонстрационном видео ниже. Вполне нормально, если эти модули не заработают с первой попытки. Если вы столкнулись с какой-либо проблемой, снова проверьте код и разводку и попробуйте приведенные выше рекомендации по устранению неполадок.

Код

Код передающей части

/* Передает положение потенциометра через NRF24L01 с помощью Arduino
 * 
 *  Соединение выводов
 *  CE   - 7
    MISO - 12
    MOSI - 11
    SCK  - 13
    CS   - 8
    POT  - A7
*/

#include <SPI.h>  
#include "RF24.h"

RF24 myRadio (7, 8);

struct package
{
  int msg = 0;
};

byte addresses[][6] = {"0"};

typedef struct package Package;
Package data;

void setup()
{
  Serial.begin(9600);
  myRadio.begin();  
  myRadio.setChannel(115);           // Диапазон 115 находится выше WIFI
  myRadio.setPALevel(RF24_PA_MIN);   // минимальная выходная мощность
  myRadio.setDataRate(RF24_250KBPS); // Минимальная скорость
  delay(500);
  Serial.print("Setup Initialized");
}

void loop()
{
  int Read_ADC = analogRead(A7);
  char servo_value = map (Read_ADC, 0, 1024, 0,180);
  if (servo_value>1)
    data.msg = servo_value;
  WriteData();
  delay(50);
  // ReadData(); 
  //delay(200);
}

void WriteData()
{
  myRadio.stopListening();                // Остановить прием и начать передачу
  myRadio.openWritingPipe( 0xF0F0F0F0AA); // Отправить данные на этот 40-разрядный адрес
  myRadio.write(&data, sizeof(data)); 
  Serial.print("\nSent:");
  Serial.println(data.msg);
  delay(300);
}

void ReadData()
{ 
  myRadio.openReadingPipe(1, 0xF0F0F0F066); // Какой канал считывать, 40-разрядный адрес
  myRadio.startListening();                 // Остановить передачу и начать прием
  if (myRadio.available()) 
  {
    while (myRadio.available())
    {
      myRadio.read(&data, sizeof(data));
    }
    Serial.print("\nReceived:");
    Serial.println(data.msg);
  }
}

Код приемной части

/*  CE   - 7
    MISO - 12
    MOSI - 11
    SCK  - 13
    CS   - 8
    POT  - A7
 Недавно тестировалось с Nano
*/

#include <SPI.h>  
#include "RF24.h" 
#include <Servo.h>

Servo myservo;

RF24 myRadio (7, 8); 

struct package
{
  int msg;
};
typedef struct package Package;
Package data;

byte addresses[][6] = {"0"}; 

void setup() 
{
  Serial.begin(9600);
  myRadio.begin();
  myRadio.setChannel(115);           // Диапазон 115 находится выше WIFI
  myRadio.setPALevel(RF24_PA_MIN);   // минимальная выходная мощность
  myRadio.setDataRate(RF24_250KBPS); // Минимальная скорость
  myservo.attach(6);
  
  Serial.print("Setup Initialized");
  delay(500);
}

int Servo_value;
int Pev_servo_value;

void loop()  
{
  ReadData();
  delay(50);
  
  Pev_servo_value = Servo_value;
  Servo_value = data.msg; 

  while (Pev_servo_value< Servo_value)
  {
    myservo.write(Pev_servo_value);
    Pev_servo_value++;
    delay(2);
  }

  while (Pev_servo_value> Servo_value)
  {
    myservo.write(Pev_servo_value);
    Pev_servo_value--;
    delay(2);
  }

  //data.msg = "nothing to send";
  //WriteData();
  // delay(50);
}

void ReadData()
{
  myRadio.openReadingPipe(1, 0xF0F0F0F0AA); // Какой канал считывать, 40-разрядный адрес
  myRadio.startListening();                 // Остановить передачу и начать прием

  if ( myRadio.available()) 
  {
    while (myRadio.available())
    {
      myRadio.read(&data, sizeof(data));
    }
    Serial.print("\nReceived:");
    Serial.println(data.msg);
  }
}

void WriteData()
{
  myRadio.stopListening();              //Остановить прием и начать передачу
  myRadio.openWritingPipe(0xF0F0F0F066);//Отправить данные на этот 40-разрядный адрес
  myRadio.write(&data, sizeof(data)); 
  Serial.print("\nSent:");
  Serial.println(data.msg);
  delay(300);
}

Видео


На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.


Сообщить об ошибке