Init fork from Stuart Robinson's repo

This commit is contained in:
2024-10-03 14:30:13 +03:00
commit 9395706524
201 changed files with 45709 additions and 0 deletions

View File

@ -0,0 +1,427 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 18/04/22
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This is a demonstration of the transmission and acknowledgement of 'Reliable'
packets to request information or operations from a remote receiver.
A reliable packet has 4 bytes automatically appended to the end of the buffer\array that is the data
payload. The first two bytes appended are a 16bit 'NetworkID'. The receiver needs to have the same
NetworkID as configured for the transmitter since the receiver program uses the NetworkID to check that
the received packet is from a known source. The third and fourth bytes appended are a 16 bit CRC of
the payload. The receiver will carry out its own CRC check on the received payload and can then verify
this against the CRC appended in the packet. The receiver is thus able to check if the payload is valid.
The transmitter sends a request for the receiver which will respond with an acknowledge whach can include
any data requested. The transmitted request is a total of 6 or more bytes, with one byte for the payload
type and another byte for station the request is directed to.
Two types af request are demonstrated here. The first request is for the receiver to return a set of GPS
co-ordinates. This information is included in the acknowledge the receiver sends if there is a match for
request type and station number. The orginal network ID and payload CRC are also returned with the
acknowledge so the transmitter can verify if the packet it receives in reply is geniune.
The second request is for the receiver to go into ranging (distance measurment) mode. The period for the
receiver to stay in ranging mode goes out with the request sent by the transmitter. The transmitter then
goes into ranging mode and measures the distance between transmitter (master) and receiver (slave).
The matching receiver program is 224_Ranging_Receiver_Data_Requestor.
Serial monitor baud rate should be set at 115200.
*******************************************************************************************************/
#include <SPI.h> //the LoRa device is SPI based so load the SPI library
#include <SX128XLT.h> //include the appropriate library
#include "Settings.h"
SX128XLT LT; //create a library class instance called LT
uint8_t TXPacketL; //length of transmitted packet
uint8_t TXPayloadL;
uint8_t RXPayloadL;
uint8_t RXPacketL; //length of received acknowledge
uint16_t PayloadCRC;
uint8_t RXBUFFER[16]; //create the buffer that received packets are copied into
uint8_t RequestType; //type of request to send
uint8_t RequestStation; //station request is aimed at
float Latitude; //variables for GPS location
float Longitude;
float Altitude;
uint8_t TrackerStatus;
//#define DEBUG
void loop()
{
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
//*****************************************************************************************
//Request GPS location
//*****************************************************************************************
RequestStation = 123;
if (sendRequestGPSLocation(RequestStation, 5))
{
Serial.println(F("Valid ACK received"));
#ifdef DEBUG
packet_is_OK();
#endif
Serial.println();
actionRequestGPSLocation();
}
else
{
Serial.println(F("No valid ACK received"));
}
Serial.println();
Serial.println();
delay(1000);
//*****************************************************************************************
//*****************************************************************************************
//Request ranging operation
//*****************************************************************************************
RequestStation = 123;
if (sendRequestRanging(RequestStation, 5)) //send request for station 123, make 5 attempts
{
Serial.println(F("Valid ACK received"));
#ifdef DEBUG
packet_is_OK();
#endif
Serial.println();
//note that RequestStation = the ranging address
actionRanging(RequestStation, RangingCount, RangingTimeoutmS, RangingTXPower);
}
else
{
Serial.println(F("No valid ACK received"));
}
Serial.println();
delay(5000);
//*****************************************************************************************
}
uint8_t sendRequestGPSLocation(uint8_t station, uint8_t sendcount)
{
uint8_t ackrequesttype;
uint8_t ackstation;
uint8_t startcount;
startcount = sendcount;
do
{
Serial.print(startcount - sendcount + 1);
Serial.print(F(" Transmit request"));
printRequestType(RequestGPSLocation);
Serial.print(F(" to station "));
Serial.println(station);
Serial.flush();
//build the request payload
LT.startWriteSXBuffer(0); //initialise SX buffer write at address 0
LT.writeUint8(RequestGPSLocation); //identify type of request
LT.writeUint8(station); //station to reply to request
TXPayloadL = LT.endWriteSXBuffer(); //close SX buffer write
//now transmit the request
digitalWrite(LED1, HIGH);
TXPacketL = LT.transmitSXReliable(0, TXPayloadL, NetworkID, TXtimeout, TXpower, WAIT_TX);
digitalWrite(LED1, LOW);
PayloadCRC = LT.getTXPayloadCRC(TXPacketL);
RXPacketL = LT.waitSXReliableACK(0, NetworkID, PayloadCRC, ACKtimeout);
if (RXPacketL > 0)
{
//if waitSXReliableACK() returns > 0 then valid ack was received
ackrequesttype = LT.getByteSXBuffer(0);
ackstation = LT.getByteSXBuffer(1);
if ((ackrequesttype == RequestGPSLocation) && (ackstation == station))
{
return RXPacketL;
}
delay(200); //small delay between tranmission attampts
}
sendcount--;
}
while ((RXPacketL == 0) && (sendcount > 0));
Serial.println(F("ERROR send request failed"));
return 0;
}
uint8_t sendRequestRanging(uint8_t station, uint8_t sendcount)
{
uint8_t ackrequesttype;
uint8_t ackstation;
uint8_t startcount;
startcount = sendcount;
do
{
Serial.print(startcount - sendcount + 1);
Serial.print(F(" Transmit request"));
printRequestType(RequestRanging);
Serial.print(F(" to station "));
Serial.println(station);
Serial.flush();
//build the request payload
LT.startWriteSXBuffer(0); //initialise SX buffer write at address 0
LT.writeUint8(RequestRanging); //identify type of request
LT.writeUint8(station); //station to reply to request
LT.writeUint32(RangingUpTimemS); //time for slave to stay in ranging listen
TXPayloadL = LT.endWriteSXBuffer(); //close SX buffer write
//now transmit the request
digitalWrite(LED1, HIGH);
TXPacketL = LT.transmitSXReliable(0, TXPayloadL, NetworkID, TXtimeout, TXpower, WAIT_TX);
digitalWrite(LED1, LOW);
PayloadCRC = LT.getTXPayloadCRC(TXPacketL);
RXPacketL = LT.waitSXReliableACK(0, NetworkID, PayloadCRC, ACKtimeout);
if (RXPacketL > 0)
{
//if waitSXReliableACK() returns > 0 then valid ack was received
ackrequesttype = LT.getByteSXBuffer(0);
ackstation = LT.getByteSXBuffer(1);
if ((ackrequesttype == RequestRanging) && (ackstation == station))
{
return RXPacketL;
}
delay(200); //small delay between tranmission attampts
}
sendcount--;
}
while ((RXPacketL == 0) && (sendcount > 0));
Serial.println(F("ERROR send request failed"));
return 0;
}
void printRequestType(uint8_t type)
{
switch (type)
{
case 1:
Serial.print(F(" RequestGPSLocation"));
break;
case 2:
Serial.print(F(" RequestRanging"));
break;
default:
Serial.print(F(" not recognised"));
break;
}
}
void actionRequestGPSLocation()
{
LT.startReadSXBuffer(0); //initialise SX buffer write at address 0
RequestType = LT.readUint8(); //read type of request
RequestStation = LT.readUint8(); //who is the request reply from
Latitude = LT.readFloat(); //read latitude
Longitude = LT.readFloat(); //read longitude
Altitude = LT.readFloat(); //read altitude
TrackerStatus = LT.readUint8(); //read status byte
RXPayloadL = LT.endReadSXBuffer(); //close SX buffer read
Serial.print(F("RequestGPSLocation reply > "));
Serial.print(RequestStation);
Serial.print(F(","));
Serial.print(Latitude, 6);
Serial.print(F(","));
Serial.print(Longitude, 6);
Serial.print(F(","));
Serial.print(Altitude, 1);
Serial.print(F(","));
Serial.print(TrackerStatus);
Serial.println();
}
void actionRanging(uint32_t rangingaddress, uint8_t number, uint32_t timeout, int8_t txpower)
{
uint8_t index;
uint16_t rangeings_valid = 0;
float distance_sum = 0;
int16_t RangingRSSI;
uint16_t rangeing_errors = 0;
uint16_t rangeing_results = 0;
uint16_t IrqStatus;
uint32_t range_result_sum = 0;
uint32_t range_result_average;
float distance;
float distance_average;
int32_t range_result;
Serial.print(F("Ranging address "));
Serial.println(rangingaddress);
Serial.flush();
LT.setupRanging(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, rangingaddress, RANGING_MASTER);
LT.setRangingCalibration(Calibration); //override automatic lookup of calibration value from library table
for (index = 1; index <= number; index++)
{
Serial.print(F("Ranging attempt "));
Serial.println(index);
digitalWrite(LED1, HIGH);
LT.transmitRanging(rangingaddress, timeout, txpower, WAIT_TX);
digitalWrite(LED1, LOW);
IrqStatus = LT.readIrqStatus();
if (IrqStatus & IRQ_RANGING_MASTER_RESULT_VALID)
{
rangeing_results++;
rangeings_valid++;
digitalWrite(LED1, HIGH);
Serial.print(F("RangingValid"));
range_result = LT.getRangingResultRegValue(RANGING_RESULT_RAW);
#ifdef DEBUG
Serial.print(F(",RAWRegisterValue,"));
Serial.print(range_result);
Serial.print(F(","));
#endif
if (range_result > 800000)
{
range_result = 0;
}
range_result_sum = range_result_sum + range_result;
distance = LT.getRangingDistance(RANGING_RESULT_RAW, range_result, DistanceAdjustment);
distance_sum = distance_sum + distance;
Serial.print(F("Distance,"));
Serial.print(distance, 1);
RangingRSSI = LT.getRangingRSSI();
Serial.print(F(",RSSI,"));
Serial.print(RangingRSSI);
Serial.print(F("dBm"));
digitalWrite(LED1, LOW);
}
else
{
rangeing_errors++;
distance = 0;
range_result = 0;
Serial.print(F("ERROR not valid"));
LT.printIrqStatus();
}
delay(PacketDelaymS);
if (index == number)
{
range_result_average = (range_result_sum / rangeing_results);
if (rangeing_results == 0)
{
distance_average = 0;
}
else
{
distance_average = (distance_sum / rangeing_results);
}
Serial.println();
Serial.print(F("TotalValid,"));
Serial.print(rangeings_valid);
Serial.print(F(",TotalErrors,"));
Serial.print(rangeing_errors);
Serial.print(F(",AverageRAWResult,"));
Serial.print(range_result_average);
Serial.print(F(",AverageDistance,"));
Serial.print(distance_average, 1);
Serial.flush();
}
Serial.println();
}
}
void packet_is_OK()
{
Serial.print(F("LocalNetworkID,0x"));
Serial.print(NetworkID, HEX);
Serial.print(F(",TransmittedPayloadCRC,0x")); //print CRC of transmitted packet
Serial.print(PayloadCRC, HEX);
}
void packet_is_Error()
{
Serial.print(F("SendError"));
LT.printIrqStatus(); //prints the text of which IRQs set
LT.printReliableStatus(); //print the reliable status
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT);
led_Flash(2, 125); //two quick LED flashes to indicate program start
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
SPI.begin();
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
Serial.println(F("LoRa Device found"));
led_Flash(2, 125); //two further quick LED flashes to indicate device found
}
else
{
Serial.println(F("ERROR No LoRa device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed LED flash indicates device error
}
}
Serial.println(F("Transmitter ready"));
Serial.println();
}

