Bruk av LoRa-radioer med Micropython

 91 total views,  2 views today

LoRa er en radioteknologi som overfører digitale data med lav hastighet, men som oppnår lang rekkevidde med lav utstrålt effekt. Radioene er billige, men kan kreve noe programmering for å kople dem til en datamaskin. Vi viser noen eksempler på hvordan.

(c) Anders Fongen, mai 2024

Innledning

Fra radioteorien kan vi finne formler som viser den øvre grensen for overføringshastighet av digitale data, og at denne grensen synker ved svakere mottatt signal (dårligere signal/støy forhold), Dersom vi ikke trenger høy overføringshastighet kan vi altså benytte radioer med lav utgangseffekt og lang rekkevidde. Radioer med lav utgangseffekt kan være små og lette, ha liten antenne og lang driftstid på batteriet. Dette er akkurat hva vi trenger i såkalte “Internet-of-Things”-anvendelser, hvor f.eks. batteridrevne sensorer skal overvåke miljøvariabler i et gartneri, eller som skal detektere inntrengere på et sperret område.

Long Range radio

En radiotype som egner seg for dette formålet kalles LoRa, en forkortelse for “Long Range”. Vi snakker ikke om en tradisjonell radio med boks og knapper, men et kretskort som koples opp og kontrolleres av en datamaskin eller mikrokontroller. Under vises bilder av LoRa-radioer i to utgaver:

Modulen til venstre er billigst, men vanskeligst å jobbe med, fordi endekontaktene står veldig tett og er vriene å lodde. Denne modulen har SPI-grensesnsitt, i motsetning til modulen til høyre, som har et seriegrensesnitt. Den til høyre har pinner med 0.1 tommes avstand som passer i vanlige eksperimentbrett (breadboard) og er derfor enklere å jobbe med. Vi har gjort eksperimenter med denne modulen, den lages av EByte og kan levere opptil 1 watt (30 dBm) utgangseffekt.

LoRa-modulen koples til en datamaskin/mikrokontroller for konfigurasjon og datatrafikk. I denne artikkelen har vi benyttet Raspberry Pico. Andre enheter, som Arduino, ESP32 eller Raspberry Pi kan også brukes, men da med nødvendige endringer i konfigurasjonen og programmet. Vi vil referere til denne enheten som mikrokontrolleren.

LoRa-moduler er alle basert på en brikke fra Semtech med betegnelsen SX1276/77/78/79. Disse 4 modellene er realtivt like og adskiller seg i hovedsak med ulike radiofrekvenser. Det er ikke likegyldig hvilke frekvenser du kan bruke! Norske myndigheter (NKOM) har strenge regler for radiosendinger som bør overholdes. Flere opplysninger om dette kommer senere i artikkelen. Her følger noen detaljer:

Selve databladet til Semtech’s LoRa-brikke finnes på denne lenken, Den trenger du ikke lese før du vil gå i dybden på virkemåten.

E32 LoRa-modul fra Ebyte

E32 LoRa-modulen som er brukt i dette eksperimentet er vist til høyre på bildet over. Der fremgår det også hvilke funksjoner som ligger på de ulike pinnene. Disse pinnene brukes på denne måten:

  • M0, M1 – inputsignal (fra mikrokontrolleren til E32) som avgjør om LoRa-modulen skal settes i konfigurasjonsmodus eller dataoverføringsmodus. De koples til to porter på mikrokontrolleren, i vårt tilfelle GPIO18 og GPIO19.
  • RXD, TXD – for å sende og motta data (konfigurasjonsdata eller nyttetrafikk, avhengig av signalene på M0 og M1). De koples “i kryss” til tilsvarende porter på mikrokontrolleren, altså med TXD til RX-porten og RXD til TX-porten.
  • AUX – Et utgående signal fra LoRa-modulen som signaliserer om den kan motta data, eller om den ønsker å overføre data fra mottatte radiosignaler. I vårt eksperiment viste det seg at denne pinnen trenger en ekstern pullup motstand!
  • Vcc og GND – Koples til 3.3 volt spenningsforsyning og jord.

Tilkopling til Raspberry Pico

Pinnene på E32 LoRa-modulen ble koplet til pinner/porter på Raspberry Pico på denne måten.

  • M0 – GPIO18, M1 – GPIO19
  • RXD – TX på UART0, pin 21
  • TXD – RX på UART0, pin 22
  • AUX – GPIO20, med pullup-motstand (1 kOhm) til 3.3v
  • Vcc – 3.3v pin 36
  • GND – GND på pin 38
E32-modulen til høyre koplet til en Raspberry Pico. Pullup-mostanden for AUX-pinnen skimtes mellom ledningene.

Nødvendig programvare

Det finnes programvarebiblioteker i microPython for kontroll av brikken SX1276 (og de andre variantene) med SPI-grensesnitt, men de kan ikke brukes mot EByte’s LoRa-moduler. EByte har plassert sin egen mikrokontroller på modulen med sitt eget grensesnitt for konfigurasjon. Programvare vi kan bruke må altså være tilpasset dette.

Vi fant et bibliotek på GitHub hvor enkeltfiler i Python kan lastes ned og installeres i mikrokontrolleren fra denne lenken. De var til stor hjelp, men krevde også noen endringer for å virke korrekt med de modulene som vi eksperimenterte med. Forklaring følger.

Nødvendige endringer i programvaren

Programvaren fra lenken vist ovenfor virket ikke uten endringer. Vi kan ikke fastslå om det skyldes programmeringsfeil eller endret firmware i E32-modulen. Dersom det siste er tilfelle (noe vi antar) vil det være nødvendig med litt eksperimentering dersom disse endringene ikke gir ønsket resultat.

  • Programkoden for å konfigurere E32-modulen ligger i filen lora_e32.py. I funksjonen get_configuration() vil responsen fra modulen leses i linje 463 og siden analyseres. Vår observasjon er at de ønskede 6 bytes kommer med en ekstra byte foran og bak (med verdien 0), og disse må fjernes før responsen blir analysert.
        data = self.uart.read()

skal derfor erstattes med

        datax = self.uart.read()
        print(datax) # For kontrollformål
        data = datax[1:-1]

  • Funksjonen clear_UART_buffer() på linje 591 vil tømme mottaksbufferen ved å lese dataene som ligger der, inntil det skjer en “timeout”. Dersom det er trafikk på kanalen vil den stadig motta data, og denne funksjonen vil tilsynelatende “henge”. En endret løsning for denne funksjonen er å spørre etter antall bytes i bufferet, for deretter å lese dette antall bytes. Funksjonen foreslås gitt dette innholdet:
    def clean_UART_buffer(self):
        n = self.uart.any()
        self.uart.read(n)
  • I filen set_configuration.py er det en feil i linje 56. Leddet wakeUpTime skal erstattes med wirelessWakeupTime.

Eksempel på enkelt sending og mottak

Med de endringene som er vist ovenfor, og med AUX-linjen koplet til en ekstern pullup-motstand (vi brukte en uke på å finne ut at dette var årsaken til at ingenting funket som forventet), skal det nå ikke mange programlinjene til for å sette opp en forbindelse mellom to E32-moduler. Her er eksempel på sende- og mottaks-modul:

Sending av en tegnstreng (klokkeslett) med faste intervaller:

from lora_e32 import LoRaE32, Configuration
from machine import UART, Pin
import utime
from lora_e32_constants import FixedTransmission, TransmissionPower, AirDataRate
from lora_e32_operation_constant import ResponseStatusCode

# Initialize the LoRaE32 module
uart2 = UART(0, rx=Pin(17), tx=Pin(16))
lora = LoRaE32('433T30D', uart2, aux_pin=20, m0_pin=18, m1_pin=19)

code = lora.begin()
print("Initialization: {}", ResponseStatusCode.get_description(code))

# Set the configuration to default values and print the updated configuration to the console
# Not needed if already configured
configuration_to_set = Configuration('433T20D')
configuration_to_set.CHAN = 27
configuration_to_set.OPTION.fixedTransmission = FixedTransmission.TRANSPARENT_TRANSMISSION
configuration_to_set.OPTION.transmissionPower = TransmissionPower('433T30D').\
                                                    get_transmission_power().POWER_30
configuration_to_set.SPED.airDataRate = AirDataRate.AIR_DATA_RATE_010_24
code, confSetted = lora.set_configuration(configuration_to_set)
print("Set configuration: {}", ResponseStatusCode.get_description(code))

# Send a string message (transparent)
while True:
    message = str(utime.time()) + '\n'
    code = lora.send_transparent_message(message)
    print(message)
    utime.sleep(5)

(her brekker noen kodelinjer, men med copy-paste inn i en teksteditor retter dette seg).

For å motta disse meldingene på en annen radio (som også varsles med et pip, og innholdet vises i et OLED-display), kan denne koden brukes:

from lora_e32 import LoRaE32, Configuration, BROADCAST_ADDRESS
from machine import UART, Pin, I2C
import ssd1306
import utime

from lora_e32_constants import FixedTransmission, AirDataRate
from lora_e32_operation_constant import ResponseStatusCode

# using default address 0x3C
i2c = I2C(1,sda=Pin(14), scl=Pin(15))
display = ssd1306.SSD1306_I2C(128, 64, i2c)
print("I2C ok")

# Initialize the beeper
beep = Pin(2,Pin.OUT)

# Initialize the LoRaE32 module
uart2 = UART(0, rx=Pin(17), tx=Pin(16))
lora = LoRaE32('433T30D', uart2, aux_pin=20, m0_pin=18, m1_pin=19)
print("UART ok")
code = lora.begin()
print("Lora started")
configuration_to_set = Configuration('433T30D')
configuration_to_set.CHAN = 27
configuration_to_set.OPTION.fixedTransmission = FixedTransmission.TRANSPARENT_TRANSMISSION
configuration_to_set.SPED.airDataRate = AirDataRate.AIR_DATA_RATE_010_24
print("Configration ready")
code, confSetted = lora.set_configuration(configuration_to_set)
#print("Set configuration: {}", ResponseStatusCode.get_description(code))

print("Waiting for counter messages...")
while True:
    if lora.available() > 0:
        code, value = lora.receive_message(delimiter=b'\n')
        #print(ResponseStatusCode.get_description(code))
        # Display on OLED display
        display.fill(0)
        display.text(value,5,8)
        display.show()
        # Beep to notify the reception
        beep.on()
        utime.sleep(0.2)
        beep.off()
        print(value) #Print to console also
        #utime.sleep_ms(2000)

Noen av disse programlinjene kan utelates om ønskelig, fordi de kun gir informasjon til konsollet, eller de setter konfigurasjonsverdier som er standard ved oppstart av modulene. Merk også at verdiene som beskriver pin-nummer og gpio-nummer må endres om du ønsker å bruke andre porter på Raspberry Pico, eller om du bruker en annen mikrokontroller, f.eks. ESP32.

Adressering og kringkasting

I et nett av LoRa-moduler vil det være behov for å sende meldinger til enkeltmottakere (Unicast), basert på deres adresser, samt å sende til alle (Broadcast). Også sendinger til enkeltmottakere kan avlyttes av andre, så det er ingen beskyttelse av konfidensialitet i LoRa. Sendinger kan skje på tre måter:

  • Fixed Unicast: Sendingen påføres mottakerens adresse sendes som Unicast
  • Fixed Broadcast: Sendingen påføres en kringkastingsadresse (xFFFF), og sendes som Broadcast
  • Transparent: Sendingen påføres ikke adresse, og sendes som Broadcast

Sender og mottaker må selvfølgelig være konfigurert til samme radiokanal. Maksimal lengde på en melding er 58 bytes i Transparent modus, 55 bytes i Fixed modus.

Forhold mellom sender- og mottakerkonfigurasjon og hvilke kombinasjoner som tillater overføring

Sendingsvarighet og kanalbredde

