¿Para qué sirve este proyecto?

Imagínate que necesitas mandar una señal entre dos Arduinos separados por 20 o 30 metros, sin WiFi, sin pareo Bluetooth ni complicaciones. Quizá un sensor en el patio que tiene que avisar al control central adentro de la casa, o un control remoto casero para una puerta de garaje. Los módulos RF de 315 MHz y 433 MHz cuestan menos de $3.000 CLP el par y resuelven exactamente eso: comunicación digital unidireccional, simple, barata, con alcance real al aire libre de hasta 100 metros si los alimentas a 12 V.

Este tutorial te lleva desde el "hola mundo" de RF hasta tres montajes funcionales: detección de presencia (recibir paquetes regulares), control remoto con botones que encienden LEDs a distancia, y envío de datos numéricos crudos (temperatura, humedad, lo que necesites). Al final vas a entender cómo funciona internamente la modulación ASK, cuándo te conviene RF en lugar de Bluetooth o LoRa, y cómo aumentar el alcance sin volar el receptor.

Cómo funciona la transmisión RF a bajo costo

Los módulos baratos de 315/433 MHz usan modulación ASK (Amplitude Shift Keying): el transmisor enciende y apaga la portadora de radio para representar 1s y 0s. Eso es genial porque es trivialmente simple, pero no tiene protocolo, ni checksum, ni control de errores. Cualquier interferencia (otro Arduino transmitiendo, un microondas, un control remoto del vecino) entra como si fuera dato válido. Por eso usamos la librería VirtualWire: agrega un preámbulo, un identificador de inicio, longitud y checksum CRC sobre los datos crudos, igual que hace Ethernet a nivel de paquete.

El par viene siempre así: una placa transmisora y una receptora, cada una con tres pines rotulados SIG (señal de datos), VCC (alimentación 5 V) y GND. Fíjate en la serigrafía antes de conectar, porque las dos placas se parecen mucho.

Par de módulos RF 315 MHz con placas transmisor y receptor rotuladas SIG, VCC y GND

Setup base de prueba

Lo primero es confirmar que el hardware funciona. Vas a armar dos circuitos idénticos en lo físico pero con código distinto: uno transmite, el otro recibe.

Lista de materiales para el test inicial:

  • 1 par de módulos RF de 315 MHz o 433 MHz (transmisor + receptor)
  • 2 Arduinos (Uno R3, Nano o compatibles)
  • 2 protoboards
  • Jumpers macho macho
  • 1 LED indicador en el receptor + 1 resistencia de 330 Ω
  • Fuente externa para el Arduino transmisor (un cargador USB sirve)

Instalación de la librería VirtualWire

La librería original ya no se distribuye desde el manager de Arduino IDE moderno, así que tienes que cargarla manualmente:

  1. Descarga el .zip de VirtualWire (sirve cualquier mirror reciente. El código no ha cambiado desde 2014).
  2. En el IDE: Sketch → Include Library → Add .zip Library... y selecciona el archivo.
  3. Verifica que aparece en Sketch → Include Library → VirtualWire.

Menú del IDE de Arduino en Sketch, Include Library, Add .ZIP Library para instalar VirtualWire

Cableado del transmisor

Módulo TX Arduino
GND GND
VCC 5 V
SIG / DATA D12

Arduino Uno en protoboard conectado al módulo transmisor RF por tres cables

Cableado del receptor

Módulo RX Arduino
GND GND
VCC 5 V
SIG / DATA D11

Adicional en el receptor: LED + resistencia de 330 Ω entre D2 y GND.

Arduino Uno en protoboard con el módulo receptor RF y un LED con resistencia como indicador

Sketch del transmisor (test "hello")

C++
#include <VirtualWire.h>

const int led_pin = 11;
const int transmit_pin = 12;
const int receive_pin = 2;
const int transmit_en_pin = 3;

void setup() {
  vw_set_tx_pin(transmit_pin);
  vw_set_rx_pin(receive_pin);
  vw_set_ptt_pin(transmit_en_pin);
  vw_set_ptt_inverted(true);
  vw_setup(2000);  // bps
  pinMode(led_pin, OUTPUT);
}

byte count = 1;
void loop() {
  char msg[7] = {'h','e','l','l','o',' ','#'};
  msg[6] = count;
  digitalWrite(led_pin, HIGH);
  vw_send((uint8_t *)msg, 7);
  vw_wait_tx();
  digitalWrite(led_pin, LOW);
  delay(1000);
  count++;
}

Sketch del receptor

C++
#include <VirtualWire.h>

const int led_pin = 2;
const int receive_pin = 11;

void setup() {
  Serial.begin(9600);
  vw_set_rx_pin(receive_pin);
  vw_set_ptt_inverted(true);
  vw_setup(2000);
  vw_rx_start();
  pinMode(led_pin, OUTPUT);
}

void loop() {
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  if (vw_get_message(buf, &buflen)) {
    digitalWrite(led_pin, HIGH);
    Serial.print("Got: ");
    for (int i = 0; i < buflen; i++) {
      Serial.print(buf[i], HEX);
      Serial.print(' ');
    }
    Serial.println();
    digitalWrite(led_pin, LOW);
  }
}

Si todo está bien, el LED del receptor parpadea una vez por segundo y el monitor serial muestra los bytes ASCII de "hello #". El test de alcance es trivial: alimenta el transmisor con un power bank, sal a caminar con él, y mide hasta dónde llega antes de que el LED deje de parpadear.

Montaje 2: control remoto con dos botones

Con la base funcionando, vamos a usar los mismos módulos para controlar dos LEDs a distancia desde dos pulsadores. El transmisor manda los caracteres a/b para el primer botón y c/d para el segundo (a = LED1 ON, b = LED1 OFF, etc.).