View File

@ -0,0 +1,39 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 18/04/22
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
const uint8_t NSS = 10; //select pin on LoRa device
const uint8_t NRESET = 9; //reset pin on LoRa device
const uint8_t RFBUSY = 7; //busy pin on LoRa device
const uint8_t DIO1 = 3; //DIO1 pin on LoRa device, used for sensing RX and TX done
const uint8_t LORA_DEVICE = DEVICE_SX1280; //we need to define the device we are using
const uint8_t LED1 = 8;
//******* Setup LoRa modem parameters here ! ***************
const uint32_t Frequency = 2445000000; //frequency of transmissions
const uint32_t Offset = 0; //offset frequency for calibration purposes
const int8_t TXpower = 2; //LoRa transmit power
const uint8_t Bandwidth = LORA_BW_0800; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint16_t NetworkID = 0x3210; //NetworkID identifies this connection, needs to match value in transmitter
const uint8_t RequestGPSLocation = 1; //request type number for GPS location, so receiver knows what information to supply
const uint8_t RequestRanging = 2; //request type number for ranging
const uint32_t ACKtimeout = 1000; //Acknowledge timeout in mS, set to 0 if ACK not used.
const uint32_t TXtimeout = 1000; //transmit timeout in mS. If 0 return from transmit function after send.
const int8_t RangingTXPower = 10; //Ranging transmit power used
const uint16_t RangingTimeoutmS = 1000; //ranging master timeout in mS, time master waits for a reply
const uint16_t RangingUpTimemS = 2000; //time for slave to stay in ranging listen
const uint16_t PacketDelaymS = 0; //forced extra delay in mS between sending packets
const uint16_t RangingCount = 3; //number of times ranging is carried out for each distance measurment
const float DistanceAdjustment = 1.0000; //adjustment factor to calculated distance
const uint16_t Calibration = 11350; //Manual Ranging calibration value

