Komunikasi antar Arduino dengan nRF24L01 (wireless)
Setelah tidak lama ngoprek karena kesibukan yang luar biasa, akhirnya hari ini ada kesempatan buat ngoprek. Hari ini saya mencoba bermain dengan radio, radio yang saya gunakan adalah nRF24L01.
Alasan saya menggunakan nRF24L01 adalah karena jarang orang yang mengetahui keberadaan chip ini untuk koneksi Arduino secara wireless. Sebagian besar orang jika ditanya cara untuk menghubungkan Arduino secara wireless, biasanya menjawab dengan menggunakan bluetooth atau menggunakan XBee. Karena XBee terlalu mahal dan bluetooth agak mahal, maka saya memilih menggunakan nRF24L01 ini.
Gambar 1 - nRF24L01
Saat tulisan ini diketik, harga 1 unit XBee yang biasa berkisar di Rp.300.000,00 - Rp.400.000,00,
harga 1 unit bluetooth module HC-05/ HC-07 berkisar di Rp. 100.000,00 - Rp. 175.000,00,
harga 1 unit nRF24L01 berkisar di Rp.50.000,00 - Rp.100.000,00
Nah dari harga saja sudah terlihat bahwa nRF24L01 terlihat lebih pas di kantong :)
Kalo dari segi teknis, XBee, Bluetooth, dan nFR24L01 sama-sama beroperasi di frekuensi 2,4GHz. Perlu diperhatikan juga bahwa ada XBee seri tertentu yang tidak beroperasi di 2,4GHz. Untuk pengetahuan teknis lebih lanjut bisa dibaca di XBee, bluetooth, dan nRF24L01
Percobaan pertama saya gatot alias gagal total, setelah lepas pasang kabel, cek sana sini, coba lagi, masih gatot juga. Akhirnya saya coba menelulsuri pelan-pelan, dan ternyata saya mendapatkan pencerahan, yaitu ternyata nRF24L01 ini menggunakan SPI, dan ternyata pin Arduino Uno dan Mega untuk komunikasi via SPI ini berbeda letaknya, berdasarkan http://arduino.cc/.
Kode yang saya gunakan adalah
/*
Copyright (C) 2011 J. Coliz
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example for Getting Started with nRF24L01+ radios.
*
* This is an example of how to use the RF24 class. Write this sketch to two
* different nodes. Put one of the nodes into 'transmit' mode by connecting
* with the serial monitor and sending a 'T'. The ping node sends the current
* time to the pong node, which responds by sending the value back. The ping
* node can then see how long the whole cycle took.
*/
#include
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9, 10);
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = {
0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
//
// Role management
//
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing.
//
// The various roles supported by this sketch
typedef enum {
role_ping_out = 1, role_pong_back }
role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = {
"invalid", "Ping out", "Pong back"};
// The role of the current running sketch
role_e role = role_pong_back;
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
//
// Setup and configure rf radio
//
radio.begin();
// optionally, increase the delay between retries & # of retries
radio.setRetries(15,15);
// optionally, reduce the payload size. seems to
// improve reliability
//radio.setPayloadSize(8);
//
// Open pipes to other nodes for communication
//
// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
// Open 'our' pipe for writing
// Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
//if ( role == role_ping_out )
{
//radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
//else
{
//radio.openWritingPipe(pipes[1]);
//radio.openReadingPipe(1,pipes[0]);
}
//
// Start listening
//
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
}
void loop(void)
{
//
// Ping out role. Repeatedly send the current time
//
if (role == role_ping_out)
{
// First, stop listening so we can talk.
radio.stopListening();
// Take the time, and send it. This will block until complete
unsigned long time = millis();
printf("Now sending %lu...",time);
bool ok = radio.write( &time, sizeof(unsigned long) );
if (ok)
printf("ok...");
else
printf("failed.\n\r");
// Now, continue listening
radio.startListening();
// Wait here until we get a response, or timeout (250ms)
unsigned long started_waiting_at = millis();
bool timeout = false;
while ( ! radio.available() && ! timeout )
if (millis() - started_waiting_at > 200 )
timeout = true;
// Describe the results
if ( timeout )
{
printf("Failed, response timed out.\n\r");
}
else
{
// Grab the response, compare, and send to debugging spew
unsigned long got_time;
radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
}
// Try again 1s later
delay(1000);
}
//
// Pong back role. Receive each packet, dump it out, and send it back
//
if ( role == role_pong_back )
{
// if there is data ready
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned long got_time;
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Got payload %lu...",got_time);
// Delay just a little bit to let the other unit
// make the transition to receiver
delay(20);
}
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( &got_time, sizeof(unsigned long) );
printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
// Become the primary transmitter (ping out)
role = role_ping_out;
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
// Become the primary receiver (pong back)
role = role_pong_back;
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
}
}
}
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example for Getting Started with nRF24L01+ radios.
*
* This is an example of how to use the RF24 class. Write this sketch to two
* different nodes. Put one of the nodes into 'transmit' mode by connecting
* with the serial monitor and sending a 'T'. The ping node sends the current
* time to the pong node, which responds by sending the value back. The ping
* node can then see how long the whole cycle took.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(48, 49);
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = {
0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
//
// Role management
//
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing.
//
// The various roles supported by this sketch
typedef enum {
role_ping_out = 1, role_pong_back }
role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = {
"invalid", "Ping out", "Pong back"};
// The role of the current running sketch
role_e role = role_pong_back;
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
//
// Setup and configure rf radio
//
radio.begin();
// optionally, increase the delay between retries & # of retries
radio.setRetries(15,15);
// optionally, reduce the payload size. seems to
// improve reliability
//radio.setPayloadSize(8);
//
// Open pipes to other nodes for communication
//
// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
// Open 'our' pipe for writing
// Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
//if ( role == role_ping_out )
{
//radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
//else
{
//radio.openWritingPipe(pipes[1]);
//radio.openReadingPipe(1,pipes[0]);
}
//
// Start listening
//
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
}
void loop(void)
{
//
// Ping out role. Repeatedly send the current time
//
if (role == role_ping_out)
{
// First, stop listening so we can talk.
radio.stopListening();
// Take the time, and send it. This will block until complete
unsigned long time = millis();
printf("Now sending %lu...",time);
bool ok = radio.write( &time, sizeof(unsigned long) );
if (ok)
printf("ok...");
else
printf("failed.\n\r");
// Now, continue listening
radio.startListening();
// Wait here until we get a response, or timeout (250ms)
unsigned long started_waiting_at = millis();
bool timeout = false;
while ( ! radio.available() && ! timeout )
if (millis() - started_waiting_at > 200 )
timeout = true;
// Describe the results
if ( timeout )
{
printf("Failed, response timed out.\n\r");
}
else
{
// Grab the response, compare, and send to debugging spew
unsigned long got_time;
radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
}
// Try again 1s later
delay(1000);
}
//
// Pong back role. Receive each packet, dump it out, and send it back
//
if ( role == role_pong_back )
{
// if there is data ready
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned long got_time;
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Got payload %lu...",got_time);
// Delay just a little bit to let the other unit
// make the transition to receiver
delay(20);
}
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( &got_time, sizeof(unsigned long) );
printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
// Become the primary transmitter (ping out)
role = role_ping_out;
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
// Become the primary receiver (pong back)
role = role_pong_back;
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
}
}
}
Nah, setelah mengganti kode RF24 radio(9, 10); dengan RF24 radio(48, 49); serta menyesuaikan pin SPI lainnya, akhirnya percobaan saya berhasil dan dapat dilihat pada video berikut.
Karena saya kurang puas dengan tutorial sebelumnya, akhirnya saya coba googling-googling lagi mencari tutorial yang lebih menantang, nah akhirnya saya menemukan tutorial yang agak menarik di http://www.bajdi.com/. Setelah saya lihat-lihat sekilas, ternyata tutorial yang ini berbeda dengan tutorial yang saya lakukan sebelumnya, tutorial ini menggunakan library Mirf.h, sedangkan tutorial sebelumnya menggunakan RF24.h. Oke, saya pun langsung mencoba merangkai.
Gambar 4 - tabel skema rangkaian yang seharusnya saya buat
Gambar 5 - rangkaian yang sudah saya buat
Oke ternyata tidak langsung berhasil, setelah saya lihat-lihat ternyata Mirf.h mendeklarasikan pin CE dan CSN pada Uno di pin 7 dan 8, saya pun memperbaiki rangkaian saya dan menjalankan lagi. Kode yang saya gunakan adalah
// http://www.bajdi.com
// Nrf24L01 connected to Arduino Uno
// Nrf24L01 connection details http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// Receives analog value from transmitter and maps it to a PWM range (0-255) to dim a led
#include
#include
#include
#include
int rate;
int ledValue;
const int led = 3;
void setup(){
Serial.begin(9600);
pinMode(led, OUTPUT);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"serv1");
Mirf.payload = sizeof(rate);
Mirf.config();
}
void loop(){
while(!Mirf.dataReady()){
}
Mirf.getData((byte *) &rate);
ledValue = (map( rate, 0, 1024, 0, 255 ) );
analogWrite(led, ledValue);
Serial.println(ledValue);
delay(10);
}
// http://www.bajdi.com
// Nrf24L01 connected to Mega 2560
// Nrf24L01 connection details http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// Transmit analog value from pin A0 to the receiver
#include
#include
#include
#include
int rate;
void setup(){
Serial.begin(9600);
Mirf.cePin = 48; //ce pin on Mega 2560, REMOVE THIS LINE IF YOU ARE USING AN UNO
Mirf.csnPin = 49; //csn pin on Mega 2560, REMOVE THIS LINE IF YOU ARE USING AN UNO
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"clie1");
Mirf.payload = sizeof(rate);
Mirf.config();
}
void loop(){
rate = analogRead(A0);
Serial.println(rate);
Mirf.setTADDR((byte *)"serv1");
Mirf.send((byte *) &rate);
while(Mirf.isSending()){
}
}
Hasil akhirnya dapat dilihat pada video berikut.
Nah sekian saja postingan kali ini, semoga membuka wawasan pembaca mengenai komunikasi radio pada Arduino. Selamat mencoba!
Artikel yang sangat informatif, Untuk library nampaknya RF24 lebih updated dan lengkap dibanding Mirf. Setelah dicoba, RF24 bahkan menyediakan lib untuk Attiny85, dan juga bisa digunakan untuk komunikasi Arduino<=>RaspberryPi, baik dengan Uno, Nano, ProMini, dll.... Dan juga mesh network RF24 nampaknya sangat bermanfaat untuk membuat jaringan sensor wireless yang handal ...
Artikel yang sangat informatif, Untuk library nampaknya RF24 lebih updated dan lengkap dibanding Mirf. Setelah dicoba, RF24 bahkan menyediakan lib untuk Attiny85, dan juga bisa digunakan untuk komunikasi Arduino<=>RaspberryPi, baik dengan Uno, Nano, ProMini, dll.... Dan juga mesh network RF24 nampaknya sangat bermanfaat untuk membuat jaringan sensor wireless yang handal ...
NRF24L01 bisa ngga dibikin seperti Bluetooth or Wi-Fi "untuk kirim data/file"
BalasHapusbandwidth dari NRF24L01 max cuma 2MBps atau sekitar 185KBps, masih lancar buat nonton yutup hahahaaa
Hapusefektifnya buat radio control mobil²an atau drone
bisa post rangkaiannya mas.. agak susah baca tabel
BalasHapuskak kok eror ya pas di upload?
BalasHapusGan, kalau pakai arduino uno semua bisa gan?
BalasHapusArtikel yang sangat informatif,
BalasHapusUntuk library nampaknya RF24 lebih updated dan lengkap dibanding Mirf. Setelah dicoba, RF24 bahkan menyediakan lib untuk Attiny85, dan juga bisa digunakan untuk komunikasi Arduino<=>RaspberryPi, baik dengan Uno, Nano, ProMini, dll.... Dan juga mesh network RF24 nampaknya sangat bermanfaat untuk membuat jaringan sensor wireless yang handal ...
Artikel yang sangat informatif,
BalasHapusUntuk library nampaknya RF24 lebih updated dan lengkap dibanding Mirf. Setelah dicoba, RF24 bahkan menyediakan lib untuk Attiny85, dan juga bisa digunakan untuk komunikasi Arduino<=>RaspberryPi, baik dengan Uno, Nano, ProMini, dll.... Dan juga mesh network RF24 nampaknya sangat bermanfaat untuk membuat jaringan sensor wireless yang handal ...
Wah artikelnya bagus, gan pernah coba komunikasi 2 arah bergantian (half duplex)?
BalasHapusMin mau tanya, kalau 1 receiver nrf24, apa bisa menerima 2 data dr 2 transmit nrf24 ?
BalasHapusUp
Hapusgan izin uji coba buat tugas ya makasih
BalasHapusKalo dibuat untuk mic bisa ga ka?
BalasHapus