Modem radiowy nRF24L01 – zdalne sterowanie urządzeniem

Zdalne sterowanie przy użyciu modemu nRF24L01 jest proste. Zwyczajnie zamiast napisu program wysyła dane, które służą do włączania, albo wyłączania urządzeń podłączonych do pinów.

Program nadajnika, który realizuje taką możliwość wygląda tak:

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

RF24 radio(7, 8);

void setup()
{
  while (!Serial);
  Serial.begin(9600);
  
  radio.begin();
  radio.setRetries(15, 15);
  radio.stopListening();
}

void loop()
{
  if (Serial.available())
  {
    byte rxAddr[6] = {0};
    Serial.readBytesUntil(' ', rxAddr, 5);
    radio.openWritingPipe(rxAddr);
    Serial.read();
    
    byte command[2];
    command[0] = Serial.parseInt();
    Serial.read();
    command[1] = Serial.parseInt();
    Serial.read();
    
    radio.write(&command, sizeof(command));
  }
}

Zasada działania jest prosta. Wysyłasz do Arduino polecenia przez port USB za pomocą Monitora portu szeregowego. Arduino je przerabia na polecenia sterujące odbiornikiem i wysyła przez modem radiowy.

By wysyłać polecenia Monitor portu szeregowego musi być ustawiony na prędkość 9600 bodów i “Nowa linia” w dolnym pasku.

Przykładowe polecenie wygląda tak:

leds1 2 1

Pierwsze 5 znaków to adres odbiornika. Czyli dla programu można łatwo stworzyć sieć wielu odbiorników o różnych adresach, które będą sterowały urządzeniami w różnych miejscach w promieniu 100 metrów.

Kolejną cyfrą po spacji jest numer urządzenia. Arduino i inne płytki mają wiele pinów więc mogą sterować wieloma urządzeniami. Ta cyfra wybiera urządzenie.

Ostatnią cyfrą jest ustawienie urządzenia. 1 oznacza włączenie, 0 wyłączenie.

Elementy polecenia są oddzielone spacjami.

Możesz wydawać polecenia ręcznie lub napisać sobie program w dowolnym języku, który obsługuje port szeregowy PC i sterować zdalnie urządzeniami za pomocą programu.

Budowa programu przypomina wcześniejsze przykłady z poprzedniego rozdziału. Postanowiłem rozwinąć je ewolucyjnie, żebyś łatwiej zrozumiał co się zmieniło i jak wpłynęło na program.

Różnice zaczynają się w funkcji “loop”. Jest tam wykorzystana metoda “Serial.available();” [interfejs szeregowy.dostępne dane], która sprawdza czy port szeregowy Arduino coś odebrał. Jeśli odebrał, to wykonywana jest reszta programu w bloku “if”.

 byte rxAddr[6] = {0};
 Serial.readBytesUntil(' ', rxAddr, 5);
 radio.openWritingPipe(rxAddr);
 Serial.read();

Ta część odczytuje pierwszą część polecenia czyli adres modemu do którego będą wysyłane dane.

W tym fragmencie deklaruję tablicę typu “byte” o 6 elementach, wypełnioną zerami o nazwie “rxAddr”. Będzie ona przechowywała adres odbiornika.

Metoda “Serial.readBytesUntil(’ ’, rxAddr, 5);” [interfejs szeregowy.czytaj bajty dopóki] odczytuje dane z interfejsu szeregowego aż natknie się na znak spacji ’ ’ lub odczyta 5 znaków.

Pierwszy argument to do pojawienia jakiego znaku metoda ma czytać dane.

Drugim argumentem jest tablica do jakiej odczytane dane trzeba zapisać. W tym przypadku jest to tablica adresu odbiornika “rxAddr”.

Trzecim argumentem jest maksymalna liczba znaków do odczytania.

Po odczytaniu adresu, program ustawia modem na adres odbiornika za pomocą metody “radio.openWritingPipe”.

Metoda “Serial.read();” [interfejs szeregowy.odczytaj dane] jest tylko po to, żeby odczytać znak spacji rozdzielający argumenty polecenia. Nigdzie go nie zapisuje. Jest to tylko po to, żeby przyśpieszyć odczytywanie danych.

byte command[2];
command[0] = Serial.parseInt();
Serial.read();
command[1] = Serial.parseInt();
Serial.read();

Kolejny fragment odczytuje 2 kolejne argumenty polecenia – numer urządzeia i jego ustawienie.