View File

@ -0,0 +1,322 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 17/04/22
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This is a demonstration of the transmission and acknowledgement of 'Reliable'
packets to request information or operations from a remote receiver.
A reliable packet has 4 bytes automatically appended to the end of the buffer\array that is the data
payload. The first two bytes appended are a 16bit 'NetworkID'. The receiver needs to have the same
NetworkID as configured for the transmitter since the receiver program uses the NetworkID to check that
the received packet is from a known source. The third and fourth bytes appended are a 16 bit CRC of
the payload. The receiver will carry out its own CRC check on the received payload and can then verify
this against the CRC appended in the packet. The receiver is thus able to check if the payload is valid.
The transmitter sends a request for the receiver which will respond with an acknowledge whach can include
any data requested. The transmitted request is a total of 6 or more bytes, with one byte for the payload
type and another byte for station the request is directed to.
Two types af request are demonstrated here. The first request is for the receiver to return a set of GPS
co-ordinates. This information is included in the acknowledge the receiver sends if there is a match for
request type and station number. The orginal network ID and payload CRC are also returned with the
acknowledge so the transmitter can verify if the packet it receives in reply is geniune.
The second request is for the receiver to go into ranging (distance measurment) mode. The period for the
receiver to stay in ranging mode goes out with the request sent by the transmitter. The transmitter then
goes into ranging mode and measures the distance between transmitter (master) and receiver (slave).
The matching transmitter program is 224_Ranging_transmitter_Data_Requestor.
Serial monitor baud rate should be set at 115200.
*******************************************************************************************************/
#include <SPI.h> //the LoRa device is SPI based so load the SPI library
#include <SX128XLT.h> //include the appropriate library
#include "Settings.h"
SX128XLT LT; //create a library class instance called LT
uint8_t RXBUFFER[251]; //create the buffer that received packets are copied into
uint8_t RXPacketL; //stores length of packet received
uint8_t RXPayloadL; //stores length of payload received
uint8_t TXPayloadL; //stores length of payload sent
uint16_t TransmitterNetworkID; //the NetworkID from the transmitted and received packet
uint16_t StationNumber;
uint8_t RequestType;
//#define DEBUG
void loop()
{
uint8_t requesttype;
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate); //need to be in LoRa mode to receiv requests
requesttype = waitRequest(ThisStation, 5000); //listen for 5000mS, will return 0 if there is no request
switch (requesttype)
{
case 0:
break;
case RequestGPSLocation:
actionRequestGPSLocation();
break;
case RequestRanging:
actionRanging(ThisStation);
break;
default:
Serial.println(F("Request not recognised"));
break;
}
Serial.println();
}
uint8_t waitRequest(uint8_t station, uint32_t timeout)
{
//wait for an incoming request, returns 0 if no request in timeout period
Serial.println(F("Wait request"));
RXPacketL = LT.receiveSXReliable(0, NetworkID, timeout, WAIT_RX);
if (RXPacketL)
{
#ifdef DEBUG
Serial.print(F("Reliable packet received > "));
packet_is_OK();
#endif
RequestType = LT.getByteSXBuffer(0);
StationNumber = LT.getByteSXBuffer(1);
Serial.print(F("Received "));
printRequestType(RequestType);
Serial.print(F(" for station "));
Serial.println(StationNumber);
if (StationNumber == station)
{
return RequestType;
}
else
{
Serial.println(F("ERROR Request not for this station"));
}
}
else
{
if (LT.readIrqStatus() & IRQ_RX_TIMEOUT)
{
Serial.println(F("ERROR Timeout waiting for valid request"));
}
else
{
packet_is_Error();
}
}
return 0;
}
bool actionRequestGPSLocation()
{
uint16_t RXPayloadCRC;
RXPayloadCRC = LT.getRXPayloadCRC(RXPacketL); //fetch received payload crc to return with ack
LT.startWriteSXBuffer(0); //initialise SX buffer write at address 0
LT.writeUint8(RequestGPSLocation); //identify type of request
LT.writeUint8(ThisStation); //who is the request reply from
LT.writeFloat(TestLatitude); //add latitude
LT.writeFloat(TestLongitude); //add longitude
LT.writeFloat(TestAltitude); //add altitude
LT.writeUint8(TrackerStatus); //add status byte
TXPayloadL = LT.endWriteSXBuffer(); //close SX buffer write
delay(ACKdelay);
digitalWrite(LED1, HIGH);
LT.sendSXReliableACK(0, TXPayloadL, NetworkID, RXPayloadCRC, TXpower);
Serial.print(F("RequestGPSLocation Replied > "));
Serial.print(ThisStation);
Serial.print(F(","));
Serial.print(TestLatitude, 6);
Serial.print(F(","));
Serial.print(TestLongitude, 6);
Serial.print(F(","));
Serial.print(TestAltitude, 1);
Serial.print(F(","));
Serial.print(TrackerStatus);
Serial.println();
Serial.flush();
digitalWrite(LED1, LOW);
return true;
}
void actionRanging(uint32_t rangingaddress)
{
uint16_t IrqStatus;
uint16_t RangingUpTimemS;
uint16_t RXPayloadCRC;
uint32_t startmS;
LT.startReadSXBuffer(2); //initialise SX buffer write at location 2
RangingUpTimemS = LT.readUint16(); //the ranging listen time was sent with request.
LT.endReadSXBuffer();
Serial.print("RangingUpTimemS ");
Serial.println(RangingUpTimemS);
RXPayloadCRC = LT.getRXPayloadCRC(RXPacketL); //fetch received payload crc to return with ack
LT.startWriteSXBuffer(0); //initialise SX buffer write at address startaddr
LT.writeUint8(RequestRanging); //identify type of request
LT.writeUint8(ThisStation); //who is the request reply from
TXPayloadL = LT.endWriteSXBuffer(); //close SX buffer write
delay(ACKdelay);
LT.sendSXReliableACK(0, TXPayloadL, NetworkID, RXPayloadCRC, TXpower);
Serial.println(F("Ranging request replied"));
LT.setupRanging(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, rangingaddress, RANGING_SLAVE);
LT.receiveRanging(rangingaddress, 0, RangingTXPower, NO_WAIT);
startmS = millis();
digitalWrite(LED1, HIGH);
do
{
if (digitalRead(DIO1))
{
IrqStatus = LT.readIrqStatus();
if (IrqStatus & IRQ_RANGING_SLAVE_RESPONSE_DONE)
{
Serial.print("Ranging response sent");
LT.receiveRanging(ThisStation, 0, RangingTXPower, NO_WAIT);
}
else
{
Serial.print("ERROR Ranging slave error,");
Serial.print(",Irq,");
Serial.print(IrqStatus, HEX);
LT.printIrqStatus();
}
Serial.println();
}
}
while ( ((uint32_t) (millis() - startmS) < RangingUpTimemS));
Serial.println("Ranging receive timeout!!");
digitalWrite(LED1, LOW);
}
void printRequestType(uint8_t type)
{
switch (type)
{
case RequestGPSLocation:
Serial.print(F(" RequestGPSLocation"));
break;
case RequestRanging:
Serial.print(F(" RequestRanging"));
break;
default:
Serial.print(F(" Request type not recognised"));
break;
}
}
void packet_is_OK()
{
printPacketDetails();
Serial.println();
}
void packet_is_Error()
{
uint16_t IRQStatus;
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
Serial.print(F("Error "));
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
{
Serial.print(F(" RXTimeout "));
}
else
{
printPacketDetails();
}
}
void printPacketDetails()
{
Serial.print(F("LocalNetworkID,0x"));
Serial.print(NetworkID, HEX);
Serial.print(F(",TransmitterNetworkID,0x"));
Serial.print(LT.getRXNetworkID(RXPacketL), HEX);
Serial.print(F(",RXPayloadCRC,0x"));
Serial.print(LT.getRXPayloadCRC(RXPacketL), HEX);
LT.printReliableStatus();
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT);
led_Flash(2, 125); //two quick LED flashes to indicate program start
Serial.begin(115200);
Serial.println(__FILE__);
Serial.println();
SPI.begin();
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
Serial.println(F("LoRa Device found"));
led_Flash(2, 125); //two further quick LED flashes to indicate device found
}
else
{
Serial.println(F("ERROR No LoRa device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed LED flash indicates device error
}
}
Serial.println(F("Receiver ready"));
Serial.println();
}

