Hello everyone,
I’m working on a project involving half-duplex LoRa communication between a Raspberry Pi and an Arduino Nano 33 IoT using RFM9x modules. My goal is to send a command from the Raspberry Pi to the Arduino, which will then switch to a mode where it sends data back to the Raspberry Pi. but im encountering an issue shown in the image.
if there is anything i can fix please let me know thank you
Project Details:
- Hardware Setup:
- Arduino Nano 33 IoT with LoRa module (RFM9x).
- Raspberry Pi with LoRa module (RFM9x).
- Connections:
- Arduino Nano 33 IoT: CS pin - 4, Reset pin - 2, IRQ pin - 3.
- Raspberry Pi: CS - CE1, Reset - D25.
- Objective:
- Raspberry Pi: Send a command ("SEND_DATA") to the Arduino.
- Arduino: Receive the command and switch to send mode to transmit data back to the Raspberry Pi.
- Half-Duplex Communication: Ensure the devices switch between sending and receiving modes correctly.
#include <SPI.h>
#include <LoRa.h>
const int csPin = 4; // LoRa radio chip select
const int resetPin = 2; // LoRa radio reset
const int irqPin = 3; // change for your board; must be a hardware interrupt pin
byte msgCount = 0; // count of outgoing messages
byte localAddress = 0xAB; // address of this device
byte destination = 0xBA; // destination to send to
bool sendMode = false; // flag to indicate send mode
long sendModeStart = 0; // timestamp for send mode start
int sendModeDuration = 5000; // send mode duration in milliseconds
void setup() {
Serial.begin(9600); // initialize serial
while (!Serial);
Serial.println("LoRa Duplex");
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH);
// override the default CS, reset, and IRQ pins (optional)
LoRa.setPins(csPin, resetPin, irqPin); // set CS, reset, IRQ pin
if (!LoRa.begin(915E6)) { // initialize radio at 915 MHz
Serial.println("LoRa init failed. Check your connections.");
while (true); // if failed, do nothing
}
LoRa.onReceive(onReceive); // register the receive callback
LoRa.receive(); // go into receive mode
Serial.println("LoRa init succeeded.");
}
void loop() {
if (sendMode && (millis() - sendModeStart > sendModeDuration)) {
sendMode = false;
LoRa.receive(); // go back into receive mode
Serial.println("Switched back to receive mode after timeout.");
}
if (sendMode) {
String message = "Hello from Arduino to 0xBA!"; // send a message
sendMessage(message);
Serial.println("Sending " + message);
// Immediately switch back to receive mode after sending
LoRa.receive();
sendMode = false;
Serial.println("Switched back to receive mode after sending message.");
}
}
void sendMessage(String outgoing) {
LoRa.beginPacket(); // start packet
LoRa.write(destination); // add destination address
LoRa.write(localAddress); // add sender address
LoRa.write(msgCount); // add message ID
LoRa.write(outgoing.length()); // add payload length
LoRa.print(outgoing); // add payload
LoRa.endPacket(); // finish packet and send it
msgCount++; // increment message ID
// Ensure the LoRa module is switched back to receive mode
LoRa.receive();
}
void onReceive(int packetSize) {
if (packetSize == 0) return; // if there's no packet, return
// read packet header bytes:
int recipient = LoRa.read(); // recipient address
byte sender = LoRa.read(); // sender address
byte incomingMsgId = LoRa.read(); // incoming msg ID
byte incomingLength = LoRa.read(); // incoming msg length
// print header for debugging
Serial.print("Recipient: ");
Serial.println(recipient, HEX);
Serial.print("Sender: ");
Serial.println(sender, HEX);
Serial.print("Message ID: ");
Serial.println(incomingMsgId, HEX);
Serial.print("Payload length: ");
Serial.println(incomingLength, HEX);
String incoming = "";
while (LoRa.available()) {
char receivedChar = (char)LoRa.read();
Serial.print("Received char: ");
Serial.println(receivedChar, HEX); // Print each received character
incoming += receivedChar;
}
// print the received message and its bytes for debugging
Serial.print("Received message: ");
Serial.println(incoming);
Serial.print("Received bytes: ");
for (int i = 0; i < incoming.length(); i++) {
Serial.print((uint8_t)incoming[i], HEX); // Print as hexadecimal values
Serial.print(" ");
}
Serial.println();
// Check if the received message length matches the expected length
if (incomingLength != incoming.length()) {
Serial.println("error: message length does not match length");
Serial.print("Expected length: ");
Serial.println(incomingLength);
Serial.print("Actual length: ");
Serial.println(incoming.length());
return; // skip rest of function
}
// if the recipient isn't this device or broadcast,
if (recipient != localAddress && recipient != 0xFF) {
Serial.println("This message is not for me.");
return; // skip rest of function
}
// handle the received command to switch modes
if (incoming == "245") {
sendMode = true;
sendModeStart = millis();
Serial.println("Switched to send mode.");
} else if (incoming == "246") {
sendMode = false;
LoRa.receive(); // go back into receive mode
Serial.println("Switched to receive mode.");
} else {
Serial.println("Unrecognized command. Staying in current mode.");
}
// send acknowledgment
sendMessage("ACK");
}
import time
import board
import busio
import digitalio
import adafruit_rfm9x
# Define radio parameters
RADIO_FREQ_MHZ = 915.0 # Frequency of the radio in MHz. 868.0 MHz in Europe, 915.0 MHz in North America.
CS = digitalio.DigitalInOut(board.CE1)
RESET = digitalio.DigitalInOut(board.D25)
# Initialize SPI bus
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
# Initialize RFM9x radio
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)
msg_count = 0
def send_command(command):
global msg_count
destination = 0xAB # Arduino address
sender = 0xBB # Raspberry Pi address
payload_length = 1 # Fixed payload length for simplicity
command_bytes = bytes([destination, sender, msg_count, payload_length, command])
print(f"Command bytes: {command_bytes}")
ack_received = False
while not ack_received:
rfm9x.send(command_bytes)
print(f"Sent command to 0x{destination:X}: {command}")
# Switch to receive mode and wait for acknowledgment
start_time = time.time()
print("Switching to receive mode...")
while time.time() - start_time < 2: # Receive for 2 seconds
packet = rfm9x.receive(with_header=True)
if packet is not None:
print(f"Received raw packet: {packet}")
recipient = packet[0]
ack_sender = packet[1]
msg_id = packet[2]
length = packet[3]
message = packet[4:].decode('utf-8', errors='ignore')
print(f"Recipient: 0x{recipient:X}, Sender: 0x{ack_sender:X}, Msg ID: {msg_id}, Length: {length}, Message: {message}")
if recipient == sender and message == "ACK":
print("Acknowledgment received")
ack_received = True
break
time.sleep(1)
msg_count += 1
if __name__ == "__main__":
while True:
send_command(245) # Command Arduino to read its address
time.sleep(10) # Wait for some time before sending the next command