Najpierw tworzę tablicę 2-elementową typu “byte” o nazwie “command” [rozkaz/polecenie], która będzie przechowywała polecenie wysyłane modemem do odbiornika.

Metoda “Serial.parseInt();” [interfejs szeregowy.zintepretuj liczbę całkowitą] zamienia tekstowe znaki liczby wysyłane z przez interfejs szeregowy z Monitora portu szeregowego na cyfrowe. Metoda składa liczbę z cyfr, aż natknie się na inny znak niż cyfra. Jeśli w interfejsie szeregowym nie odebrano cyfr, to ta metoda zwraca 0.

Zinterpretowane liczby zapisywane są w pierwszym i drugim elemencie tablicy “command”. Pierwszy element przechowuje numer urządzenia, a drugi jego ustawienie w postaci cyfrowej.

Na koniec program wysyła wypełnioną tablicę “command” do odbiornika za pomocą metody “radio.write(&command, sizeof(command));”.

Program odbiornika wygląda tak:

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

RF24 radio(7, 8);

void setup()
{
  radio.begin();
  const byte rxAddr[6] = "leds1";
  radio.openReadingPipe(0, rxAddr);
  
  radio.startListening();
  
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop()
{
  if (radio.available())
  {
    byte command[2];
    radio.read(&command, sizeof(command));
    
    if (command[0] < 3)
    {
      digitalWrite(command[0]+2, command[1]);
    }
  }
}

Zasada działania programu jest taka, że do pinów 2, 3, 4 podłączyłem trzy światełka LED (zielone, żółte, czerwone) anodami przez rezystory 220 Ohm. Katody podłączyłem do pinu GND. Urządzenie ma adres “leds1” i numery urządzeń dla światełek to 0 – zielony, 1 – żółty, 2 – czerwony. Zatem jeśli do nadajnika wyślesz polecenie:

leds1 2 1

To w odbiorniku zaświeci się światło czerwone.

Budowa programu przypomina oczywiście program odbiornika z poprzedniego rozdziału.

To co się zmieniło w funkcji “setup”. Adres odbiornika znajduje się z tablicy “rxAddr”. Każdy odbiornik powinien mieć inny adres, by można było sterować nim niezależnie.

Kolejną nowością jest użycie funkcji “pinMode(2, OUTPUT);” [pin ustaw działanie]. Ustawiam nim piny 2, 3, 4 jako wyjście “OUTPUT” [wyjście], żeby sterowały światłami LED.

W funkcji “loop” zaczynamy od znanego sprawdzenia czy modem odebrał dane za pomocą metody “radio.available();”.

Jeśli odebrał, to tworzona jest 2-elementowa tablica “command” [rozkaz/polecenie] typu “byte”, która będzie przechowywać polecenie wysłane do modemu.

Polecenie jest odczytywane za pomocą metody “radio.read”.

Następnie za pomocą “if” [jeśli/gdyby] sprawdzane jest czy pierwszy element tablicy polecenia – przechowujący numer urządzenia jest mniejszy niż 2. Mamy tyko 3 urządzenia numerach 0, 1, 2 więc nie chciałem, żeby błędne polecenie coś napsuło.

Jeśli polecenie ma dobrą wartość to przekazywane jest do funkcji “digitalWrite(command[0]+2, command[1]);” [zapisz do pinu cyfrowego].

Jego pierwszym argumentem jest numer pinu, a drugim ustawienie stanu tego pinu.

Jako pierwszy argument użyłem pierwszego elementu tablicy “command” przechowującego numer urządzenia. Ponieważ numer urządzenia jest od 0 do 2, a piny są od 2 do 4 dodałem do niego “+2”, żeby zamienił się w numer pinu (0+2=2, 1+2=3…).

Drugi argument przekazuje wartość dla pinu. 0 to stan niski – dioda nie świeci, 1 to stan wysoki – dioda świeci.

Na koniec wpisałem w Monitor Portu to:

I 6 metrów dalej zrobiło się to:

Zamiast diod możesz podłączyć przekaźniki i sterować zdalnie urządzeniami na prąd.

Zamiast funkcji możesz użyć “analogWrite” i sterować urządzeniami przez sygnał PWM np. silnikami. Możesz też tam wstawić obsługę serwomechanizmu i mieć zdalnie sterowanego robota.

Jeśli masz pytania lub coś napisałem niezrozumiale, zapytaj w komentarzach.

Modemy radiowe nRf24L01 kupisz w Nettigo.

sprae

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.