LoRa Sending Function takes 2 seconds and cause issue

My problem is that the sending function I use to send data through LoRa consumes about 2 seconds with a spreading factor of 7 and the node is close to the gateway, that time interferes with my estimation of the beats per minute (bpm) which is the variable we want to send through LoRa given we we need to know the elapsed time between two beats, if there is a delay between them due to LoRa functions since we can not get a correct result of the BPM

A possible solution could be using a thread where the bpm algorithm is executed all the time and sending though lora in another thread but I am using an Arduino where this is not possible (Sodaq One V3)

Our code is:

#include <Arduino.h>
#include "CayenneLPP.h"
#include <Sodaq_RN2483.h>
#include <Sodaq_UBlox_GPS.h>
#include "ArduinoLowPower.h"
#include "heartRate.h"
#include "MAX30105.h"
#define debugSerial SERIAL_PORT_MONITOR

#if defined(ARDUINO_AVR_SODAQ_MBILI)
#define loraSerial Serial1
#define BEE_VCC 20

#elif defined(ARDUINO_SODAQ_AUTONOMO) || defined(ARDUINO_SODAQ_ONE) || defined(ARDUINO_SODAQ_ONE_BETA)
#define loraSerial Serial1

#elif defined(ARDUINO_SODAQ_EXPLORER)
#define loraSerial Serial2

#else
// please select a sodaq board
debugSerial.println("Please select a sodaq board!!");
#endif
CayenneLPP data(51);
float lat = 56.0441087;
float lon = -90.9716481;
MAX30105 particleSensor;

const byte RATE_SIZE = 4; // Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE];	  // Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; // Time at which the last beat occurred

float beatsPerMinute;
int beatAvg;

// OTAA

// 0c13321786b9c36f272e7cbdbef2cd71 0004A30B0022F78C
// sodaq 2  0004A30B0022f78c, 0004A30B00228B3B
uint8_t DevEUI[8] = {0x00, 0x04, 0xA3, 0x0B, 0x00, 0x22, 0xF7, 0x8C};
uint8_t AppEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t AppKey[16] = {0x0C, 0x13, 0x32, 0x17, 0x86, 0xb9, 0xc3, 0x6f, 0x27, 0x2e, 0x7c, 0xbd, 0xbe, 0xf2, 0xcd, 0x71};

void setupLoRaOTAA()
{
	if (LoRaBee.initOTA(loraSerial, DevEUI, AppEUI, AppKey, true))
	{
		debugSerial.println("Communication to LoRaBEE successful.");
	}
	else
	{
		debugSerial.println("OTAA Setup failed!");
	}
}
void setupLoRa()
{
	long start = millis();
	setupLoRaOTAA();
	LoRaBee.setSpreadingFactor(7);
	long end = millis();
	debugSerial.println((end - start) / 1000);
}

void setup()
{
// Power up the LoRaBEE
#if defined(ARDUINO_AVR_SODAQ_MBILI) || defined(ARDUINO_SODAQ_AUTONOMO)
	pinMode(BEE_VCC, OUTPUT);
	digitalWrite(BEE_VCC, HIGH);
#endif
	delay(3000);

	while ((!SerialUSB) && (millis() < 10000))
	{
		// Wait 10 seconds for the Serial Monitor
	}

	// Set baud rate
	debugSerial.begin(57600);
	loraSerial.begin(LoRaBee.getDefaultBaudRate());
	// LoRaBee.setDiag(debugSerial);
	//  sodaq_gps.init(GPS_ENABLE);
	setupLoRa();
	if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) // Use default I2C port, 400kHz speed
	{
		while (1)
			;
	}

	particleSensor.setup();					   // Configure sensor with default settings
	particleSensor.setPulseAmplitudeRed(0x0A); // Turn Red LED to low to indicate sensor is running
	particleSensor.setPulseAmplitudeGreen(0);  // Turn off Green LED
	debugSerial.println("Starting");
}

void sendPacket(CayenneLPP &packet)
{
	switch (LoRaBee.send(1, packet.getBuffer(), packet.getSize()))
	{
	case NoError:
		debugSerial.println("Successful transmission.");
		break;
	case NoResponse:
		debugSerial.println("There was no response from the device.");
		setupLoRa();
		break;
	case Timeout:
		debugSerial.println("Connection timed-out. Check your serial connection to the device! Sleeping for 20sec.");
		delay(20000);
		break;
	case PayloadSizeError:
		debugSerial.println("The size of the payload is greater than allowed. Transmission failed!");
		break;
	case InternalError:
		setupLoRa();
		break;
	case Busy:
		delay(10000);
		break;
	case NetworkFatalError:
		setupLoRa();
		break;
	case NotConnected:
		setupLoRa();
		break;
	case NoAcknowledgment:
		debugSerial.println("There was no acknowledgment sent back!");
		break;
	default:
		break;
	}
}

void loop()
{
	//obteniendo bpm
	long irValue = particleSensor.getIR();

	if (checkForBeat(irValue) == true)
	{
		// We sensed a beat!
		long delta = millis() - lastBeat;
		lastBeat = millis();

		beatsPerMinute = 60 / (delta / 1000.0);

		if (beatsPerMinute < 255 && beatsPerMinute > 20)
		{
			rates[rateSpot++] = (byte)beatsPerMinute; // Store this reading in the array
			rateSpot %= RATE_SIZE;					  // Wrap variable

			// Take average of readings
			beatAvg = 0;
			for (byte x = 0; x < RATE_SIZE; x++)
				beatAvg += rates[x];
			beatAvg /= RATE_SIZE;
		}
	}
	//fin
	data.reset();
	/*
		if (sodaq_gps.scan(true))
		{
			lat = sodaq_gps.getLat();
		lon = sodaq_gps.getLon();
		}
	*/
	data.addGPS(1, lat, lon, 0);
	data.addAnalogInput(2, beatsPerMinute);
	// auto start = millis();
	sendPacket(data); //delay de aprox 2s con sf 7

	// auto end = millis();
	// debugSerial.println((end - start) / 1000);
	// LoRaBee.sleep();
	// LowPower.sleep(1000);
	// LoRaBee.wakeUp();
}

I was thinking on changing the sensor for a PulseSensor (https://pulsesensor.com/) since I read it works pretty different, realizing I need to read an analog signal and I do not have to get the inifity loop but still reading.

If you could help me with your experience and advise, I would appreciate it so much! Also I hope this could help for other people trying to work something similar

Separate the two functions. Measure BPM, then send the data. Repeat.

1 Like

thank you so much for your response jremington, I actually tried to do it but no succed since the algorithm of the bpm does not give me a correct value :frowning:

You can use esp32 and work with the two cores

1 Like

The first step is to learn to read the BPM sensor and get reasonable values. A different and unrelated step is to learn how to send some data.

When you have both of those working independently and correctly, combine the code into one functional package.

That is something I was reading, thank you so much for your help megadrive, i will try it!!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.