mercoledì 20 marzo 2019

Mkr1010 Wake up da pin e risparmio energetico

Un sistema rapido per mettere in sleep mode una MKR1010 e risvegliarla tramite un interrupt sul pin 8 (che puo' essere simulato connettendo il pin 8 al GND)



-----------------------------------------------------------------
#include "ArduinoLowPower.h"

// Pin per wakeup
const int pin = 8;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(pin, INPUT_PULLUP);
  LowPower.attachInterruptWakeup(pin, funzione, CHANGE);
}

void loop() {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    LowPower.sleep();
}

void funzione {
// qui il codice da eseguire durante l'interrupt
}

Casio FP-200

Un nuovo piccolino si e' aggiunta alla collezione, Casio FP-200 direttamente dal 1982 con processore 80c85, in pratica un concorrente dell'M10

Prima di tutto una nota : attenzione all'alimentazione. Il jack laterale e' un input per un 6V 1A ma con il positivo sull'esterno e non sul pin centrale (c'e' anche una alimentazione con 4 batterie AA nascoste in cassetto sul lato superiore)


La macchina doveva essere funzionante ma all'accensione si presentava immancabilmente questo messaggio Memory illegal con 0 Bytes di memoria libera e premendo Invio gli errori SN Error, FC Error. La documentazione on line e' molto scarsa ma ho trovato il Service Manual ed un User Manual (in tedesco) da cui si legge che in questi casi si deve digitare RESET e premere Invio


 

I banchi di memoria sono sul retro coperti da un coperchio


Schermata di modalita' Basic e CETL (uno spreadsheet integrato)



Da notare la presenza di una porta Centronics


martedì 19 marzo 2019

Arduino MKR1010 ed allarme ricorsivo con RTCZero e risparmio energetico

Aggiornamento: questo post e' molto simile al precedente

Lo scopo di questo script e' generare ogni 10 secondi un allarme che risvegli dall standby la MKR1010 per effettuare una operazione e poi la riaddormenti in staandy


Una volta in Sleep Mode in consumo e' inferiore a 10 mA ovvero e' sotto la soglia di misura del mio strumento

Con questa configurazione il consumo e' di circa 14 mA

Attenzione : quando viene lanciato il programma il processore va in standby e viene disabilitata la porta USB. Per effettuare un nuovo upload si deve premere il tasto di reset per due volte in modo veloce
--------------------------------------------------------------------------
#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 00;
const byte hours = 17;

/* Change these values to set the current initial date */
const byte day = 17;
const byte month = 11;
const byte year = 15;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  rtc.begin();

  rtc.setTime(hours, minutes, seconds);
  rtc.setDate(day, month, year);

  rtc.setAlarmTime(17, 00, 10);
  // Abilita l'allarme quando i secondi sono uguali alla soglia
  rtc.enableAlarm(rtc.MATCH_SS);
  rtc.attachInterrupt(alarmMatch);

  rtc.standbyMode();
}

void loop()
{
  rtc.standbyMode();    // Sleep until next alarm match
}

void alarmMatch()

  // INVERTE LO STATO DEL LED
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  // Setta il nuovo allarme 10 secondi nel futuro
  rtc.setAlarmSeconds((rtc.getSeconds() + 10) % 60);
}

Complimentary filter con MPU6050 ed Arduino

Per terminare la serie, dopo Kalman e Madgwick un esempio di Complementary Filter
Dal punto di vistra computazionale e' il piu' semplice perche' si tratta di una sola formula
senza ricorsione e matrici

angle = 0.98 *(angle+gyro*dt) + 0.02*acc
(i parametri possono essere ottimizzati)

Una breve statistica (per raffronto con le prove precedenti)

Nr campioni : 20121
Media : -11.97
Range : 0.41
Std : 0.02
Varianza : 0.0005
Skewness :0.62

Il codice e' stato adattato da qui
-----------------------------------------------------------------------
// Complementary filter

#include <Wire.h>

int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperature;

float pitch=0;
float pitchAcc;
float P_CompCoeff= 0.98;
unsigned long delta_t,old_time;


void ComplementaryFilter(int ax,int ay,int az,int gy,int gz) {
 long squaresum=(long)ay*ay+(long)az*az;
 delta_t = micros()- old_time;
 old_time = micros();

 pitch+=((-gy/32.8f)*(delta_t/1000000.0f)); 
 pitchAcc =atan(ax/sqrt(squaresum))*RAD_TO_DEG;
 pitch =P_CompCoeff*pitch + (1.0f-P_CompCoeff)*pitchAcc;
}


void setup() {
Serial.begin(115200);
  //Inizio configurazione clock interno 
  
  Wire.beginTransmission(0x68);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission();
  
  // Inizializzazione Accelerometro intervallo di 8g Fattore di scala 4096
  Wire.beginTransmission(0x68);
  Wire.write(0x1C);
  Wire.write(0x10);
  Wire.endTransmission();
  
  // Inizializzazione Gyro Intervallo di 500 deg/sec LSB (fattore di scala) 65.5 deg/s
  Wire.beginTransmission(0x68);
  Wire.write(0x1B);
  Wire.write(0x08);
  Wire.endTransmission();
  old_time = micros();
}

void loop() {
  Wire.beginTransmission(0x68);
  Wire.write(0x3B);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 14);
  while (Wire.available() < 14);
  axRaw = Wire.read() << 8 | Wire.read();
  ayRaw = Wire.read() << 8 | Wire.read();
  azRaw = Wire.read() << 8 | Wire.read();
  temperature = Wire.read() << 8 | Wire.read();
  gxRaw = Wire.read() << 8 | Wire.read();
  gyRaw = Wire.read() << 8 | Wire.read();
  gzRaw = Wire.read() << 8 | Wire.read();

  /*Serial.print(axRaw/4096.0); Serial.print(",");
  Serial.print(ayRaw/4096.0); Serial.print(",");
  Serial.print(azRaw/4096.0); Serial.print(",");
  Serial.print(gxRaw/131.0); Serial.print(",");
  Serial.print(gyRaw/131.0); Serial.print(",");
  Serial.println(gzRaw/131.0);*/
  ComplementaryFilter(axRaw,ayRaw,azRaw,gyRaw,gzRaw);
  Serial.println(pitch);
  delay(2);
}

lunedì 18 marzo 2019

Filtro Madgwick con MPU6050 ed Arduino

Un test del filtro di Madgwick , un possibile sostituto per il filtro Kalman su processori meno potenti

La libreria per Arduino si trova a questo link

Da notare prima di tutte che :

1) la finestra di campionamento del filtro in Madgwick.begin aumenta o diminuisce la velocita' di convergenza dei dati

2) i dati devono essere inseriti nel filtro con le corrette unita' fisiche (m/sec2 e deg/sec) e non con i dati raw in uscita dal sensore

3) la libreria permette di inserire anche i dati di un sensore magnetico (che non e' pero' presente nella 6050)

Una prova veloce con il filtro Madgwick e MPU statica

Nr campioni : 73071
Media : 9.82
Range : 0.56
Std : 0.04
Varianza : 0.001
Skewness : -0.01

Nelle stesse condizioni ma con filtro Kalman

Nr campioni : 16568
Media : 9.84
Range : 0.44
Std : 0.04
Varianza : 0.001
Skewness : 0.05


Aggiornamento : per calcolare il valore della Temperatura in gradi Celsius si usa la formula

T = (lettura/340.0)+36.53

--------------------------------------------------------------------------------------------
#include  <MadgwickAHRS.h> 
#include <Wire.h>

int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperature;


Madgwick  MadgwickFilter;

void setup() {
Serial.begin(115200);
  //Inizio configurazione clock interno 
  
  Wire.beginTransmission(0x68);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission();
  
  // Inizializzazione Accelerometro intervallo di 8g Fattore di scala 4096
  Wire.beginTransmission(0x68);
  Wire.write(0x1C);
  Wire.write(0x10);
  Wire.endTransmission();
  
  // Inizializzazione Gyro Intervallo di 500 deg/sec LSB (fattore di scala) 65.5 deg/s
  Wire.beginTransmission(0x68);
  Wire.write(0x1B);
  Wire.write(0x08);
  Wire.endTransmission();

  // Inizializzazione LPF (Filtro passa basso) 43 Hz
  Wire.beginTransmission(0x68);
  Wire.write(0x1A);
  Wire.write(0x03);
  Wire.endTransmission();
  
  MadgwickFilter.begin(100);  // 100 Hz

}

void loop() {
  Wire.beginTransmission(0x68);
  Wire.write(0x3B);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 14);
  while (Wire.available() < 14);
  axRaw = Wire.read() << 8 | Wire.read();
  ayRaw = Wire.read() << 8 | Wire.read();
  azRaw = Wire.read() << 8 | Wire.read();
  temperature = Wire.read() << 8 | Wire.read();
  gxRaw = Wire.read() << 8 | Wire.read();
  gyRaw = Wire.read() << 8 | Wire.read();
  gzRaw = Wire.read() << 8 | Wire.read();

  /*Serial.print(axRaw/4096.0); Serial.print(",");
  Serial.print(ayRaw/4096.0); Serial.print(",");
  Serial.print(azRaw/4096.0); Serial.print(",");
  Serial.print(gxRaw/65.5); Serial.print(",");
  Serial.print(gyRaw/65.5); Serial.print(",");
  Serial.println(gzRaw/65.5);*/
  MadgwickFilter.updateIMU(gxRaw/65.5,gyRaw/65.5,gzRaw/65.5,axRaw/4096.0,ayRaw/4096.0,azRaw/4096.0) ;
  Serial.println(MadgwickFilter.getRoll());
  //ROLL  = MadgwickFilter.getRoll();
  //PITCH = MadgwickFilter.getPitch();
  //YAW   = MadgwickFilter.getYaw();
  delay(2);
}

venerdì 15 marzo 2019

RS485 su Arduino

Dovendo acquisire dati in un posto in cui non posso usare nessuna trasmissione radio e dovendo mettere ad almeno 15-20 m il sensore dal micro controllore cercavo una trasmissione seriale "robusta" ed ho voluto provare la seriale RS485 di tipo industriale che e' data per trasmissioni fno al chilometro (ovviamente dipende dalla velocita' di trasmissione, qualita' dei cavi ecc.)


L'utilizzo e' molto trasparente. Si collega il cavo A+ con tutti i dispositivi presenti sulla linea di comunicazione (possono essere piu' di due)  ed il cavo B-

Il connettore TTL-RS485 deve essere semplicemente alimentato e collegato alla seriale TTL di Arduino sui pin D0 e D1


Sul lato PC il dongle RS485-USB e' stato riconosciuto in modo immediato da Linux

E visto che ci siamo comprati un oscilloscopio perche' non usarlo


Progetto Due

Il progetto due prevede un sistema ad alimentazione solare con una Arduino MKR1400  collegata ad un accelerometro ADXL345 che invia un SMS nel momento in cui il sensore registra un movimento



Per l'alimentazione solare ho usato un modulo basato su CN3065 per la ricarica della LiPo con una LiPo da 2000 mAh ed un pannello solare da 0.5W. I cavi sono stati saldati sulla piastra invece su usare i connettori JST (per la batteria ed il pannello solare ci sono sia i connettori JST che le basi per saldare...per l'output su SYS ho collegato i cavi dietro al JST)


Le connessioni sono piuttosto semplici

ADXL345 : il pin di interrupt e' collegato a  D8 di MKR. Gli altri cavi sono 3.3V, GND SDA ed SCL in modo standard



Un problema che e' stato riscontrato e' che l'interrupt 1 dell'ADXL345 passa da uno stato High ad uno Low mentre la MKR si aspetta l'esatto contrario per attivare l'interrupt
Per questo motivo il collegamento tra INT1 di ADXL345 e D8 di MKR1400 passa attraverso un circuito di logic inverter (in pratica una porta NOT) realizzato con un transistor 2n2222a
Sull'IN e' stato collegato INT1 di ADXL345 e su out D8 di MKR




Circuito di prova...l'interrutore serve a simulare il cambio di stato del pin
Per la versione finale sara' usato l'integrato SN74HC04N, un integrato con 6 porte NOT a tensioni tra 2 e 6V



Il consumo in standby e' di circa 20 mA (mi aspettavo di meno...forse ho sbagliato qualcosa??)




mentre quando viene attivato il GSM e si invia l'SMS la corrente raggiunge un picco di circa 220 mA con valori stabili per una decina di secondi sopra i 100 mA

Questo e' lo sketch di funzionamento
----------------------------------------------------
#include "ArduinoLowPower.h"
#include <SparkFun_ADXL345.h> 
#include <MKRGSM.h>


// Pin per wakeup
const int interruptPin = 8;
// GSM
GSM gsmAccess;
GSM_SMS sms;

ADXL345 adxl = ADXL345();           
volatile int invia = 0;


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT);
  delay(5000);
  adxl.powerOn();                     
  adxl.setRangeSetting(2);
  adxl.setInterruptLevelBit(1);
  adxl.setSpiBit(0);                  
  adxl.setActivityXYZ(1, 1, 1);       
  adxl.setActivityThreshold(50);      
  adxl.setTapDetectionOnXYZ(1, 1, 1);
  adxl.setTapThreshold(50);         
  adxl.setTapDuration(55);    
  adxl.ActivityINT(1);
  adxl.singleTapINT(1);
      
  LowPower.attachInterruptWakeup(interruptPin, funzione, CHANGE);
}

void loop() {  

if (invia == 1){
       bool connected = false;
       digitalWrite(LED_BUILTIN, HIGH);
       delay(500);
       digitalWrite(LED_BUILTIN, LOW);
       delay(500);
       while (!connected) {
        if (gsmAccess.begin() == GSM_READY) {
          connected = true;
          } 
       delay(1000);
       sms.beginSMS("+393471xxxxxx");
       sms.print("Luca mi ha toccato");
       sms.endSMS(); 
       invia = 0;  
       }
  }    

LowPower.sleep();
}

void funzione() {
   invia = 1;
}

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...