Visualizzazione post con etichetta MKR1000. Mostra tutti i post
Visualizzazione post con etichetta MKR1000. Mostra tutti i post

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();
}

mercoledì 6 marzo 2019

Differenza FreeRTOs su Arduino AVR e SAMD21 e ESP-Wroom-32

La principale differenza nell'implementazione di FreeRTOs in ESP32 ed in Arduino Uno (ovvero AVR ATMega328) e' il fatto che Esp32 e' un processore dual core. FreeRTOs riesce a distribuire il carico del lavoro tra i core. Nell'esempio sottostante (ripreso da qui), fatto girare su Esp-Wroom-32, si vede che il main loop ed il task vengono eseguiti su due core differente in modo parallelo


Viene creato un task generico che fa un solo loop e poi si autodistrugge (vTaskDelete(NULL)) mentre il loop principale continua a rimanere in esecuzione.
-------------------------------------------------------------------------
void setup() {

  Serial.begin(9600);
  delay(1000);

  Serial.print("Setup: Executing on core ");
  Serial.println(xPortGetCoreID());

  xTaskCreate(
                    genericTask,       /* Task function. */
                    "genericTask",     /* String with name of task. */
                    10000,             /* Stack size in words. */
                    NULL,              /* Parameter passed as input of the task */
                    2,                 /* Priority of the task. */
                    NULL);             /* Task handle. */
 delay(2000); 

}

void loop() {
  Serial.print("Main Loop: Executing on core ");
  Serial.println(xPortGetCoreID());
  delay(1000);
}

void genericTask( void * parameter ){
    Serial.print("Created task: Executing on core ");
    Serial.println(xPortGetCoreID());
    vTaskDelete(NULL);
}

-----------------------------------------------------------------------------------------
Setup: Executing on core 1
Created task: Executing on core 0
Main Loop: Executing on core 1
Main Loop: Executing on core 1

Main Loop: Executing on core 1


 Se si usa #include <Arduino_FreeRTOS.h> si vedra' che non esiste nemmeno la funzione xprtoGetCoreID perche' ATMega328 e' un processore single core...i task vengono eseguiti su un unico core dividendo i tick del processore tra i vari task come un time sharing

Le cose non cambiano con la serie Arduino MKR che montano SAM D21 Cortex M0-+ (solo alcuni  Cortex di fascia alta sono multi core) 

venerdì 25 gennaio 2019

MKR1000 Sleep Mode con Interrupt da RTC

Ho ripreso in mano anche la MKR1000 per testare le capacita' di sleep mode in rapporto ad Arduino Uno. La MKR1000 ha un processore completamente differente (un SAMD21  per la precisione) e integra un RTC per cui non ha bisogno di supporto esterno



Un paio di annotazioni
1) La MKR1000 non ha un pulsante di accensione e l'unico modo di spengerla e' staccare la batteria. Cio' e' abbastanza fastidioso

2) In un caso ho perso il controllo della scheda perche' non si vedeva il device tra i dispositivi USB. In questi casi si deve premere in modo ravvicinato nel tempo per due volte il pulsante di reset

3) Per minimizzare il consumo si deve esplicitamente spengere il modulo Wifi, questa operazione non viene eseguita dallo standbymode

4) Le alimentazioni, quando e' presente la sola LiPo, sono a 3.3V. La porta a 5V in alimentazione output e' disponibile solo quando c'e' un cavo USB che alimenta dall'esterno

Il trucco per impostate il risveglio da RTC e' simile a quello visto in questo post. Si setta un'allarme ad una certa ora, poi all'interno del codice di interrupt si setta il nuovo allarme nel futuro. In questo esempio gli allarmi sono spostati nel tempo di un minuto

(il codice e' stato ripreso da questo link originario e leggermente migliorato per le mie esigenze)
----------------------------------------------

#include <RTCZero.h>

#include <WiFi101.h>


RTCZero rtc;

bool matched = false;
int alarmMinutes = 15;

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

/* Change these values to set the current initial date */
const byte day = 25;
const byte month = 1;
const byte year = 19;

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


  WiFi.end();



  rtc.begin();

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

  rtc.setAlarmMinutes(alarmMinutes);
  
  rtc.enableAlarm(rtc.MATCH_MMSS);
  rtc.attachInterrupt(alarmMatch);
}

void loop()
{
  if (matched) {


    matched = false;
    printDate();
    printTime();
    Serial.println();
    delay(1000);
        
    alarmMinutes= (rtc.getMinutes()+1)%60;
    rtc.setAlarmMinutes(alarmMinutes);
    rtc.enableAlarm(rtc.MATCH_SS);
    rtc.attachInterrupt(alarmMatch);

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

void alarmMatch()
{
  matched = true;
}

void printTime()
{
  print2digits(rtc.getHours());
  Serial.print(":");
  print2digits(rtc.getMinutes());
  Serial.print(":");
  print2digits(rtc.getSeconds());
  Serial.println();
}

void printDate()
{
  Serial.print(rtc.getDay());
  Serial.print("/");
  Serial.print(rtc.getMonth());
  Serial.print("/");
  Serial.print(rtc.getYear());
  Serial.print(" ");
}

void print2digits(int number) {
  if (number < 10) {
    Serial.print("0");
  }
  Serial.print(number);
}

giovedì 29 giugno 2017

OBD e MKR1000

Un breve esempio su come interfacciare una Arduino MKR1000 con un trasmettitore ODB Wifi



l'ELM327 OBD con trasmissione WiFi si comporta come un hotspot WiFi senza nessuna autenticazione. Se ci si collega all'indirizzo 192.168.0.10 con telnet sulla porta 35000 si puo' interagire con il sistema diagnostico dell'auto.
In questo esempio si interroga il numero di giri motore: per prima cosa si inviano i codici ATZ e AT SP 0 per resettare ELM327 e per definire il protocollo di comunicazione, in seguito si invia la richiesta 010C per ottenere il numero di giri motore (vedi qui)

----------------------------------------------------------
#include <SPI.h>
#include <WiFi101.h>

char ssid[] = "WiFi_OBDII"; //  your network SSID (name)
char pass[] = "";    // your network password (use for WPA, or use as key for WEP)

int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

IPAddress server(192,168,0,10);
WiFiClient client;



void setup() {
  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid);

    // wait 10 seconds for connection:
    delay(10000);
  }

WiFi.maxLowPowerMode()

  // you're connected now, so print out the status:
  printWiFiStatus();

 if (client.connect(server, 35000)) {
    Serial.println("connected");
  } else {
    Serial.println("connection failed");
  }
  client.println("ATZ");
  delay(2000);
  client.println("AT SP 0");
  delay(2000);

}


void loop() {
  client.println("010C");

  while (client.available())
    {
      char c = client.read();
      Serial.print(c);
    }
  Serial.println();
  delay(1000);
}


void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

------------------------------------------

Questo e' il log di una sessione. L'Elm327 puo' rispondere con

Searching....
No data
Engine Off

nel caso in cui il sistema non riesca ad interrogare il numero di giri motore. Altrimenti si ha un codice di 4 gruppi del tipo 41 0C a conferma della richiesta e poi due byte (byte alto e byte basso) che indicano il numero di giri motore moltiplicato per 4
------------------------------------------
SSID: WiFi_OBDII
IP Address: 192.168.0.13
signal strength (RSSI):-37 dBm
connected
ATZ



ELM327 v1.5

>
AT SP 0
OK

>
010C
SEARCHING...

41 0C 0C 84


>010C
41 0C 0C 8C


>
010C
41 0C 0C 90

>
010C
41 0C 0C 70

>
010C
41 0C 0C 8C

>
010C
41 0C 0C 78


>
010C
41 0C 0C 84


>010C
41 0C 0C 88


>
010C
41 0C 0C 80


>
010C
41 0C 0C 88

Geologi

  E so anche espatriare senza praticamente toccare strada asfaltata