View File

@ -0,0 +1,39 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 18/04/22
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
const uint8_t NSS = 10; //select pin on LoRa device
const uint8_t NRESET = 9; //reset pin on LoRa device
const uint8_t RFBUSY = 7; //busy pin on LoRa device
const uint8_t DIO1 = 3; //DIO1 pin on LoRa device, used for sensing RX and TX done
const uint8_t LED1 = 8;
const uint8_t LORA_DEVICE = DEVICE_SX1280; //we need to define the device we are using
//******* Setup LoRa modem parameters here ! ***************
const uint32_t Frequency = 2445000000; //frequency of transmissions
const uint32_t Offset = 0; //offset frequency for calibration purposes
const int8_t TXpower = 2; //LoRa transmit power
const int8_t RangingTXPower = 10; //Transmit power used for ranging
const uint8_t Bandwidth = LORA_BW_0800; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint32_t ACKdelay = 200; //delay in mS before sending reply
const uint32_t RXtimeout = 5000; //receive timeout in mS.
const uint8_t RequestGPSLocation = 1; //request type for GPS location
const uint8_t RequestRanging = 2; //request type for ranging
//GPS co-ordinates to use for the GPS location request
const float TestLatitude = 51.48230; //GPS co-ordinates to use for test
const float TestLongitude = -3.18136; //Cardiff castle keep, used for testing purposes
const float TestAltitude = 25.5;
const uint8_t TrackerStatus = 1; //set status bit to represent tracker GPS has fix
const uint16_t NetworkID = 0x3210; //NetworkID identifies this connection, needs to match value in transmitter
const uint8_t ThisStation = 123; //the number of this station for requests and ranging

View File

