NRF24 Arduino-Raspberry Pi (bidireccional)

Hola de nuevo! En este tutorial vamos a enviar datos mediante el módulo NRF24 entre Arduino y Raspberry Pi. Hace unos meses escribimos un tutorial para enviar datos con el módulo NRF24 entre Arduinos.

 

El material que vamos a necesitar es el siguiente:

  • Módulo NRF24L01
  • Arduino
  • Raspberry Pi (está probado con la Raspberry Pi B)
  • Cable HDMI
  • Jumpers

Librerias

La libreria que usaremos tanto en Arduino como en Raspberry Pi será la RF24. En el anterior tutorial se explicó como funciona en Arduino, así que ahora vamos a instalarla en la Raspberry Pi.

Lo primero de todo mirar si existe alguna actualización:

sudo apt-get update
sudo apt-get upgrade

 

Ahora habilitamos los GPIO de la Raspberry Pi

sudo apt-get install python-dev

#comentar las líneas con los módulos spi-bcm2708 y i2c-bcm2708
sudo vim /etc/modprobe.d/raspi-blacklist.conf

#aseguraros de tener el módulo i2c-dev en /etc/module
sudo vim /etc/modules

sudo adduser pi i2c
sudo apt-get update

#reiniciamos
sudo shutdown -r now

#obtenemos el software GPIO
wget https://pypi.python.org/packages/source/R/RPi.GPIO/RPi.GPIO-0.5.3a.tar.gz

#descomprimimos e instalamos
tar -xzvf RPi.GPIO-0.5.3a.tar.gz
cd RPi.GPIO-0.5.3a/
sudo python setup.py install
sudo apt-get install i2c-tools

 

Llega el momento de descargarse la biblioteca RF24 para la Raspberry Pi.

#instalamos git
sudo apt-get install git

#vamos al directorio general
cd ~

#clonar las reposiciones RF24 del github de edoardoo
git clone https://github.com/edoardoo/RF24RaspberryCommunicator.git#recuperar la libreria RF24
cd ~/RF24RaspberryCommunicator/
git submodule init
git submodule update
#instalamos la libreria
cd ~/RF24RaspberryCommunicator/RF24
sudo make install

Montaje

Las conexiones tanto para Arduino como para Raspberry Pi se muestran en la siguiente tabla

Tabla conexiones NRF24L01
Tabla conexiones NRF24L01

 

El NRF24L01 se conecta a los puertos GPIO de la Raspberry Pi siguiendo el siguiente esquema

esquema NRF24L01 en Raspberry Pi

 

El Arduino, para este caso, tiene un montaje diferente que para la conexión entre Arduinos.esquema NRF24L01 en Arduino

Código

Una vez instalada la libreria tanto en Arduino como en Raspberry Pi vamos a realizar nuestro código.

Arduino

Para hacer la prueba de si funciona, abriremos GettingStarted.ino de la libreria RF24. A continuación os dejo el código por si no le encontrais:

/*
 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.
//2014 - TMRh20 - Updated along with Optimized RF24 Library fork
 */

/**
 * Example for Getting Started with nRF24L01+ radios. 
 *
 * This is an example of how to use the RF24 class to communicate on a basic level.  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. 
 * Note: For a more efficient call-response scenario see the GettingStarted_CallResponse.ino example.
 * Note: When switching between sketches, the radio may need to be powered down to clear settings that are not "un-set" otherwise
 */


#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(9,10);

byte addresses[][6] = {"1Node","2Node"};


// Set up roles to simplify testing 
boolean role;                                    // The main role variable, holds the current role identifier
boolean role_ping_out = 1, role_pong_back = 0;   // The two different roles.

void setup() {

  Serial.begin(57600);
  printf_begin();
  printf("*** PULSA 'T' para empezar a atransmitir con la Raspberry\n\r");

  // Setup and configure rf radio
  radio.begin();                          // Start up the radio
  radio.setAutoAck(1);                    // Ensure autoACK is enabled
  radio.setRetries(15,15);                // Max delay between retries & number of retries
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1,addresses[0]);
  
  radio.startListening();                 // Start listening
  radio.printDetails();                   // Dump the configuration of the rf unit for debugging
}

void loop(void){

/****************** Ping Out Role ***************************/
 if (role == role_ping_out)  {
    
    radio.stopListening();                                    // First, stop listening so we can talk.
      
    printf("Now sending \n\r");

    unsigned long time = micros();                             // Take the time, and send it.  This will block until complete
     if (!radio.write( &time, sizeof(unsigned long) )){  printf("failed.\n\r");  }
        
    radio.startListening();                                    // Now, continue listening
    
    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    boolean timeout = false;                                   // Set up a variable to indicate if a response was received or not
    
    while ( ! radio.available() ){                             // While nothing is received
      if (micros() - started_waiting_at > 200000 ){            // If waited longer than 200ms, indicate timeout and exit while loop
          timeout = true;
          break;
      }      
    }
        
    if ( timeout ){                                             // Describe the results
        printf("Failed, response timed out.\n\r");
    }else{
        unsigned long got_time;                                 // Grab the response, compare, and send to debugging spew
        radio.read( &got_time, sizeof(unsigned long) );

        // Spew it
        printf("Sent %lu, Got response %lu, round-trip delay: %lu microseconds\n\r",time,got_time,micros()-got_time);
    }

    // Try again 1s later
    delay(1000);
  }


/****************** Pong Back Role ***************************/

  if ( role == role_pong_back )
  {
    if( radio.available()){
      unsigned long got_time;                                       // Variable for the received timestamp
      while (radio.available()) {                                   // While there is data ready
        radio.read( &got_time, sizeof(unsigned long) );             // Get the payload
      }    
     
      radio.stopListening();                                        // First, stop listening so we can talk   
      radio.write( &got_time, sizeof(unsigned long) );              // Send the final one back.      
      radio.startListening();                                       // Now, resume listening so we catch the next packets.     
      printf("Sent response %lu \n\r", got_time);  
   }
 }


/****************** Change Roles via Serial Commands ***************************/

 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");

      role = role_ping_out;                  // Become the primary transmitter (ping out)
      radio.openWritingPipe(addresses[0]);
      radio.openReadingPipe(1,addresses[1]);
  
    }*/
