A bit of context, I am participating in the UK CanSat competition. I am sorting out the communication between the CanSat and the ground station. We are using LoRa transceivers as required per the competition. We are using a raspberry pi pico as a emitter and an Arduino nano in the ground station as a receiver. The LoRa module we are using is this one.
Long story short, when I receive the message in the ground station, there are multiple symbols, here is a picture:
Here is the code for the Arduino (receiver):
// Arduino9x_RX
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messaging client (receiver)
// with the RH_RF95 class. RH_RF95 class does not provide for addressing or
// reliability, so you should only use RH_RF95 if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example Arduino9x_TX
#include <SPI.h>
#include <RH_RF95.h>
#define RFM95_CS 10
#define RFM95_RST 9
#define RFM95_INT 2
// Change to .0 or other frequency, must match RX's freq!
#define RF95_FREQ 433.0
// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);
// Blinky on receipt
#define LED 13
void setup() {
pinMode(LED, OUTPUT);
pinMode(RFM95_RST, OUTPUT);
digitalWrite(RFM95_RST, HIGH);
while (!Serial);
Serial.begin(9600);
delay(100);
Serial.println("Arduino LoRa RX Test!");
// manual reset
digitalWrite(RFM95_RST, LOW);
delay(10);
digitalWrite(RFM95_RST, HIGH);
delay(10);
while (!rf95.init()) {
Serial.println("LoRa radio init failed");
while (1);
}
Serial.println("LoRa radio init OK!");
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
if (!rf95.setFrequency(RF95_FREQ)) {
Serial.println("setFrequency failed");
while (1);
}
Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
// Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
// The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
rf95.setTxPower(23, false);
}
void loop() {
if (rf95.available()) {
// Should be a message for us now
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
//char buf = (char*)buf;
uint8_t len = sizeof(buf);
if (rf95.recv(buf, &len)) {
digitalWrite(LED, HIGH);
Serial.print("Got: ");
Serial.println((char*)buf);
Serial.print("RSSI: ");
Serial.println(rf95.lastRssi(), DEC);
} else {
return;
}
}
}
Disclaimer this code was extracted from the internet.
And here is the code for the Raspberry pi pico (emitter):
import board
import busio
import time
import digitalio
import adafruit_rfm9x
import adafruit_bmp280
"Led configuration"
# Led amarillo
ledambar = digitalio.DigitalInOut(board.GP16)
ledambar.direction = digitalio.Direction.OUTPUT
# Led azul
ledazul = digitalio.DigitalInOut(board.GP17)
ledazul.direction = digitalio.Direction.OUTPUT
"LoRa"
# LoRa radio setup
spi = busio.SPI(clock=board.GP2, MOSI=board.GP3, MISO=board.GP4)
cs = digitalio.DigitalInOut(board.GP6)
reset = digitalio.DigitalInOut(board.GP7)
rfm9x = adafruit_rfm9x.RFM9x(spi, cs, reset, 433.0)
print("RFM9x radio ready")
"Not LoRa from here"
"BMP280 Sensor"
# BMP280 comunication start up
i2c = busio.I2C(scl=board.GP15, sda=board.GP14)
bmp280_sensor = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, address=0x76)
# BMP280 sensor readings
def read_temperature():
return bmp280_sensor.temperature
def read_pressure():
return bmp280_sensor.pressure
while True:
ledazul.value = True
"LoRa"
rfm9x.send("Hello World, this is a test, why does this not work? im going mad!!!!")
print("Radio mensage sent")
"Not LoRa from here"
ledazul.value = False
cansat_temperature = read_temperature()
print("TEMPERATURE:")
print(cansat_temperature)
cansat_pressure = read_pressure()
print("PRESSURE:")
print(cansat_pressure)
print(" ")
time.sleep(2.5)
Disclaimer, this code is designed to do more things than just LoRa communication. The LoRa part of the code is below the tag: "LoRa".
If you have any recommendations on how to improve my code in any way, just let me know, it would be really helpful.
Thank you.
I have tried soldering the antennas, changing them, modifying the code, both in the pico and the Arduino, also tried changing the antennas but nothing worked.
You have a buffer over-read - a major security flaw, same as the infamous Heartbleed bug.
When you pass a char *
to Serial.println
, it will print the data until it finds a null character. Your python string does not contain such null termination, so the the print function keeps going through the memory until it finds one. You were lucky that it found one quite quickly. It could also go on much longer, depending on what is in the memory at that time.
A naive way to fix the issue would be to just append a null character to the python string:
rfm9x.send("Hello World, this is a test, why does this not work? im going mad!!!!\0")
However, if you were to receive partial data (or someone forgot to add a null character), the issue would reappear.
The proper way to fix the problem is to check how much data is received and only print that much. According to the documentation, the received number of octets is stored in the len
parameter. Therefore, you can add null-termination on the receiving end like so:
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
// Leave space for null-termination
uint8_t len = sizeof(buf) - 1;
if (rf95.recv(buf, &len))
{
// Add null-termination at the end of the received data.
buf[len] = '\0';
// Print as before.
digitalWrite(LED, HIGH);
Serial.print("Got: ");
Serial.println((char*)buf);
Serial.print("RSSI: ");
Serial.println(rf95.lastRssi(), DEC);
}