LoRa har relativt lav overføringshastighet, maksimum 19200 bits/sekund og egner seg ikke til overføring av bilder, video eller lyd. Ved høy hastighet vil rekkevidden være lavere og feilraten høyere. Programeksemplet ovenfor sender meldinger hvert 5 sekund ved 2400 bits/sekund, og ved å studere dette signalet med en SDR-dongle og programmet GQRX (på Linux, på Windows kan SDR# brukes) kan vi fremstille et “fossefall” som viser både kanalbredde (horisontal akse) og sendingsvarighet (vertikal akse). Slik ser filmen ut:

Det er mulig å anslå båndbredden på dette signalet til ca 500 kHz, fra 432,75-433,25 MHz. Det er relativt bredt, og byr på problemer knyttet til lovligheten av å bruke så “brede” signaler. Båndbredden varierer ikke ved forskjellig sendeeffekt og overføringshastighet. Selve LoRa-kretsen kan konfigureres til ulike båndbredder, men det er ikke tilgjengelig på E32-modulen.

Overføringstiden lar seg vanskelig måle på vannfallet ovenfor, men vi lyttet til signalet med en vanlig radio og gjorde lydopptak til programmet Audacity. Dette programmet kan vise et lydsignal (vertikal akse) langs en tidsakse (horisontal akse) og gi oss en pekepinn om når signalet starter og slutter. Slik ser bildet ut på Audacity:

Ved å velge ut det tidsintervallet som sendingen foregår i, vil programmet vise varigheten nederst på skjermen, nemlig 302 millisekunder. Som ventet blir dette intervallet kortere ved høyere overføringshastighet: 63 millisekunder ved 9600 bits/sekund, og 32 millisekunder ved 19200 bits per sekund.

Rekkevidde for meldingsoverføring

LoRa er designet for å gi lang rekkevidde ved lav utstrålt effekt og lav overføringshastighet. I tillegg til disse to parametrene vil antennekonstruksjon og -plassering ha en betydning. Vi satte opp et eksperiment med en LoRa-mottaker i bilen koplet til en antenne på biltaket. Denne antennen er en “pisk” med ca 35 cm lengde.

Antennevalg: Senderen befant seg i huset, koplet til én av to antenner: (1) En kort antenne for håndapparat, plassert i vinduskarmen, eller (2) en 5-elements beam plassert på loftet, pekende ut av loftsvinduet.

Utstrålt effekt: Effekt (tilført antennen) var henholdsvis (a) 21 dBm=125 mW, eller (b) 30 dBm=1 W.

Ved å kjøre rundt i området (Lillehammer) og observere når mottak skjer (programkoden vist ovenfor gir et kort pip ved mottak), danner vi oss et uformelt inntrykk av rekkevidden. Terrenget i området er bebygget og kupert. Resultatene var som følger:

(1)(a) – Stabilt mottak til ca 750 meters avstand, sporadisk mottak utover dette.

(2)(a) – Stabilt mottak til ca 750 meters avstand, men også andre steder med synslinje til huset opp til 3,3 km avstand.

(2)(b) – Stabilt mottak i hele byområdet, langs E6 sydover opptil 10 km avstand. Stedvis mottak med en åskam mellom sender og mottaker (Saksumdalen). Ingen mottak “bak” antennen (en beam-antenne er direktiv og stråler mest i én retning).

LoRa og myndighetenes forskrifter

Bruk av radiosendere er strengt regulert i Norge, og det er på sin plass med noen vurderinger om hvordan LoRa-sendinger kan foregå på lovlig vis. Det er to regelverk som kommer til anvendelse: Fribruksforskriften, som stiller krav til radiosendinger for allmenheten, og Forskrift om radioamatørlisens, som angir krav til radiosendinger for personer med radioamatørlisens (radioamatørlisens tildeles personer som har bestått en såkalt lisensprøve).

La oss først ta for oss vilkårene i Fribruksforskriften, siden den vedkommer alle. Kapittel IV (§11) lister opp en del frekvenser som kan brukes, med oppgitt maksimal utstrålt effekt, båndbredde og sendetid. E32-modulen opererer med 500 kHz kanalbredde, og det er punkt (1), (4) og (5) som tillater dette, men da begrenset til 25 mW utstrålt effekt (14 dBm). Disse frekvensene ligger alle i området 800-900 MHz, som ikke støttes av den E32-modulen som er brukt i dette eksperimentet, men derimot med en annen modell: E32-900T20D. Den opererer i dette frekvensbåndet (862-931 MHz) og med mulighet for å sette utgangseffekten til 14 dBm. Merk at denne utgangseffekten vil gi betydelig kortere rekkevidde, og bruk av antenne med “gain” ikke er tillatt, siden 14 dBm er grensen for utstrålt effekt, ikke effekt tilført antennen.

Med en båndbredde satt til maksimalt 200 kHz kan også punkt (2), (3) og (6) i Fribruksforskriftens §11 brukes, opp til 500 mW (27 dBm). Slik båndbredde er ikke støttet av E32-modulen, så en annen modul basert på SX1276-kretsen må brukes. Spesifikasjonene til SX1276-kretsen oppgis til å kunne operere innenfor denne båndbredden. Rekkevidden og feilraten for en slik konfigurasjon er ikke undersøkt av oss ennå.

Merk at Fribruksforskriften også setter krav til såkalt sendetid, oppgitt i prosent. Denne verdien angir forholdet mellom sendetid og “stilletid”. 1% sendetid betyr at senderen skal være taus i gjennomsnittlig 99% av tiden.

For brukere med radioamatørlisens gjelder §7 i Forskrift om radioamatørlisens, som angir maksimal båndbredde og utstrålt effekt for de ulike frekvensbåndene. Det eneste aktuelle frekvensbånd for LoRa er 432-438 MHz, hvor maksimal kanabåndbredde er 30 kHz. E32-modulen kan ikke operere med 30 kHz båndbredde, men en annen SX-1276 basert modul kan muligens oppnå dette, men dette er ikke undersøkt av oss. Maksimal sendeeffekt for en slik konfigurasjon er hele 300 W, men vi tviler på om det finnes noe ferdiglaget produkt som tilbyr slik utstrålt effekt. Dette blir i så fall noe som må designes og konstrueres av en radioamatør.

Leave a Reply

Your email address will not be published. Required fields are marked *

1 × two =