Material adicional: 2 pulsadores táctiles, 2 resistencias de 10 kΩ (pull-down), 2 LEDs en el receptor.

Diagrama de conexión de un pulsador con resistencia pull-down de 10 kΩ a un pin digital del Arduino Uno

Cada botón usa una resistencia pull-down de 10 kΩ entre el pin y GND para que la entrada lea LOW estable cuando el pulsador está suelto, y HIGH solo al presionarlo. En este montaje el transmisor lee D8 y D7.

Transmisor con botones

C++
#include <VirtualWire.h>

const char *on2 = "a", *off2 = "b";
const char *on3 = "c", *off3 = "d";

void setup() {
  vw_set_ptt_inverted(true);
  vw_setup(300);
  vw_set_tx_pin(12);
  pinMode(8, INPUT);
  pinMode(7, INPUT);
}

void loop() {
  if (digitalRead(8) == HIGH) { vw_send((uint8_t*)on2,  1); vw_wait_tx(); delay(200); }
  else                         { vw_send((uint8_t*)off2, 1); vw_wait_tx(); delay(200); }
  if (digitalRead(7) == HIGH) { vw_send((uint8_t*)on3,  1); vw_wait_tx(); delay(200); }
  else                         { vw_send((uint8_t*)off3, 1); vw_wait_tx(); delay(200); }
}

Receptor con switch-case

C++
#include <VirtualWire.h>
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;

void setup() {
  vw_set_ptt_inverted(true);
  vw_setup(300);
  vw_set_rx_pin(11);
  vw_rx_start();
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
}

void loop() {
  if (vw_get_message(buf, &buflen)) {
    switch (buf[0]) {
      case 'a': digitalWrite(2, HIGH); break;
      case 'b': digitalWrite(2, LOW);  break;
      case 'c': digitalWrite(3, HIGH); break;
      case 'd': digitalWrite(3, LOW);  break;
    }
  }
}

Nota: bajamos la velocidad a 300 bps. A menor bit rate, mayor robustez y alcance: vale la pena cuando el "payload" útil son solo 4 caracteres.

Montaje 3: enviar enteros (sensores)

Para enviar el valor de un sensor analógico (un LDR, un potenciómetro, un sensor de temperatura LM35), conviertes el int a string ASCII con itoa() y mandas el buffer:

C++
#include <VirtualWire.h>
const int Sensor1Pin = A1;
int Sensor1Data;
char Sensor1CharMsg[4];

void setup() {
  pinMode(A1, INPUT);
  vw_setup(2000);
  vw_set_tx_pin(12);
}

void loop() {
  Sensor1Data = analogRead(Sensor1Pin);
  itoa(Sensor1Data, Sensor1CharMsg, 10);
  vw_send((uint8_t*)Sensor1CharMsg, strlen(Sensor1CharMsg));
  vw_wait_tx();
  delay(1000);
}

En el receptor, el monitor serial muestra la lectura del pin analógico llegando por aire en tiempo real, valor por valor:

Monitor serial del IDE mostrando las lecturas del pin analógico recibidas por radio: 435, 439, 443...

Para reconstruir el número, en el receptor llamas a atoi() sobre el buffer y vuelves al entero. Truco: si vas a enviar float o struct, usa una union o memcpy y manda los bytes crudos, pero acuérdate de que ambos Arduinos deben tener la misma endianness (no es problema con AVR a AVR; sí podría serlo de AVR a ARM o ESP).

Variantes y mejoras

Estas extensiones no aparecen en el tutorial original pero son las preguntas que siempre te surgen después del "hola mundo":

  • Aumentar alcance a 100 m o más: alimenta el módulo transmisor con 9 a 12 V en lugar de 5 V (revisa la datasheet de tu módulo específico, algunos aceptan hasta 12 V). Suelda una antena helicoidal de 17 cm (cuarto de onda para 433 MHz) al pin ANT. Ganancia real: de 30 m a 80 o 100 m sin obstáculos.
  • Bidireccional con dos pares de módulos: usa un par TX/RX en cada extremo. Es más caro que un módulo "transceiver" tipo NRF24L01, pero te ahorra aprender SPI y el manejo de canales del nRF.
  • Cifrado simple con XOR: VirtualWire no encripta nada. Si te preocupa que el vecino haga sniffing con un SDR de $30 USD, aplica msg[i] ^= key[i % keylen] antes de enviar y después de recibir. No es AES, pero detiene al curioso casual.

Personalización para Chile

Los componentes están disponibles en MechatronicStore con stock local. En Chile el 433 MHz cae en banda ISM no licenciada y es la opción más común, así que ese es el kit que recomendamos para este proyecto:

  • Kit De Radiofrecuencia 433Mhz 5V (Transmisor y Receptor) (SKU GP3-6): $2.490 CLP
  • Arduino Uno R3 (SKU X4-8): $9.990 CLP (necesitas 2)
  • Breadboard / Protoboard 830 puntos MB102 (SKU C-302): $3.790 CLP (necesitas 2)
  • Cables macho macho 30cm (SKU C-417): $2.990 CLP (paquete de 40)
  • LED 5mm rojo (SKU GA1-5): $100 CLP
  • Resistencia 330Ω (SKU GK3-18): $100 CLP
  • Resistencia 10kΩ (SKU GK2-15): $100 CLP (pull-down para los pulsadores)
  • Botón pulsador 12x12x8 mm (SKU GA6-16): $290 CLP (necesitas 2 para el control remoto)

Si en el tutorial original mencionan "RF Link modules" o marcas tipo XY MK 5V o XY FST, son funcionalmente los mismos que el kit de MechatronicStore.

Recursos

Versión chilena con componentes en stock local en MechatronicStore.