//else 
  if ( c == 'R' && role == role_ping_out )
    {
      printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
      
       role = role_pong_back;                // Become the primary receiver (pong back)
       radio.openWritingPipe(addresses[1]);
       radio.openReadingPipe(1,addresses[0]);
    }
  }
}

 

Raspberry Pi

Abrimos un archivo de texto con extension *.cpp y ahí es donde escribiremos nuestro código. Después para compilar en el terminal teneis que abrir la carpeta donde está guardado el archivo y seguidamente escribir:

Supongamos que nuestro archivo se llama arduino-raspberry.cpp

g++ -lstdc++ -lrt -lrf24-bcm -lpthread arduino-raspberry.cpp -o arduino-raspberry

sudo ./arduino-raspberry

 

Aquí es donde se complica la cosa, dado que tenemos un código para enviar datos a Arduino y otro para recibir datos.

Se puede usar el archivo GettingStarted directamente pero hay que comentar algún apartado y cuando compilas hay que pulsar un 0 en el terminal si queremos enviar datos Arduino – Raspberry Pi; y un 1 si queremos Raspberry Pi – Arduino.

 

Enviar datos

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <RF24/RF24.h>

using namespace std;


// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);


// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t pipes[][6] = {"3Node","4Node"};

int main(int argc, char** argv){

	// Setup and configure rf radio
	radio.begin();

	// optionally, increase the delay between retries & # of retries
	radio.setRetries(15,15);
	// Dump the configuration of the rf unit for debugging
	radio.printDetails();


	radio.openWritingPipe(pipes[0]);
	radio.openReadingPipe(1,pipes[1]);
	
	// forever loop
	while (1){
		// First, stop listening so we can talk.
		radio.stopListening();

		// Take the time, and send it.  This will block until complete

		printf("Now sending...\n");
		unsigned long time = millis();

		bool ok = radio.write( &time, sizeof(unsigned long) );

		if (!ok){
			printf("failed.\n");
		}
		// 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");
		}
		else{
			// Grab the response, compare, and send to debugging spew
			unsigned long got_time;
			radio.read( &got_time, sizeof(unsigned long) );

			// Spew it
			printf("Numero a enviar %lu \n",got_time);
		}

		// Try again 1s later
		// delay(1000);

		sleep(1);

	
	} // forever loop

  return 0;
}

 

Después de compilar, el resultado sería el siguiente:

Terminal de la Raspberry Pi
Terminal de la Raspberry Pi
Serial Terminal del Arduino
Serial Terminal del Arduino (hay que pulsar R para recibir datos)

 

Recibir datos

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <RF24/RF24.h>

using namespace std;

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);


// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t pipes[][6] = {"1Node","2Node"};


int main(int argc, char** argv){

   // Setup and configure rf radio
  radio.begin();

  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);
  // Dump the configuration of the rf unit for debugging
  //radio.printDetails();



      radio.openWritingPipe(pipes[1]);
      radio.openReadingPipe(1,pipes[0]);
      radio.startListening();

    
	
	// forever loop
	while (1){
					
		// if there is data ready
		//printf("Check available...\n");

		if ( radio.available()){
			// Dump the payloads until we've gotten everything
			unsigned long humedad;


			// Fetch the payload, and see if this was the last one.
			while(radio.available()){
				radio.read( &humedad, sizeof(unsigned long) );
			}
			
			radio.stopListening();
				
			radio.write( &humedad, sizeof(unsigned long) );

			// Now, resume listening so we catch the next packets.
			radio.startListening();

			// Spew it
			printf("Humedad del suelo: %lu\n",humedad);
				
			delay(925); //Delay after payload responded to, minimize RPi CPU time
				
		}
		
		

	} // forever loop

  return 0;
}  //fin main

 

Después de compilar, el resultado es:

Serial Terminal del Arduino (hay que pulsar T para enviar datos)
Serial Terminal del Arduino (hay que pulsar T para enviar datos)
Terminal de la Raspberry Pi
Terminal de la Raspberry Pi

 

Todos estos tutoriales sobre NRF24L01 vienen de un proyecto, el cuál es un riego automatizado. Poco a poco os iremos poniendo más tutoriales hasta completar el proyecto.

Si os habeis quedado con ganas de más, el próximo tutorial será como enviar datos Arduino(1) – Raspberry Pi – Arduino (2) mediante radiofrecuencia.

Hasta la próxima!!

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *