Overview
The Ra-02 is Ai-Thinker's LoRa module built on the Semtech SX1278 — the radio that made kilometer-range, battery-friendly links a hobbyist reality. LoRa's chirp spread-spectrum modulation digs signals out from far below the noise floor, so two of these modules can exchange sensor packets across 2-5 km line-of-sight (hundreds of meters through buildings) while transmitting at just +20 dBm from a coin-sized board. It operates in the 433 MHz ISM band and also speaks FSK/GFSK/OOK for conventional radio work.
The module talks SPI — NSS, SCK, MOSI, MISO plus a RESET line and six DIO event pins (DIO0 signals "packet received/sent" and is the only one most libraries use). Sixteen castellated pads on 2mm pitch, a U.FL connector for the antenna, and that's the whole interface. It is strictly a 3.3V device: 5V on VCC or the SPI pins kills it, so classic 5V Arduinos need a level shifter while ESP32, Pi, and Pico connect directly.
One hard rule before anything else: never power it up and transmit without an antenna attached — the reflected RF destroys the output stage in seconds. Screw a 433 MHz antenna onto the U.FL (or a U.FL-to-SMA pigtail) first, then enjoy the fun parts: remote weather stations, farm and greenhouse telemetry, GPS trackers, off-grid text messaging, and multi-node sensor networks that WiFi could never reach.
At a Glance
Specifications
| Parameter | Value |
| Module / Chipset | Ai-Thinker Ra-02, Semtech SX1278 |
| Frequency Range | 410 - 525 MHz (433 MHz band typical) |
| Modulation | LoRa chirp spread spectrum; FSK/GFSK/OOK modes |
| Max TX Power | +20 dBm (~100 mW) via PA_BOOST |
| Sensitivity | Down to -148 dBm (SF12, narrow BW) |
| Spreading Factor / BW | SF6-SF12; 7.8 kHz - 500 kHz bandwidth |
| Data Rate | ~18 bps (max range) to ~37.5 kbps |
| Supply Voltage | 1.8 - 3.7V (3.3V nominal) — NOT 5V tolerant |
| Current | ~120 mA TX @ +20 dBm, ~12 mA RX, ~1 uA sleep |
| Interface | SPI (NSS/SCK/MOSI/MISO) + RESET + DIO0-DIO5 |
| Antenna | U.FL/IPEX connector — 433 MHz antenna required |
| Size | 17 x 16 mm, 16 castellated pads (2.0 mm pitch) |
Pinout Diagram
Pins 1-8 down the left: GND, GND, 3.3V, RESET, DIO0, DIO1, DIO2, DIO3. Pins 9-16 up the right: GND, DIO4, DIO5, SCK, MISO, MOSI, NSS, GND. The U.FL antenna socket sits at the top corner. For basic LoRa links you wire the SPI four, RESET, DIO0, power and ground — DIO1-DIO5 can stay unconnected.
Wiring Guide
Arduino Wiring (3.3V caution!)
A 5V Uno/Nano needs its SPI outputs level-shifted down to 3.3V. Use a level shifter module or resistor dividers on SCK, MOSI, NSS, and RESET; MISO (module → Arduino) connects directly.
| Ra-02 Pin | Arduino Pin | Details |
|---|---|---|
| 3.3V | 3.3V | NOT 5V — add 100uF locally |
| GND (any) | GND | |
| NSS | D10 (via shifter) | Chip select |
| SCK / MOSI | D13 / D11 (via shifter) | SPI |
| MISO | D12 (direct) | 3.3V high reads fine |
| RESET | D9 (via shifter) | |
| DIO0 | D2 (direct) | RX/TX done interrupt |
ESP32 Wiring (direct, no shifting)
| Ra-02 Pin | ESP32 Pin | Details |
|---|---|---|
| 3.3V / GND | 3V3 / GND | |
| NSS | GPIO 5 | Chip select |
| SCK | GPIO 18 | VSPI |
| MOSI | GPIO 23 | |
| MISO | GPIO 19 | |
| RESET | GPIO 14 | |
| DIO0 | GPIO 26 | Interrupt |
Raspberry Pi Wiring (SPI0)
| Ra-02 Pin | Pi Pin | Details |
|---|---|---|
| 3.3V / GND | Pin 1 / Pin 6 | |
| NSS | Pin 24 (GPIO 8, CE0) | |
| SCK | Pin 23 (GPIO 11) | |
| MOSI | Pin 19 (GPIO 10) | |
| MISO | Pin 21 (GPIO 9) | |
| RESET | Pin 15 (GPIO 22) | |
| DIO0 | Pin 18 (GPIO 24) |
Raspberry Pi Pico Wiring (SPI0)
| Ra-02 Pin | Pico Pin | Details |
|---|---|---|
| 3.3V / GND | 3V3(OUT) / GND | |
| NSS | GP5 | Chip select |
| SCK | GP2 (SPI0 SCK) | |
| MOSI | GP3 (SPI0 TX) | |
| MISO | GP4 (SPI0 RX) | |
| RESET | GP6 | |
| DIO0 | GP7 |
Code Examples
The Arduino/ESP32 sketches use Sandeep Mistry's LoRa library (a sender and a receiver — flash one of each). The Pi and Pico examples use popular SX127x Python/MicroPython drivers. Both ends of a link must match frequency, spreading factor, bandwidth, and sync word.
Arduino / ESP32 — Sender (Arduino IDE)
// Ra-02 SX1278 - LoRa Sender (Arduino IDE)
// Library: "LoRa" by Sandeep Mistry (Library Manager)
// ESP32 pins: NSS=5, RESET=14, DIO0=26 (change for your wiring)
#include <SPI.h>
#include <LoRa.h>
const long FREQ = 433E6;
int counter = 0;
void setup() {
Serial.begin(115200);
LoRa.setPins(5, 14, 26); // NSS, RESET, DIO0
if (!LoRa.begin(FREQ)) {
Serial.println("LoRa init failed - check wiring/antenna!");
while (1);
}
LoRa.setSpreadingFactor(9); // 7 = fast, 12 = max range
LoRa.setSignalBandwidth(125E3);
LoRa.setTxPower(17); // dBm (max 20)
LoRa.setSyncWord(0x12); // private-network marker
Serial.println("LoRa sender ready");
}
void loop() {
Serial.print("Sending packet ");
Serial.println(counter);
LoRa.beginPacket();
LoRa.print("Hello #");
LoRa.print(counter++);
LoRa.endPacket();
delay(2000);
}
Arduino / ESP32 — Receiver (Arduino IDE)
// Ra-02 SX1278 - LoRa Receiver (Arduino IDE)
// Same library and settings as the sender.
#include <SPI.h>
#include <LoRa.h>
void setup() {
Serial.begin(115200);
LoRa.setPins(5, 14, 26);
if (!LoRa.begin(433E6)) {
Serial.println("LoRa init failed!");
while (1);
}
LoRa.setSpreadingFactor(9);
LoRa.setSignalBandwidth(125E3);
LoRa.setSyncWord(0x12);
Serial.println("LoRa receiver ready");
}
void loop() {
int packetSize = LoRa.parsePacket();
if (packetSize) {
String msg = "";
while (LoRa.available()) {
msg += (char)LoRa.read();
}
Serial.print("Received: '");
Serial.print(msg);
Serial.print("' RSSI: ");
Serial.print(LoRa.packetRssi());
Serial.print(" dBm SNR: ");
Serial.println(LoRa.packetSnr());
}
}
Raspberry Pi (Python)
#!/usr/bin/env python3
# Ra-02 SX1278 - Raspberry Pi LoRa receiver (pyLoRa)
# Install: pip3 install pyLoRa spidev RPi.GPIO
# Wiring: NSS->CE0, RESET->GPIO22, DIO0->GPIO24 (BOARD mode in lib config)
from SX127x.LoRa import LoRa
from SX127x.board_config import BOARD
import time
BOARD.setup()
class Receiver(LoRa):
def __init__(self):
super(Receiver, self).__init__(verbose=False)
self.set_mode(0x80) # sleep, LoRa mode
self.set_freq(433.0)
self.set_spreading_factor(9)
self.set_bw(7) # 7 = 125 kHz
self.set_sync_word(0x12)
self.set_rx_crc(True)
def on_rx_done(self):
payload = self.read_payload(nocheck=True)
text = bytes(payload).decode(errors="ignore")
print("Received: '{}' RSSI: {} dBm".format(
text, self.get_pkt_rssi_value()))
self.set_mode(0x85) # back to RX continuous
lora = Receiver()
print("LoRa receiver ready (433 MHz, SF9)")
lora.set_mode(0x85) # RX continuous
try:
while True:
time.sleep(0.5)
except KeyboardInterrupt:
BOARD.teardown()
print("Stopped by user")
Raspberry Pi Pico (MicroPython)
# Ra-02 SX1278 - Pico MicroPython sender
# Driver: copy sx127x.py from the micropython-lora project
# (github.com/martynwheeler/u-lora or similar sx127x.py) to the Pico
# Wiring: SCK=GP2, MOSI=GP3, MISO=GP4, NSS=GP5, RESET=GP6, DIO0=GP7
from machine import Pin, SPI
from sx127x import SX127x
import time
lora_cfg = {
"frequency": 433E6,
"spreading_factor": 9,
"signal_bandwidth": 125E3,
"tx_power_level": 17,
"sync_word": 0x12,
}
spi = SPI(0, baudrate=5_000_000,
sck=Pin(2), mosi=Pin(3), miso=Pin(4))
lora = SX127x(spi,
pins={"ss": 5, "reset": 6, "dio_0": 7},
parameters=lora_cfg)
counter = 0
print("LoRa sender ready (433 MHz, SF9)")
while True:
msg = "Pico #{}".format(counter)
print("Sending:", msg)
lora.println(msg)
counter += 1
time.sleep(2)