venerdì 5 aprile 2019

LoraWan TheThingsNetwork con Arduino MKR1300

Dopo aver settato il gateway Dragino LG-01 vediamo come poter trasmettere i dati al cloud di TheThingsNetwork

Le impostazioni del gateway per LoraWAN sono le seguenti

Come si vede e' stato impostato uno spreading factor di 7, bandwith 125 KHz e CR 4 per una velocita' di circa 3400 bps. Tali valori devono essere compatibili con quelli dello sketch

Per prima cosa si imposta crea (dopo aver il gateway funzionante ed onlinea) una Application sulla console di TTN


dopo aver creato una App si devono creare i Devices
Ogni device e' identificato dal proprio EUI. Questo codice esadecimale puo' essere letto per esempio lanciando lo sketch FirstConfiguration degli esempi della libreria MKRWAN



Si passa poi alla programmazione Arduino.
Il dispositivo MKR1300 viene attivato come ABP (activation by personalization) e non OTAA. Mi e' stato spiegato sul forum di Arduino che Dragino LG-01 e' un gateway monocanale e gestisce solo ABP

E' stato modificato lo script di esempio LoraSendandReceive (eliminado la parte di ricezione che non mi serve). In giallo le modifiche sostanziali
----------------------------------------
#include <MKRWAN.h>

LoRaModem modem;

String devAddr;
String nwkSKey;
String appSKey;

void setup() {
  Serial.begin(115200);
  if (!modem.begin(EU868)) {
    Serial.println("Failed to start module");
    while (1) {}
  };
//chiavi
devAddr = "26011xxxx";
nwkSKey = "C05AB32C3F7B4Dxxxxxxxxxxxxxxxxxx";
appSKey = "1C8567078CB4613B168xxxxxxxxxxxxxx";

    int connected = modem.joinABP(devAddr, nwkSKey, appSKey);
    if (!connected) {
    Serial.println("Errore di connessione");
    while (1) {}
  }
    {
    Serial.println("connesso");
    }
}

void loop() {
  modem.setPort(3);
  modem.setADR(true);
  modem.dataRate(5);
  delay(5000);
  modem.minPollInterval(60);
  
  String msg = "Luca";


  int err;
  modem.beginPacket();
  modem.print(msg);
  err = modem.endPacket(false);
  if (err > 0) {
    Serial.println("Message sent correctly!");
  } else {
    Serial.println("Error sending message :(");
  }

  delay(20000);
}
----------------------------------------

Ed ecco apparire i dati sul cloud





In questo modo i dati sono pero' abbastanza inutili ..
Per processarli sullla propria macchina conviene abilitare una Integration dalla console di TTN ed nel mio caso in particolare il Data Storage


con questa modalita' i dati vengono conservati per 7 giorni

sul servizio Swagger



da cui  i dati possono essere scaricati mediante una chiamata CURL (dopo aver autorizzato il servizio mediante apposita chiave)

curl -X GET --header 'Accept: application/json' --header 'Authorization: key ttn-account-v2.p-Sxxxxxxx' 'https://hello_world_mkr1300.data.thethingsnetwork.org/api/v2/query'

e questo e' un esempio di dato ricevuto 

{"device_id":"mkr1300_1","raw":"THVjYTI=","time":"2019-04-05T08:54:01.208249737Z"}

altrimenti si possono scaricare i dati mediante Python con 

-----------------------------------------------------
import time
import ttn

app_id = "hello_world_mkr1300"
access_key = "ttn-account-v2.g_-r8AT6eTxxxxxxxxxxxxxxxxxxxxxxxxxx"

def uplink_callback(msg, client):
  print("Received uplink from ", msg.dev_id)
  print(msg)
  print("\n")

handler = ttn.HandlerClient(app_id, access_key)

# using mqtt client
mqtt_client = handler.data()
mqtt_client.set_uplink_callback(uplink_callback)
mqtt_client.connect()
time.sleep(600)
mqtt_client.close()
---------------------------------------------------

i dati ricevuti sono molto piu' dettagliati rispetto a quelli di Swagger

('Received uplink from ', u'mkr1300_1')
MSG(dev_id=u'mkr1300_1', counter=177, app_id=u'hello_world_mkr1300', payload_raw=u'THVjYTI=', hardware_serial=u'A8610A3233258909', port=3, metadata=MSG(location_source=u'registry', data_rate=u'SF7BW125', modulation=u'LORA', altitude=50, longitude=11.290198, airtime=51456000, coding_rate=u'4/5', frequency=868100000, gateways=[MSG(gtw_id=u'eui-a840411bf188ffff', timestamp=2951977680, longitude=11, rf_chain=0, snr=7.8, time=u'2019-04-05T08:58:15.615108Z', latitude=43.111, rssi=-62, channel=7)], time=u'2019-04-05T08:58:15.719069012Z', latitude=43.758617))


 

giovedì 4 aprile 2019

Python API per TheThingsNetwork

Per interagire con le API di TheThingsNetwork via Python si deve prima installare la libreria via Python

pip install ttn

in seguito e' preferibile creare una Access Key appposita per l'accesso Python andando in Console di TTN Application/Nome Applicazione/Settings/Access Key e creare una nuova chiave che abbia i permessi per Settings/Devices/Messages (non e' strettamente necessario ma essendo uno script  puo' essere utile avere il controllo completo

--------------------------------------------------------------
import time
import ttn

app_id = "hello_world_mkr1300"
access_key = "mettere qui la access key prima generata"

def uplink_callback(msg, client):
  print("Received uplink from ", msg.dev_id)
  print(msg)

handler = ttn.HandlerClient(app_id, access_key)

# using mqtt client
mqtt_client = handler.data()
mqtt_client.set_uplink_callback(uplink_callback)
mqtt_client.connect()
time.sleep(60)
mqtt_client.close()

# using application manager client
app_client =  handler.application()
my_app = app_client.get()
print(my_app)
my_devices = app_client.devices()
print(my_devices)
--------------------------------------------------------------

Questo semplice script usa mqtt ed attende per 60 secondi eventuali messaggi di uplink dai device e poi nella parte in arancione  le configurazioni della app 

mercoledì 3 aprile 2019

Monostable, Bistable, Astable Multivibrator 555

Un piccolo promemoria di definizioni

Fonte Wikipedia. Configurazione Monostabile


Monostable: questa configurazione, detta anche One Shot, riceve un impulso e come conseguenza genera un impulso in uscita (indipendentemente dalla lunghezza dell'input) di una durata pari alla configurazione della circuito RC (tempo di carica). E' simile ad un Schmitt Trigger ma questo muta la lunghezza della riposta in base alla lunghezza dell'input

Bistable: anche detto Flip-Flop. Per ogni impulso in ingresso cambia il proprio stato da 0 a 1 e da 1 a 0

Astable : genera con continuita' una onda quadra. Puo' essere visto come due Monostabiti in sequenza in cui il primo out e' usato come ingresso del secondo

Aggiungere libreria ad un progetto Cmake

Abituato a -L -I per includere una libreria in un progetto C (tipo qui) mi sono dovuto convertire a CMake. Per includere una libreria (sia in Eclipse che in KDevelop), per esempio NCurses, si deve editare il file  CMakeLists.txt e aggiungere la riga

target_link_libraries(nome_progetto ncurses)

Update MKRWAN1300 firmware

AGGIORNAMENTO : come suggerito dal forum di Arduino c'e' un metodo molto piu' semplice. Si aggiorna la libreria MKRWAN e poi si lancia lo skecth MKRWANFWUpdate_standalone. Nella directory della libreria c'e' l'ultimo firmware disponibile senza la necesssita' di scaricarlo a parte



Per aggiornare il firmware di una Arduino MKR1300 si parte scaricando il firmware compilato da link https://github.com/arduino/mkrwan1300-fw/releases


Al momento di scrivere questa nota l'ultima release e' la 1.1.6 (la 1.1.9 non risulta in formato bin) mentre nella Mkr1300 che mi e' arrivata e' montato un ARD-078 1.1.5

Si copia il file mlm32l07x01.bin nella stessa directory dove e' presente lo sketch MKRWANFWUpdate_standalone incluso negli esempi della libreria MKRWAN e si lancia il comando da terminale

echo -n "const " > fw.h && xxd -i mlm32l07x01.bin >> fw.h

si lancia quindi  lo sketch ed aprendo il terminale seriale si vedranno i seguenti comandi


Wrote and verified address 0x08012700 (98%)
 Wrote and verified address 0x08012800 (98%)
 Wrote and verified address 0x08012900 (98%)
 Wrote and verified address 0x08012a00 (99%)
 Wrote and verified address 0x08012b00 (99%)
 Wrote and verified address 0x08012c00 (99%)
 Wrote and verified address 0x08012d00 (100%)
 Done.

Starting execution at address 0x08000000... done.
Flashing ok :)
ARD-078 1.1.6

venerdì 29 marzo 2019

Dragino LG01 Lora Gateway su TheThingsNetwork

Un gateway Lora e' un dispositivo che legge il traffico Lora e lo rilancia su Internet e nel caso sul cloud di TheThingsNetwork (abbreviato TTN)
Ci sono molti Gateway Lora compreso quello originale Arduino ma a causa dei costi (Lora Gateway Arduino costa circa 350 euro) ho preso Dragino LG01, a canale singolo 868 MHz (standard Italia) che e' molto simile ad una Arduino Yun (si  programma via Arduino IDE con la libreria Bridge)


Le istruzioni ufficiale si trovano al link seguente
https://wiki.dragino.com/index.php?title=Connect_to_TTN#Create_TTN_account

(il manuale completo si trova qui)

Ma prima di iniziare si deve creare un account se TheThingsNetwork, andare nella console a creare un Gateway


Per il codice identificativo si puo'utilizzare il Mac Address (riempiendo i byte rimanenti per arrivare a 16 con FF) ed impostando Legacy Packet Forwarder

Successivamente ci si collega alla WiFi aperta del Dragino al 10.130.1.1 (od alla porta LAN) con le credenziali root/dragino. Il sistema di base e' OpenWRT per cui e' semplice configurare l'access point in WPA e controllare che il gateway sia connesso ad Internet


Si va poi sul Dragino e si scarica da qui  il file single_pkt_fwd_v004.hex. Attenzione : il file sul server si chiama single_pkt_fwd_v004.ino.hex... ho dovuto rinominare il file
Poi si va Sensor/Flash MCU, si seleziona il file sopra indicato e si aggiorna. Da questa pagina si puo' controllare che il caricamento sia avvenuto in modo corretto



Si imposta la radio sullo standard europeo


Si configura il Lora Gateway per dialogare con TheThingsNetwork indicando l'indirizzo router.eu.thethings.network, ed il Gateway ID che e' riportato nella consolle di TTN (ma senza i primi 4 caratteri ovvero senza eui-)




e si seleziona LorWan come IoT server


Se tutto e' andato bene sulla consolle di TTN il gateway sara' visto come online 

giovedì 28 marzo 2019

MPU9250 9DOF e filtro Madgwick

La MPU9250 e' un dispositivo con accelerometro, giroscopio e magnetometro triassiale


Per interfacciare l'MPU9250 ho usato la libreria https://github.com/sparkfun/MPU-9250_Breakout che funziona solo con schede Arduino con processore SAM (quindi MKR)

Nello sketch degli esempi e' stato aggiunto il filtro Madgwick

5852 dati

Pitch (filtrato)
media 60.475°
std 0.22°
skew -0.597

Roll (filtrato)
media 50.471°
std 0.34°
skew -0.113

Yaw (filtrato)
media 209.56°
std 0.54°
skew 0.2


---------------------------------------------------------------------------
#include <SparkFunMPU9250-DMP.h>
#include  <MadgwickAHRS.h> 



MPU9250_DMP imu;
Madgwick  MadgwickFilter;


void setup() 
{
  Serial.begin(115200);

   MadgwickFilter.begin(100);  // 100 Hz

  if (imu.begin() != INV_SUCCESS)
  {
    while (1)
    {
      Serial.println("Unable to communicate with MPU-9250");
      Serial.println("Check connections, and try again.");
      Serial.println();
      delay(5000);
    }
  }


  imu.setSensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS);


  imu.setGyroFSR(2000); // Set gyro to 2000 dps
  // Accel options are +/- 2, 4, 8, or 16 g
  imu.setAccelFSR(2); // Set accel to +/-2g
  // Note: the MPU-9250's magnetometer FSR is set at 
  // +/- 4912 uT (micro-tesla's)

  // setLPF() can be used to set the digital low-pass filter
  // of the accelerometer and gyroscope.
  // Can be any of the following: 188, 98, 42, 20, 10, 5
  // (values are in Hz).
  imu.setLPF(5); // Set LPF corner frequency to 5Hz

  // The sample rate of the accel/gyro can be set using
  // setSampleRate. Acceptable values range from 4Hz to 1kHz
  imu.setSampleRate(10); // Set sample rate to 10Hz

  // Likewise, the compass (magnetometer) sample rate can be
  // set using the setCompassSampleRate() function.
  // This value can range between: 1-100Hz
  imu.setCompassSampleRate(10); // Set mag rate to 10Hz

  imu.dmpBegin(DMP_FEATURE_GYRO_CAL |   // Enable gyro cal
              DMP_FEATURE_SEND_CAL_GYRO,// Send cal'd gyro values
              10);         
}

void loop() 
{

  if ( imu.dataReady() )
  {
    
    imu.update(UPDATE_ACCEL | UPDATE_GYRO | UPDATE_COMPASS);
    printIMUData();
  }
}

void printIMUData(void)
{  

  float accelX = imu.calcAccel(imu.ax);
  float accelY = imu.calcAccel(imu.ay);
  float accelZ = imu.calcAccel(imu.az);
  float gyroX = imu.calcGyro(imu.gx);
  float gyroY = imu.calcGyro(imu.gy);
  float gyroZ = imu.calcGyro(imu.gz);
  float magX = imu.calcMag(imu.mx);
  float magY = imu.calcMag(imu.my);
  float magZ = imu.calcMag(imu.mz);

  MadgwickFilter.update(accelX,accelY,accelZ,gyroX,gyroY,gyroZ,magX,magY,magZ) ;

  
  Serial.print(String(accelX) + "," +String(accelY) + "," + String(accelZ));
  Serial.print("," + String(gyroX) + "," + String(gyroY) + "," + String(gyroZ) + ",");
  Serial.print(String(magX) + "," + String(magY) + "," + String(magZ)+ "," );
  Serial.print(String(MadgwickFilter.getPitch())+ "," +String(MadgwickFilter.getRoll())+ "," +String(MadgwickFilter.getYaw()));
  Serial.println();
}

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...