@ -0,0 +1,224 @@
/*****************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 16/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
#include <SPI.h>
#include <SX128XLT.h>
#include "Settings.h"
SX128XLT LT;
#ifdef ENABLEOLED
#include <U8x8lib.h> //https://github.com/olikraus/u8g2
//U8X8_SSD1306_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //standard 0.96" SSD1306
U8X8_SH1106_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //1.3" OLED often sold as 1.3" SSD1306
#endif
uint16_t rangeing_errors, rangeings_valid, rangeing_results;
uint16_t IrqStatus;
uint32_t endwaitmS, startrangingmS, range_result_sum, range_result_average;
float distance, distance_sum, distance_average;
bool ranging_error;
int32_t range_result;
int16_t RangingRSSI;
void loop()
{
uint8_t index;
distance_sum = 0;
range_result_sum = 0;
rangeing_results = 0; //count of valid results in each loop
for (index = 1; index <= rangeingcount; index++)
{
startrangingmS = millis();
Serial.println(F("Start Ranging"));
LT.transmitRanging(RangingAddress, TXtimeoutmS, RangingTXPower, WAIT_TX);
IrqStatus = LT.readIrqStatus();
if (IrqStatus & IRQ_RANGING_MASTER_RESULT_VALID)
{
rangeing_results++;
rangeings_valid++;
digitalWrite(LED1, HIGH);
Serial.print(F("Valid"));
range_result = LT.getRangingResultRegValue(RANGING_RESULT_RAW);
Serial.print(F(",Register,"));
Serial.print(range_result);
if (range_result > 800000)
{
range_result = 0;
}
range_result_sum = range_result_sum + range_result;
distance = LT.getRangingDistance(RANGING_RESULT_RAW, range_result, distance_adjustment);
distance_sum = distance_sum + distance;
Serial.print(F(",Distance,"));
Serial.print(distance, 1);
Serial.print(F(",RSSIReg,"));
Serial.print(LT.readRegister(REG_RANGING_RSSI));
RangingRSSI = LT.getRangingRSSI();
Serial.print(F(",RSSI,"));
Serial.print(RangingRSSI);
Serial.print(F("dBm"));
digitalWrite(LED1, LOW);
}
else
{
rangeing_errors++;
distance = 0;
range_result = 0;
Serial.print(F("NotValid"));
Serial.print(F(",Irq,"));
Serial.print(IrqStatus, HEX);
}
delay(packet_delaymS);
if (index == rangeingcount)
{
range_result_average = (range_result_sum / rangeing_results);
if (rangeing_results == 0)
{
distance_average = 0;
}
else
{
distance_average = (distance_sum / rangeing_results);
}
Serial.print(F(",TotalValid,"));
Serial.print(rangeings_valid);
Serial.print(F(",TotalErrors,"));
Serial.print(rangeing_errors);
Serial.print(F(",AverageRAWResult,"));
Serial.print(range_result_average);
Serial.print(F(",AverageDistance,"));
Serial.print(distance_average, 1);
#ifdef ENABLEDISPLAY
display_screen1();
#endif
delay(2000);
}
Serial.println();
}
}
#ifdef ENABLEDISPLAY
void display_screen1()
{
disp.clear();
disp.setCursor(0, 0);
disp.print(F("Distance "));
disp.print(distance_average, 1);
disp.print(F("m"));
disp.setCursor(0, 2);
disp.print(F("RSSI "));
disp.print(RangingRSSI);
disp.print(F("dBm"));
disp.setCursor(0, 4);
disp.print(F("OK,"));
disp.print(rangeings_valid);
disp.print(F(",Err,"));
disp.print(rangeing_errors);
}
#endif
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
led_Flash(4, 125); //two quick LED flashes to indicate program start
Serial.begin(9600);
Serial.println();
Serial.println(F("54_Ranging_Master Starting"));
SPI.begin();
led_Flash(2, 125);
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
Serial.println(F("Device found"));
led_Flash(2, 125);
delay(1000);
}
else
{
Serial.println(F("No device responding"));
while (1)
{
led_Flash(50, 50); //long fast flash indicates device error
}
}
LT.setupRanging(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, RangingAddress, RANGING_MASTER);
//LT.setRangingCalibration(Calibration); //override automatic lookup of calibration value from library table
Serial.println();
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
Serial.println();
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
Serial.println();
Serial.println();
LT.printRegisters(0x900, 0x9FF); //print contents of device registers, normally 0x900 to 0x9FF
Serial.println();
Serial.println();
#ifdef ENABLEDISPLAY
Serial.println("Display Enabled");
disp.begin();
disp.setFont(u8x8_font_chroma48medium8_r);
disp.setCursor(0, 0);
disp.print(F("Ranging RAW Ready"));
disp.setCursor(0, 1);
disp.print(F("Power "));
disp.print(RangingTXPower);
disp.print(F("dBm"));
disp.setCursor(0, 2);
disp.print(F("Cal "));
disp.print(Calibration);
disp.setCursor(0, 3);
disp.print(F("Adjust "));
disp.print(distance_adjustment, 4);
#endif
Serial.print(F("Address "));
Serial.println(RangingAddress);
Serial.print(F("CalibrationValue "));
Serial.println(LT.getSetCalibrationValue());
Serial.println(F("Ranging master RAW ready"));
delay(2000);
}

View File

@ -0,0 +1,42 @@
/*****************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 04/11/21
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10
#define RFBUSY 7
#define NRESET 9
#define LED1 8
#define DIO1 3
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
//******* Setup LoRa Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 2445000000; //frequency of transmissions in hz
const int32_t Offset = 0; //offset frequency in hz for calibration purposes
const uint8_t Bandwidth = LORA_BW_0800; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint16_t Calibration = 11350; //Manual Ranging calibrarion value
const int8_t RangingTXPower = 10; //Transmit power used
const uint32_t RangingAddress = 16; //must match address in recever
const uint16_t waittimemS = 10000; //wait this long in mS for packet before assuming timeout
const uint16_t TXtimeoutmS = 5000; //ranging TX timeout in mS
const uint16_t packet_delaymS = 0; //forced extra delay in mS between ranging requests
const uint16_t rangeingcount = 5; //number of times ranging is cqarried out for each distance measurment
float distance_adjustment = 1.0000; //adjustment factor to calculated distance
#define ENABLEOLED //enable this define to use display
#define ENABLEDISPLAY //enable this define to use display

View File

@ -0,0 +1,137 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 16/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation -
Serial monitor baud rate is set at 9600
*******************************************************************************************************/
#include <SPI.h>
#include <SX128XLT.h>
#include "Settings.h"
SX128XLT LT;
uint32_t endwaitmS;
uint16_t IrqStatus;
uint32_t response_sent;
void loop()
{
LT.receiveRanging(RangingAddress, 0, TXpower, NO_WAIT);
endwaitmS = millis() + rangingRXTimeoutmS;
while (!digitalRead(DIO1) && (millis() <= endwaitmS)); //wait for Ranging valid or timeout
if (millis() >= endwaitmS)
{
Serial.println("Error - Ranging Receive Timeout!!");
led_Flash(2, 100); //single flash to indicate timeout
}
else
{
IrqStatus = LT.readIrqStatus();
digitalWrite(LED1, HIGH);
if (IrqStatus & IRQ_RANGING_SLAVE_RESPONSE_DONE)
{
response_sent++;
Serial.print(response_sent);
Serial.print(" Response sent");
}
else
{
Serial.print("Slave error,");
Serial.print(",Irq,");
Serial.print(IrqStatus, HEX);
LT.printIrqStatus();
}
digitalWrite(LED1, LOW);
Serial.println();
}
}
void led_Flash(unsigned int flashes, unsigned int delaymS)
{
//flash LED to show board is alive
unsigned int index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
Serial.begin(9600); //setup Serial console ouput
Serial.println();
Serial.println("55_Ranging_Slave Starting");
pinMode(LED1, OUTPUT);
led_Flash(2, 125);
SPI.begin();
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
Serial.println(F("Device found"));
led_Flash(2, 125);
delay(1000);
}
else
{
Serial.println(F("No device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
//The function call list below shows the complete setup for the LoRa device for ranging using the information
//defined in the Settings.h file.
//The 'Setup LoRa device for Ranging' list below can be replaced with a single function call, note that
//the calibration value will be loaded automatically from the table in the library;
//LT.setupRanging(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, RangingAddress, RangingRole);
LT.setupRanging(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, RangingAddress, RANGING_SLAVE);
//***************************************************************************************************
//Setup LoRa device for Ranging Slave
//***************************************************************************************************
/*
LT.setMode(MODE_STDBY_RC);
LT.setPacketType(PACKET_TYPE_RANGING);
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 0, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
LT.setRfFrequency(Frequency, Offset);
LT.setTxParams(TXpower, RADIO_RAMP_02_US);
LT.setRangingMasterAddress(RangingAddress);
LT.setRangingSlaveAddress(RangingAddress);
LT.setRangingCalibration(LT.lookupCalibrationValue(SpreadingFactor, Bandwidth));
LT.setRangingRole(RANGING_SLAVE);
LT.writeRegister(REG_RANGING_FILTER_WINDOW_SIZE, 8); //set up window size for ranging averaging
LT.setHighSensitivity();
*/
//***************************************************************************************************
LT.setRangingCalibration(11300); //override automatic lookup of calibration value from library table
Serial.print(F("Calibration,"));
Serial.println(LT.getSetCalibrationValue()); //reads the calibratuion value currently set
delay(2000);
}

View File

@ -0,0 +1,34 @@
/*****************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 16/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10
#define RFBUSY 7
#define NRESET 9
#define LED1 8
#define DIO1 3
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
//******* Setup LoRa Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 2445000000; //frequency of transmissions in hz
const int32_t Offset = 0; //offset frequency in hz for calibration purposes
const uint8_t Bandwidth = LORA_BW_0800; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint16_t Calibration = 11350; //Manual Ranging calibration value
const int8_t TXpower = 10; //Transmit power used
const uint32_t RangingAddress = 16; //must match address in master
const uint16_t rangingRXTimeoutmS = 0xFFFF; //ranging RX timeout in mS

View File

@ -0,0 +1,190 @@
/*****************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 17/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
#include <SPI.h>
#include <SX128XLT.h>
SX128XLT LT;
#include "Settings.h"
uint8_t distance_zero_count;
uint16_t calvalue, calibrationstart, calibrationend;
uint16_t rangeing_error_count, rangeing_valid_count;
uint16_t IrqStatus;
uint32_t endwaitmS, startrangingmS, range_result;
float distance;
void loop()
{
uint16_t index;
distance_zero_count = 0;
for (index = calibrationstart; index <= calibrationend; index = index + 10)
{
digitalWrite(LED1, HIGH);
LT.setRangingCalibration(index);
Serial.print(F("TransmitRanging,Calibration,"));
Serial.print(index);
LT.transmitRanging(RangingAddress, TXtimeoutmS, TXpower, NO_WAIT);
digitalWrite(LED1, LOW);
endwaitmS = millis() + waittimemS;
startrangingmS = millis();
while (!(digitalRead(DIO1)) && (millis() < endwaitmS)); //wait for Ranging valid or timeout
delay(10);
IrqStatus = LT.readIrqStatus();
Serial.print(F(",IRQ,"));
Serial.print(IrqStatus, HEX);
if (IrqStatus & IRQ_RANGING_MASTER_RESULT_TIMEOUT)
{
rangeing_error_count++;
Serial.print(F(", RangingTimeout! "));
}
if (millis() > endwaitmS)
{
Serial.print(F(",ProgramTimeout"));
}
if (IrqStatus & IRQ_RANGING_MASTER_RESULT_VALID)
{
rangeing_valid_count++;
digitalWrite(LED1, HIGH);
Serial.print(F(",Valid"));
range_result = LT.getRangingResultRegValue(RANGING_RESULT_RAW);
Serial.print(F(",RAW,"));
Serial.print(range_result, HEX);
distance = LT.getRangingDistance(RANGING_RESULT_RAW, range_result, 1);
Serial.print(F(",Distance,"));
Serial.print(distance, 1);
Serial.print(F("m"));
Serial.print(F(",Time,"));
Serial.print(millis() - startrangingmS);
Serial.print("mS");
digitalWrite(LED1, LOW);
}
Serial.print(F(",OKCount,"));
Serial.print(rangeing_valid_count);
Serial.print(F(",ErrorCount,"));
Serial.print(rangeing_error_count);
if (distance == 0)
{
Serial.print(F(", Distance is Zero!"));
distance_zero_count++;
}
if (distance_zero_count >= 3)
{
delay(5000);
break;
}
Serial.println();
delay(packet_delaymS);
}
Serial.println();
Serial.println();
Serial.println();
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
unsigned int index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
uint16_t Remainder;
Serial.println();
Serial.println();
Serial.begin(9600); //setup Serial console ouput
Serial.println();
Serial.println(F("56_Ranging_Calibration_Checker Starting"));
pinMode(LED1, OUTPUT);
led_Flash(2, 125);
Serial.println(F("Checking device"));
SPI.begin();
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
Serial.println(F("Device found"));
led_Flash(2, 125);
delay(1000);
}
else
{
Serial.println(F("No device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
//The function call list below shows the complete setup for the LoRa device for ranging using the information
//defined in the Settings.h file.
//The 'Setup LoRa device for Ranging' list below can be replaced with a single function call, note that
//the calibration value will be loaded automatically from the table in the library;
//LT.setupRanging(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, RangingAddress, RangingRole);
//***************************************************************************************************
//Setup LoRa device for Ranging Master
//***************************************************************************************************
LT.setMode(MODE_STDBY_RC);
LT.setPacketType(PACKET_TYPE_RANGING);
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 0, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
LT.setRfFrequency(Frequency, Offset);
LT.setTxParams(TXpower, RADIO_RAMP_02_US);
LT.setRangingMasterAddress(RangingAddress);
LT.setRangingSlaveAddress(RangingAddress);
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RANGING_MASTER_RESULT_VALID + IRQ_RANGING_MASTER_RESULT_TIMEOUT), 0, 0); //set for IRQ on RX done
LT.setRangingCalibration(LT.lookupCalibrationValue(SpreadingFactor, Bandwidth));
LT.setRangingRole(RANGING_MASTER);
LT.writeRegister(REG_RANGING_FILTER_WINDOW_SIZE, 8); //set up window size for ranging averaging
LT.setHighSensitivity();
//***************************************************************************************************
//LT.setRangingCalibration(Calibration); //override automatic lookup of calibration value from library table
calvalue = LT.getSetCalibrationValue();
Remainder = calvalue / 10;
calibrationstart = (Remainder * 10) - 1000;
calibrationend = (Remainder * 10) + 1000;
Serial.print(F("CalibrationStart,"));
Serial.print(calibrationstart);
Serial.print(F(",CalibrationEnd,"));
Serial.println(calibrationend);
Serial.println();
delay(2000);
}

View File

@ -0,0 +1,40 @@
/*****************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 17/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10
#define RFBUSY 7
#define NRESET 9
#define LED1 8
#define DIO1 3
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
//******* Setup LoRa Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 2445000000; //frequency of transmissions in hz
const int32_t Offset = 0; //offset frequency in hz for calibration purposes
const uint8_t Bandwidth = LORA_BW_0800; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint16_t Calibration = 11426; //Manual Ranging calibrarion value
const uint8_t RangingRole = RANGING_SLAVE; //Ranging role, RANGING_MASTER or RANGING_SLAVE
const int8_t TXpower = 10; //Transmit power used
const uint32_t RangingAddress = 16; //must match address in recever
const uint16_t waittimemS = 10000; //wait this long in mS for packet before assuming timeout
const uint16_t TXtimeoutmS = 5000; //ranging TX timeout in mS
const uint16_t RXtimeoutmS = 0xFFFF; //ranging RX timeout in mS
const uint16_t packet_delaymS = 250; //forced extra delay in mS between ranging requests
const uint16_t rangeingcount = 5; //number of times ranging is cqarried out for each distance measurment
float distance_adjustment = 1; //adjustment factor to calculated distance

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,113 @@
## Ranging Calibration
**Note:** The ranging feature of the SX128X is not supported if the module uses external RX and TX switching.
To measure a distance the master device transmits a ranging request which a slave receives and then sends a response, if the request was for that particular slave. The master receives the slaves response and knows by use of a timer how long the master slave response exchange took.
The total time for the master slave exchange includes a fixed processing time for the master and slave to transmit and receive the appropriate packets. This fixed time should be static and should be the same no matter how far apart the master initiator and slave receiver are.
This fixed time then needs to be subtracted from the total round trip time. The remainder of the time is then proportional to the distance in a linear way.
Thus the ranging function needs a calibration value (the fixed time mentioned above) which changes according to the bandwidth and spreading factor used. Bandwidths of 400khz, 800khz and 1600khz are supported for ranging. The calibration value can also vary slightly between different modules or antennas used. So for the best results its suggested to calibrate a pair of modules together. The SX128XLT library does, by default, do a lookup from a pre-determined range of calibration values.
Its been noticed in testing that variations in distance measurements of +\-10m are not unusual and this is typically the sort of adjustment that calibration might correct for. If your using the SX128x to measure long distances, into several kilometres, then the standard values provided by the library are probably accurate enough, a variation of 10m over 4km is hardly significant.
There is a calibration method described in a Semtech document;
[Introduction to Ranging](https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/44000000MDiH/OF02Lve2RzM6pUw9gNgSJXbDNaQJ_NtQ555rLzY3UvY)
My own approach to the ranging calibration has been simplified. The starting base for the calibration numbers was this table produced by Semtech;
![Picture 1](Pictures/SX128X_Ranging_Calibration_Values.jpg)
After running some checks on my own set-ups, I came up with the following set of values, and the ranging programs pick up these numbers by default, you can of course use your own.
![Picture 1](Pictures/Calibration_Values.jpg)
To check the the calibration values from the library a ranging slave was programmed with the **'55\_Ranging\_Slave'** program. Normally the ranging example programs automatically lookup the calibration value from a table in the file 'SX128XLT_Definitions.h'. However the value can be manually configured using the command;
setRangingCalibration(Calibration);
where Calibration is the value to use, normally in the range of 10,000 to 13,500.
Lets follow and example of testing the calibration of the modules for ranging at spreading factor 8, bandwidth 800khz. From the initial table shown above, the calibration value is around 11350. Set the appropriate LoRa settings in the 'Settings.h' file for the slave and ranging calibration programs to;
const uint8_t Bandwidth = LORA_BW_0800; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
Program the slave device and at start-up the serial monitor should show;
55_Ranging_Slave Starting
Device found
Calibration,11350
RangingListen,
The example program **'56\_Ranging\_Calibration\_Checker'** varies the calibration value for each master ranging measurement starting at a value 1000 less than the calibration value provided and changing it in steps to a value that is 1000 more than the mid value. At each change of calibration value the distance is measured and sent to the serial monitor. When the distance goes to zero 3 times in a row the process stops. You can then see on the serial monitor which calibration value gives close to a 0m reading.
When the ranging calibration program starts you should see this;
56_Ranging_Calibration_Checker Starting
Checking device
Device found
CalibrationStart,10350,CalibrationEnd,12350
After a while the program reported this;
TransmitRanging,Calibration,11220,IRQ,200,Valid,RAW,47,Distance,3.2m,Time,33mS,OKCount,88,ErrorCount,0
TransmitRanging,Calibration,11230,IRQ,200,Valid,RAW,1F,Distance,1.4m,Time,31mS,OKCount,89,ErrorCount,0
TransmitRanging,Calibration,11240,IRQ,200,Valid,RAW,19,Distance,1.1m,Time,31mS,OKCount,90,ErrorCount,0
TransmitRanging,Calibration,11250,IRQ,200,Valid,RAW,36,Distance,2.4m,Time,30mS,OKCount,91,ErrorCount,0
TransmitRanging,Calibration,11260,IRQ,200,Valid,RAW,FFFFFF,Distance,0.0m,Time,31mS,OKCount,92,ErrorCount,0, Distance is Zero!
TransmitRanging,Calibration,11270,IRQ,200,Valid,RAW,2B,Distance,1.9m,Time,33mS,OKCount,93,ErrorCount,0
TransmitRanging,Calibration,11280,IRQ,200,Valid,RAW,1D,Distance,1.3m,Time,30mS,OKCount,94,ErrorCount,0
TransmitRanging,Calibration,11290,IRQ,200,Valid,RAW,0,Distance,0.0m,Time,31mS,OKCount,95,ErrorCount,0, Distance is Zero!
TransmitRanging,Calibration,11300,IRQ,200,Valid,RAW,FFFFD7,Distance,0.0m,Time,33mS,OKCount,96,ErrorCount,0, Distance is Zero!
So with the slave using an initial calibration value of 11350 the master got to around 0m at a calibration value of 11300. Lets re-program the slave with a calibration value of 11300. To override the automatic lookup of the calibration value from the table in SX128XLT_Definitions.h ensure this command is enabled in setup() function after the main sequence functions calls configuring the SX128X device;
**LT.setRangingCalibration(11300); //override automatic lookup of calibration value from library table**
The ranging calibration program then produced these results;
TransmitRanging,Calibration,11300,IRQ,400, RangingTimeout! ,OKCount,94,ErrorCount,2
TransmitRanging,Calibration,11310,IRQ,200,Valid,RAW,73,Distance,5.2m,Time,31mS,OKCount,95,ErrorCount,2
TransmitRanging,Calibration,11320,IRQ,200,Valid,RAW,59,Distance,4.0m,Time,31mS,OKCount,96,ErrorCount,2
TransmitRanging,Calibration,11330,IRQ,200,Valid,RAW,FFFF46,Distance,0.0m,Time,30mS,OKCount,97,ErrorCount,2, Distance is Zero!
TransmitRanging,Calibration,11340,IRQ,200,Valid,RAW,FFFFD0,Distance,0.0m,Time,33mS,OKCount,98,ErrorCount,2, Distance is Zero!
TransmitRanging,Calibration,11350,IRQ,200,Valid,RAW,FFFFCB,Distance,0.0m,Time,33mS,OKCount,99,ErrorCount,2, Distance is Zero!
So a calibration value of maybe 11320 seems about right. This value can then be used to manually configure a particular set-up.
The example program **54_Ranging_Master** can then be programmed with the same calibration value just determined. This program will carry out 5 ranging attempts and average the results to a distance shown on the serial monitor. This program will also drive a SSD1306 OLED for use as a portable distance measuring device.
The master ranging programs calculates the distance and then adjusts the measured value with this setting in the Settings.h file;
**const float distance_adjustment = 1.0; //adjustment to calculated distance**
The adjustment value need to be determined by using the ranging programs to measure the distance over a long known path. I used a location when the master has line of sight over a long path, 4.405km in this case. This distance measurement was obtained from the 1:25000 Ordnance Survey map.
Over this long path the average distance reported by the SX1280 4.424km, so the adjustment factor is 4.405/4.424 = 0.99571
### Variances at short distances.
Regardless of the derived calibration value the conversion of the time of flight result from the values reported in the SX1280 registers to distance is a linear one, so any variation in register value over a fixed distance will represent a distance variation. Whilst you can average results the distance variations will be down to the limitations of the internal timing measurements that the SX128x takes.
I set-up a outdoor test in a large open areas, my local playing field. The slave was placed on a pole about 1.8M off the ground and I stood with the master hand-held, away from my body, at 100m distance. The calibration and adjustment values were determined as mentioned above, so the master ought to be recoding a distance of 100m. The results of around 140 ranging measurements are below;
![Picture 1](Pictures/SX128XLT_Ranging_100m.jpg)
You can see a variation in distance of +\- 10m at 100m distance is not unusual. Apart from long term averaging its difficult to see what can be done to reduce these variances.
It has also been noted that where there is a possibility of reflections such as in urban areas, larger variances than this have been seen particularly if the antenna orientations are moving or otherwise changed.
### Stuart Robinson
### March 2020

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB