Archivi categoria: IoT

Commenti al Firmware Arduino 0.18.08

Revisione 0.03

La nuova versione 0.18.08 del Firmware Arduino permette di realizzare l’Unità Didattica Il Semaforo Arduino.

L’Unità Didattica prevede di realizzare un modello di semaforo con tre LED colorati rosso, giallo e verde, collegati ai pin 2, 4 e 6.

All’avvio, se la sezione SEMAFORO nello sketch è attivata e la variabile semaforo_stato è automatico, allora si avvia il ciclo continuo di accensione e spegnimento con dati ritardi delle luci.

Seguirà l’ implementazione del comando
semaforo automatico|disabilitato|rosso|giallo|verde
da utilizzare nel consueto modo da remoto mediante canale USB .

Il codice sorgente relativo all’Unità Didattica viene attivato con

#define SEMAFORO

In questo caso vengono definite ed inizializzate le seguenti variabili:

#if defined(SEMAFORO)
      String semaforo_stato = “automatico”;
  // manuale|automatico|disabilitato
     String semaforo_luce = “rossa”; // rossa|gialla|verde
     int semaforo_durata_rosso = 3; // in secondi
     int semaforo_durata_giallo = 1; // in secondi
     int semaforo_durata_verde = 3; // in secondi
     int semaforo_pin_rosso = 2;
     int semaforo_pin_giallo = 4;
     int semaforo_pin_verde = 6;
#endif

 

Quindi nella funzione setup()

#if defined(SEMAFORO)

     pinMode(semaforo_pin_rosso, OUTPUT);
     pinMode(semaforo_pin_giallo, OUTPUT);
     pinMode(semaforo_pin_verde, OUTPUT);

#endif

 

E nella funzione loop()

#if defined(SEMAFORO)

if(semaforo_stato == “automatico”)
{
   while(true) {

      digitalWrite(semaforo_pin_rosso, HIGH);
      delay(1000 * semaforo_durata_rosso);
      digitalWrite(semaforo_pin_rosso, LOW);

      digitalWrite(semaforo_pin_giallo, HIGH);
      delay(1000 * semaforo_durata_giallo);
      digitalWrite(semaforo_pin_giallo, LOW);

      digitalWrite(semaforo_pin_verde, HIGH);
      delay(1000 * semaforo_durata_verde);
      digitalWrite(semaforo_pin_verde, LOW);
   }
}
#endif

Arduino Firmware 0.18.08

#define FIRMWARE_VERSION "0.18.08"

/*Language: Wiring/Arduino Serial Console 115200 baud \n ASCII 10 */ 

#define WATCH_DOG_ENABLED
#define LCD_ENABLED // pin 4,5,6,7,8,9 reserved
#define MACRO_01 // per utilizzi specifici

#define SEMAFORO
/* 001
   Si osservi l'utilizzo del C preprocessor,
   macro processor, per compilare il minor codice
   possibile al fine di poter utilizzare
   microcontroller con modeste risorse.
   Il generatore codice sorgente firmware
   provvederà a includere le opportune
   righe di definizione variabili 
   per il prepocessor
*/

// #include <Wire.h>

#if defined(WATCH_DOG_ENABLED)
#include <avr/wdt.h>
#endif
/* 002
   Importante predisposione dei microcontroller:
   watch dog al livello hardware
   che firmware successivi andranno a
   implementare in modo migliore.
   Dovranno tener conto anche del tipo di scheda
   che esegue il firmware, infatti Uno e Mega
   hanno gestione diverse del watch dog 
   a livello hardware
*/
#if defined(LCD_ENABLED)
#include <LiquidCrystal.h>
#endif
/* 003
   La connessione LCD al controller
   adottata lo standard DF-Robots
*/

#if defined(TEENSYDUINO)
/* 004
   Riconoscimento della scheda 
   che esegue il Firmware
*/
// --------------- Teensy -----------------
#if defined(__AVR_ATmega32U4__)
#define BOARD "Teensy 2.0"
#elif defined(__AVR_AT90USB1286__)
#define BOARD "Teensy++ 2.0"
#elif defined(__MK20DX128__)
#define BOARD "Teensy 3.0"
#elif defined(__MK20DX256__)
#define BOARD "Teensy 3.2" // and Teensy 3.1 (obsolete)
#elif defined(__MKL26Z64__)
#define BOARD "Teensy LC"
#elif defined(__MK64FX512__)
#define BOARD "Teensy 3.5"
#elif defined(__MK66FX1M0__)
#define BOARD "Teensy 3.6"
#else
#error "Unknown board"
#endif

#else // --------------- Arduino ------------------
#if defined(ARDUINO_AVR_ADK)
#define BOARD "Mega Adk"
#elif defined(ARDUINO_AVR_BT) // Bluetooth
#define BOARD "Bt"
#elif defined(ARDUINO_AVR_DUEMILANOVE)
#define BOARD "Duemilanove"
#elif defined(ARDUINO_AVR_ESPLORA)
#define BOARD "Esplora"
#elif defined(ARDUINO_AVR_ETHERNET)
#define BOARD "Ethernet"
#elif defined(ARDUINO_AVR_FIO)
#define BOARD "Fio"
#elif defined(ARDUINO_AVR_GEMMA)
#define BOARD "Gemma"
#elif defined(ARDUINO_AVR_LEONARDO)
#define BOARD "Leonardo"
#elif defined(ARDUINO_AVR_LILYPAD)
#define BOARD "Lilypad"
#elif defined(ARDUINO_AVR_LILYPAD_USB)
#define BOARD "Lilypad Usb"
#elif defined(ARDUINO_AVR_MEGA)
#define BOARD "Mega"
#elif defined(ARDUINO_AVR_MEGA2560)
#define BOARD "Mega 2560"
#elif defined(ARDUINO_AVR_MICRO)
#define BOARD "Micro"
#elif defined(ARDUINO_AVR_MINI)
#define BOARD "Mini"
#elif defined(ARDUINO_AVR_NANO)
#define BOARD "Nano"
#elif defined(ARDUINO_AVR_NG)
#define BOARD "NG"
#elif defined(ARDUINO_AVR_PRO)
#define BOARD "Pro"
#elif defined(ARDUINO_AVR_ROBOT_CONTROL)
#define BOARD "Robot Ctrl"
#elif defined(ARDUINO_AVR_ROBOT_MOTOR)
#define BOARD "Robot Motor"
#elif defined(ARDUINO_AVR_UNO)
#define BOARD "Uno"
#elif defined(ARDUINO_AVR_YUN)
#define BOARD "Yun"
// These boards must be installed separately:
#elif defined(ARDUINO_SAM_DUE)
#define BOARD "Due"
#elif defined(ARDUINO_SAMD_ZERO)
#define BOARD "Zero"
#elif defined(ARDUINO_ARC32_TOOLS)
#define BOARD "101"
#else
#define BOARD "Unknown board"
#endif
#endif

boolean lcd_print_sec = true;

#if defined(LCD_ENABLED)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// lcd_print_sec   = true;
#endif


#if defined(SEMAFORO)
  
  String semaforo_stato       = "automatico";  // manuale|automatico|disabilitato
  String semaforo_luce        = "rossa";       // rossa|gialla|verde
  int semaforo_durata_rosso   = 3;              // in secondi 
  int semaforo_durata_giallo  = 1;              // in secondi
  int semaforo_durata_verde   = 3;              // in secondi
  int semaforo_pin_rosso      = 2;              
  int semaforo_pin_giallo     = 4;             
  int semaforo_pin_verde      = 6;             
  
#endif

boolean request_response = true;
String end_response = "Done ";
/* 006
   Il protocollo sviluppato utilizza 
   lo schema naturale request / response
   con stringhe di testo e terminate da capo riga
   Il Firmware prevede di poter terminare 
   la risposta del controller con una riga
   che inizia con Done ...
*/

// const int TIMEOUT_CICLE = 200;
int CYCLE_DELAY   = 20;
/* 007
   CYCLE_DELAY è il ritardo nel ciclo principale
   che realizza il poll mediante porta USB
   verrà gestito il comando che
   permetterà di variare il contenuto
*/

byte portType[54];
/* 008
   Matrice fondamentale che contiene la
   configurazione dei PIN del microcontroller
   che è assegnata dal comando CONFIG
*/

char incomingChar = '\0';
String incomingString = "";
String command    = "";
String parameters = "";
String parameter  = "";
String tempString = "";
String tempString1= "";
String tempString2= "";
int port = 0;
String portvalue  = "";
String portname   = "";
int pos  = 0;
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int tempInt     = 0;
char tempChar   = '\0';
int inPortMap[7];

int loop_100    = 0;
int loop_10000  = 0;
/* 009
   variabili che realizzano due cicli
   demoltiplicati rispetto al ciclo principale
   ovvero loop_100 diventa vera ogni cento 
   cicli principali   
*/


void setup() 
{

#if defined(WATCH_DOG_ENABLED)
   wdt_enable(WDTO_8S);
#endif

   Serial.begin(115200);
   delay(50);
#if defined(LCD_ENABLED)
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("IoT ");
lcd.print(FIRMWARE_VERSION);
#endif

   for (int i = 0; i <= 53; i++)
   {
      portType[i] = 0; 
   }

/* 010
   La matrice portType contiene la configurazione
   dei PIN del microcontroller

   Le Schede Mega hanno
      54 port digital, from 9 to 53
      16 port AD, from 0 to 13
   
   I valori in portType significano:

      0   not defined
      1   IN
      2   OUT
      3   PWM
      4   LCD
      5   I2C
      6   SPI
      7   SERIAL
*/

#if defined(LCD_ENABLED)
// 8, 9, 4, 5, 6, 7
portType[4] = 4;
portType[5] = 4;
portType[6] = 4;
portType[7] = 4;
portType[8] = 4;
portType[9] = 4;
#endif

#if defined(SEMAFORO)

pinMode(semaforo_pin_rosso, OUTPUT);
pinMode(semaforo_pin_giallo, OUTPUT);
pinMode(semaforo_pin_verde, OUTPUT);
#endif

   // Wire.begin();

}



void loop() 
{
  loop_100 = loop_100 + 1;
  if (loop_100 = 100)
  {
    loop_100 = 0;
    loop_10000 = loop_10000 +1;
  }

  if (loop_10000 = 100)
  {
    loop_10000=0;
  }

  #if defined(WATCH_DOG_ENABLED)
     wdt_reset();
  #endif
  #if defined(LCD_ENABLED)
     if (lcd_print_sec)
     {
        lcd.setCursor(0,1);
        lcd.print(millis()/1000);
     }
  #endif

#if defined(SEMAFORO)

if(semaforo_stato == “automatico”)
{
while(true) {

digitalWrite(semaforo_pin_rosso, HIGH);
delay(1000 * semaforo_durata_rosso);
digitalWrite(semaforo_pin_rosso, LOW);

digitalWrite(semaforo_pin_giallo, HIGH);
delay(1000 * semaforo_durata_giallo);
digitalWrite(semaforo_pin_giallo, LOW);

digitalWrite(semaforo_pin_verde, HIGH);
delay(1000 * semaforo_durata_verde);
digitalWrite(semaforo_pin_verde, LOW);

}
}




   if (Serial.available() > 0) 
   {
      incomingChar = Serial.read();
      if (incomingChar == '\n') 
      {
         execCommand();
         incomingString = "";
      }
      else 
      {
         incomingString += incomingChar;
         if (incomingString.length() > 254) 
         {
            Serial.print("Error: ");
            Serial.println(incomingString);
            incomingString = "";
         }
       }
   }
}


void execCommand() 
{
   incomingString.trim();
   command = incomingString;
   if (incomingString.indexOf(" ")>0) 
   {
      command = incomingString.substring(0,
      incomingString.indexOf(" "));
      command.trim();
      parameters = incomingString.substring(pos);
      parameters.trim();
   }
   command.toLowerCase();
   if ((command == "version") || (command == "ver"))
   {
      Serial.println(FIRMWARE_VERSION);
   }
   else 
      if ((command == "board"))
      {
         Serial.println(BOARD);
      }
      else if ((command == "help"))
      {
         PrintHelp();
      }
      else if (command == "config")
      {
         configPort();
      }
      else if (command == "write" or command == "set")
      {
         writePort();
      }
      else if (command == "read" or command == "get")
      {
         readPort();
      }
      else if (command == "lcd")
      {
         #if defined(LCD_ENABLED)
            lcdExecCommand();
         #endif
      }
      else
      {
         Serial.println("command unknown");
      }
};

void PrintHelp()
{
   Serial.println( "--------------------------------------------------------");
   Serial.println("");
   Serial.println("Commands (case not sensitive)");
   Serial.println("");
   Serial.println("ver|version");
   Serial.println("board");
   Serial.println("config port 0..53 type unused|IN|OUT|PWM|LCD|I2C|SPI|SERIAL");
   Serial.println("set|write port <n> value 0|low|1|high");
   Serial.println("get|read port <n>");
   Serial.println("lcd on|enable|off|disable");
   Serial.println("lcd clear");
   Serial.println("lcd clear row 1|2");
   Serial.println("lcd print row 1|2 <string>");
   Serial.println("lcd print seconds on|off");
   Serial.println("request_response on|off");
   Serial.println("");
   Serial.println( "------------------------------------------------");

}

void configPort() 
{
   // CONFIG PORT n TYPE out
   parameters = parameters.substring(parameters.indexOf("port") + 5);
   parameters.trim();
   pos = parameters.indexOf(" ");
   String port_number = parameters.substring(0, pos);
   port_number.trim();
   String port_type = parameters.substring(parameters.indexOf("type")+4);
   port_type.trim();
   port_type.toLowerCase();
   int int_port_number = -1;

   if(port_number.length()>0)
   {
      int_port_number = port_number[0] - '0';
   }
   if(port_number.length()>1)
   {
      int_port_number = int_port_number * 10 +    port_number[1] - '0';
   }

   if (int_port_number>=0 and (BOARD=="Mega" or (BOARD=="Uno" and int_port_number< 14)) )
   {
      if (port_type=="unused")
      {
         portType[int_port_number] = 0;
      }
      else if (port_type=="in" or port_type=="input")
      {
         portType[int_port_number] = 1;
         pinMode(int_port_number, INPUT);
      }
      else if (port_type=="out" or port_type=="output")
      {
         portType[int_port_number] = 2;
         pinMode(int_port_number, OUTPUT);
      }
      else if (port_type=="pwm")
      {
         portType[int_port_number] = 3;
         pinMode(int_port_number, OUTPUT);
      }
      else if (port_type=="i2c")
      {
         portType[int_port_number] = 5;
      }
      else if (port_type=="spi")
      {
         portType[int_port_number] = 6;
      }
      else if (port_type=="serial")
      {
         portType[int_port_number] = 7;
      }
      else
      {
         incomingString = "not "+incomingString;
      }

   } else
   {
      incomingString = " not "+incomingString;
   }

/* Mega
54 port digital, from 9 to 53
16 port AD, from 0 to 13

portType value

0 unused
1 IN
2 OUT
3 PWM
4 LCD
5 I2C
6 SPI
7 SERIAL

*/

   if (request_response)
   {
      Serial.println(end_response+ incomingString);
   }
}

void lcdExecCommand() 
{
#if defined(LCD_ENABLED)

   if (parameters.indexOf("clear")>0 or parameters.indexOf("CLEAR")>0 )
   {
      lcd_print_sec = false;
      if (parameters.indexOf("row")>0 or parameters.indexOf("ROW")>0 )
      {
         if (parameters.indexOf("1")>0 )
         {
            lcd.setCursor(0,0);
            lcd.print(" ");
         }
         if (parameters.indexOf("2")>0 )
         {
            lcd.setCursor(0,1);
            lcd.print(" ");
         }
      } 
      else
      {
         lcd.setCursor(0,0);
         lcd.print(" ");
         lcd.setCursor(0,1);
         lcd.print(" ");
      }

      if (request_response)
      {
         Serial.println(end_response+ incomingString);
      }

      } else if (parameters.indexOf("print")>0 and (parameters.indexOf("seconds")>0 or parameters.indexOf("second")>0 or parameters.indexOf("SECOND")>0 or parameters.indexOf("SECONDS")>0 ))
      {
         if (parameters.indexOf("off")>0 or parameters.indexOf("OFF")>0 )
            lcd_print_sec = false;
         else
            lcd_print_sec = true;

         if (request_response)
         {
             Serial.println(end_response+ incomingString);
         }
      } else if (parameters.indexOf("print")>0 and ( parameters.indexOf("row 1")>0) )
      {
         lcd.setCursor(0,0);
         lcd.print(parameters.substring( parameters.indexOf("row") + 6 ) ); 
         if (request_response)
         {
            Serial.println(end_response+ incomingString);
         }
      } else if (parameters.indexOf("print")>0 and (parameters.indexOf("row 1")>0) )
      {
         lcd.setCursor(0,0);
         lcd.print(parameters.substring( parameters.indexOf("row") + 7 ) ); 
         if (request_response)
         {
            Serial.println(end_response+ incomingString);
         }
      } else if (parameters.indexOf("print")>0 and (parameters.indexOf("row 2")>0) )
      {
         lcd.setCursor(0,1);
         lcd.print(parameters.substring( parameters.indexOf("row") + 6 ) ); 
         if (request_response)
         {
            Serial.println(end_response+ incomingString);
         }
     } else if (parameters.indexOf("print")>0 and (parameters.indexOf("row 2")>0) )
     {
        lcd.setCursor(0,1);
        lcd.print(parameters.substring( parameters.indexOf("row") + 7 ) ); 
        if (request_response)
        {
            Serial.println(end_response+ incomingString);
        }
        } else
        {
            Serial.println("lcd on");
        }
#endif
}


void writePort()
{
   // WRITE PORT n VALUE out

   parameters = parameters.substring( parameters.indexOf("port") + 5);
   parameters.trim();

   pos = parameters.indexOf(" ");
   String port_number = parameters.substring(0, pos); 
   port_number.trim();

   String port_value = parameters.substring( parameters.indexOf("value")+5);
   port_value.trim(); 
   port_value.toLowerCase();
   int int_port_number = -1;
   if(port_number.length()>0)
   {
      int_port_number = port_number[0] - '0';
   }
   if(port_number.length()>1)
   {
      int_port_number = int_port_number * 10 +    port_number[1] - '0';
   }

   if (int_port_number>=0 and (BOARD=="Mega" or (BOARD=="Uno" and int_port_number< 14) ) and portType[int_port_number]== 2 )
   {
      if (port_value=="1" or port_value=="true" or port_value=="high")
      {
         digitalWrite(int_port_number, HIGH);
      }
      else if (port_value=="0" or port_value=="false" or port_value=="low")
      {
         digitalWrite(int_port_number, LOW);
      }
      else
      {
         incomingString = " not "+incomingString;
      }
   } else
   {
      incomingString = " not "+incomingString;
   }
   if (request_response)
   {
      Serial.println(end_response+ incomingString);
   }
}

void readPort()
{

   // WRITE PORT n VALUE out

   parameters = parameters.substring(parameters.indexOf("port") + 5);
   parameters.trim();
   pos = parameters.indexOf(" ");
   String port_number = parameters.substring(0, pos);
   port_number.trim();
   int int_port_number = -1;
   if(port_number.length()>0)
   {
      int_port_number = port_number[0] - '0'; 
   }
   if(port_number.length()>1)
   {
      int_port_number = int_port_number * 10 + port_number[1] - '0';
   }

  if (int_port_number>=0 and (BOARD=="Mega" or (BOARD=="Uno" and int_port_number< 14) ) and portType[int_port_number]== 1 )
  {
     Serial.println(digitalRead( int_port_number));
  }
  else
  {
     incomingString = " not "+incomingString;
  }
  if (request_response)
  {
     Serial.println(end_response+incomingString);
  }
}

void getPort()
{
   pos = parameters.indexOf(" ");
   while ( pos > 0 ) 
   {
      parameter = parameters.substring(0, pos);
      parameter.trim();
      parameters = parameters.substring(pos);
      parameters.trim();
      if (parameter.length() == 1 ) 
      {
         parameter.setCharAt(1, tempChar);
         tempChar = tempChar - 48;
         if ((tempChar >= 0) && (tempChar <= 7))
         {
            port = tempChar + 22 ;
            // digitalRead(port);
         }
      }
      else 
      {  
         // Errore:
      };
   };
}

 

Mezzi di trasporto elettrici

Revisione 0.04

Il 2018 è un anno di svolta perchè, dopo aver visto l’affermazione nel mercato delle biciclette elettriche a pedalata assistita, in questo autunno assistiamo al lancio delle moto elettriche. Si comincia dai 10 cavalli circa, ovvero equivalente a quella particolare classe di motociclette denominata 125.

Risultati immagini per imagine bici bosch elettrica

Nel giro dei prossimi anni verranno introdotte, in termini competitivi, le motociclette di classe superiore.

Risultati immagini per immagini moto elettriche

Poi, verso il 2022, ci sarà la svolta per le utilitarie, quali Smart, Panda e 500. E’ noto che nazioni evolute, quali la Cina, abbiano quasi imposto l’adozione per città intere di mezzi elettrici, ed aziende automobilistiche importanti, quali FCA, abbiamo presentato i nuovi piani industriali basati sulla quasi totale a breve, si parla per la FCA del 2022, produzione di utilitarie elettriche.

Risultati immagini per immagine smart elettrica

 

La trazione elettrica è una vera rivoluzione, ora possibile.

I motivi sono moltissimi, ma uno per tutti è poter dire che i costi di manutenzione sono abbattuti.

Infatti la trazione elettrica elimina:

  • il circuito di refrigerazione motore con acqua e relativi radiatori
  • il circuito olio motore
  • il cambio
  • la frizione
  • riduce la trasmissione all’osso
  • non ci sono candele e candelette
  • le parti rotanti molto delicate si semplificano all’estremo eliminando cilindri, fascie, pistoni, bielle, distribuzione e relative cinghie
  • si eliminano tubi di scarico con complicazioni estreme quali sonde lambda e parti catalittiche da sempre in discussione
  • si eliminano i serbatoi carburante, con pompe e tubi che si seccano
  • non serve il motore elettrico di avviamento
  • non serve l’alternatore
  • l’elettronica ed in particolare i firmware si semplificano all’estremo; scompaiono le vecchie e complicate centraline elettroniche per introdurre invece dispositivi I.o.T.
  • si semplifica in modo enorme per l’utente la distribuzione dell’energia, ma creando il vero nuovo problema legato alla struttura nazionale antiquata della distribuzione elettrica
  • l’impianto frenante idraulico con tubi e pompe può essere semplificato dall’impianto elettromeccanico
    • che non può essere alimentato a 12 V, ma con 60V e più disponibili è possibile costruirlo
    • e non si dimenti che gran parte della forza frenante può essere esecitata dallo stesso motore elettrico con la benefica conseguenza di generare corrente che può ricaricare la batteria
  • con riferimento alle automobili, si elimina il fenomeno, particolarmente italiano fortemente sviluppato per raggirare l’enorme tassazione sui carburanti, dell’aggiungere al motore impianti a gas che, per quanto evoluti e quindi complicati, introducono inevitabilmente problematica dovute alla secchezza nella parti meccanice rotanti da combustione gassosa

Il tutto si semplifica in un motore elettrico ed una batteria innovativa.

La seconda vera criticità, dopo la struttura nazionale per la distribuzione dell’energia elettrica, si sposta sulle batterie che devono ancora evolvere. Una grande speranza è costituita dai dispositivi di conversione locale dall’idrogeno all’energia elettrica. Scenario che perè sposta un enorme problema ad un’altro: la produzione ed il trasporto dell’idrogeno.

Anche la guida migliora nettamente, niente cambio o frizione, e la trasmissione continua produce un piacere migliore. La coppia erogata dal propulsore elettrico rende il mezzo sempre brillante, mezzo che da fermo non consuma. Tutta l’energia elettrica finisce nella trazione senza le enormi dispersioni termiche dei motori ormai antiquati: il rispetto per l’ambiente diverge.

Ricordiamo anche l’abbattimento anche della seconda forma di enorme dispersione energetica: l’inquinamento acustico. Boati e fragori, oltre che fuochi e fiamme, vengono sostituiti dal leggero sfregolio, quasi una brezza, del propulsore elettrico.

Purtroppo allo stato attuale la vera criticità è nella distribuzione dell’energia elettrica, che risente della concezione tutta italiana di monopoli ciechi ed inscalfibili, da investitura divina, come nei vecchi regimi dinastici, e personale ingaggiato certamente non per meriti ed inamovibile. Infatti la batteria, per un motore elettrico per motocicletta, equivalente a 125cc, da 10KW, per essere utilizzata un’ora richiede una carica che , semplificando, assorbe l’intera erogazione di un usuale contatore, da utenza domestica di circa 3.5KW, per circa tre ore. Un colpo mortale per l’attuale distribuzione elettrica. E si parla solo di piccole motociclette.

I motori termici non sono praticamente usabili in robotica ed in contesti di precisione, mentre gli elettrici possono essere così finemente precisi da poterne coordinare 4 o 6 od 8 e permette persino il volo di un mezzo.

Se si assume come valido il principio, per applicazioni robotiche,  della necessità di associare ad ogni ruota un motore, allora il mezzo che ne esce ha poternzialità di controllo e precisione incredibili, se lo sono i motori.

Quindi i motori elettrici possono essere estremamante precisi. Se tralasciamo le motociclette e consideriamo mezzi con un maggior numero di ruote , per esempio quattro, ognuna dotata di motore, otteniamo un mezzo incredibile.

Infatti tale veicolo è a quattro ruote motrici ed indipendenti. Non necessita di scatole di distribuziuone, differenziali, alberi, mozzi e semiassi che rendono la parte meccanica così complessa da creare i problemi di fragilità e di continua rimessa a punto. Ma il controllo alla singola ruota supera di botto i vecchi sistemi ABS, ESP ed altre diavolerie rese completamente inutili e superate. Se poi si adottano computer di controllo con software che vediamo oggi nella versioni giocattolo per i quadricotteri e più, allora la rivoluzione è apocalittica.

Ma una centralina elettronica con un processore primitivo che deve coordianre dalla sonda lamba all’ABS alla distribuzione ed iniezione risulta una clava del paleolitico rispetto, per esempio ed improvvisando, ad  un piccolo cluster di schede ARM quad e più core ad oltre 2GHz con watch dog incrociato e connettività locale in fibra, che utilizzano un vero sistema operativo, per dire Linux in una versione real time su cluster con disaster recovery e storage magari su doppio RAID di SSD anche per log. Senza tener conto della parte I.o.T. con servizi remoti in data farm quali cartografici, monitoraggio e sicurezza. La rivoluzione è epocale come l’introduzione della polvere da sparo, la pressa tipografica, il motore termico, la valvola, la penicellina, il transistor e i computer.

Ma perchè tali vantaggi non vengono introdotti con grande velocità? La risposta è l’usuale e quasi ovvia osservazione: gli interessi dominanti richiedono tempi lunghi per poptrer impadronirsi del nuovo e poter continuare classici schemi predatori.

Commenti I.o.T. Arduino Firmware 0.18.06.05

Revisione 0.03.

Il primo I.o.T. Firmware per Arduino pubblicato, indicato come versione 0.18.06.05, permette di valutare concretamente il Progetto I.o.T.

E’ facile allestire l’ I.o.T. Controller con una qualsiasi scheda della famiglia  Arduino mediante questa prima versione pubblicata del Firmware. Compilato e installato nel microcontroller, è possibile usare il terminale seriale per comunicare manualmente, laboratorio fondamentale per entrare nel progetto.

Image result for arduino images

Si osservi come i comandi, stringhe con a capo, siano intellegibili per l’operatore umano, .

Questa prima versione riconosce il tipo di scheda, per esempio Uno o Mega,  e tiene conto del numero di porte disponibili.

E’ prevista la configurazione dinamica delle porte nei limiti strutturali del tipo di scheda riconosciuto.
Infatti il codice controlla dinamicamente la coerenza dei comandi inviati con l’architettura disponibile. Per esempio se viene riconosciuta una Scheda Uno e si invia il comando set port 54 value high il firmware rende errore perché la scheda Uno non ha 54 pin digitali come la Scheda Mega. Nel caso di Scheda Mega  se una porta è non è stata configurata oppure è stata configurata in lettura allora dovrà rendere errore alla medesima istruzione.

Si osservi il ruolo del comando CONFIG che permette la configurazione delle porte stesse del microcontroller, per esempio come porta digitale in uscita oppure in entrata o PWM.

Si adotta il principio di distinzione di comandi a basso livello, o comandi elementari o comandi,  direttamente inviati al ed eseguiti dal controller,  e di comandi ad alto livello, o macro comandi o macro ai quali il servizio controller_communicate, in esecuzione nel processore,  applica il parsing in comandi a basso livello che invia al controller.
Pertanto si ottiene una distribuzione delle computazioni e degli stati tra programmi eseguiti nel processore e comandi eseguiti nel controller, ben meno dotato del processore.

Le librerie e particolari righe di codice possono essere escluse dal compilatore per permette di non appesantire il compilato, e quindi poter essere eseguito in microcontroller meno dotati.

La Comunicazione con il Processore è mediante la porta USB che viene dedicata a questa attività. La velocità adottata è di 115200 baud che nelle molti test eseguito non ha mai dato problemi.

Il poll centrale contiene un primo ritardo che sarà perfezionato con demoltiplicatori, ovvero permetteranno l’esecuzione di codice ogni n  cicli del poll principale.

La Comunicazione dal Processore al Controller è di ovvia realizzazione, il verso opposto, ovvero gestione eventi,  richiede delle scelte che, in questa fase, sono realizzate mediante l’opzione repeat del comando inviato.
La gestione degli eventi sarà permessa dal parametro repeat legato al comando stesso, ovvero un comando con repeat nullo verrà eseguito una sola volta, realizzando quando si intende per eseguire il comando,  altrimenti verrà continuamente eseguito ma con una frequenza demoltiplicata rispetto ai cicli eseguiti del poll principale. L’effetto è di mettere il comando in poll, ovvero riporto eventi dal controller al processore.

 

Seguirà la pubblicazione dell’immagine SD per realizzare un I.o.T. Processore con scheda ARM del tipo Raspberry Pi 3 Model B.

Image result for raspberrypi images

 

I.o.T. Arduino Firmware 0.18.06.05

#define FIRMWARE_VERSION "0.18.06.05"

/*Language: Wiring/Arduino Serial Console 115200 baud \n ASCII 10 */ 

#define WATCH_DOG_ENABLED
#define LCD_ENABLED // pin 4,5,6,7,8,9 reserved
#define MACRO_01 // per utilizzi specifici

/* 001
   Si osservi l'utilizzo del C preprocessor,
   macro processor, per compilare il minor codice
   possibile al fine di poter utilizzare
   microcontroller con modeste risorse.
   Il generatore codice sorgente firmware
   provvederà a includere le opportune
   righe di definizione variabili 
   per il prepocessor
*/

// #include <Wire.h>

#if defined(WATCH_DOG_ENABLED)
#include <avr/wdt.h>
#endif
/* 002
   Importante predisposione dei microcontroller:
   watch dog al livello hardware
   che firmware successivi andranno a
   implementare in modo migliore.
   Dovranno tener conto anche del tipo di scheda
   che esegue il firmware, infatti Uno e Mega
   hanno gestione diverse del watch dog 
   a livello hardware
*/
#if defined(LCD_ENABLED)
#include <LiquidCrystal.h>
#endif
/* 003
   La connessione LCD al controller
   adottata lo standard DF-Robots
*/

#if defined(TEENSYDUINO)
/* 004
   Riconoscimento della scheda 
   che esegue il Firmware
*/
// --------------- Teensy -----------------
#if defined(__AVR_ATmega32U4__)
#define BOARD "Teensy 2.0"
#elif defined(__AVR_AT90USB1286__)
#define BOARD "Teensy++ 2.0"
#elif defined(__MK20DX128__)
#define BOARD "Teensy 3.0"
#elif defined(__MK20DX256__)
#define BOARD "Teensy 3.2" // and Teensy 3.1 (obsolete)
#elif defined(__MKL26Z64__)
#define BOARD "Teensy LC"
#elif defined(__MK64FX512__)
#define BOARD "Teensy 3.5"
#elif defined(__MK66FX1M0__)
#define BOARD "Teensy 3.6"
#else
#error "Unknown board"
#endif

#else // --------------- Arduino ------------------
#if defined(ARDUINO_AVR_ADK)
#define BOARD "Mega Adk"
#elif defined(ARDUINO_AVR_BT) // Bluetooth
#define BOARD "Bt"
#elif defined(ARDUINO_AVR_DUEMILANOVE)
#define BOARD "Duemilanove"
#elif defined(ARDUINO_AVR_ESPLORA)
#define BOARD "Esplora"
#elif defined(ARDUINO_AVR_ETHERNET)
#define BOARD "Ethernet"
#elif defined(ARDUINO_AVR_FIO)
#define BOARD "Fio"
#elif defined(ARDUINO_AVR_GEMMA)
#define BOARD "Gemma"
#elif defined(ARDUINO_AVR_LEONARDO)
#define BOARD "Leonardo"
#elif defined(ARDUINO_AVR_LILYPAD)
#define BOARD "Lilypad"
#elif defined(ARDUINO_AVR_LILYPAD_USB)
#define BOARD "Lilypad Usb"
#elif defined(ARDUINO_AVR_MEGA)
#define BOARD "Mega"
#elif defined(ARDUINO_AVR_MEGA2560)
#define BOARD "Mega 2560"
#elif defined(ARDUINO_AVR_MICRO)
#define BOARD "Micro"
#elif defined(ARDUINO_AVR_MINI)
#define BOARD "Mini"
#elif defined(ARDUINO_AVR_NANO)
#define BOARD "Nano"
#elif defined(ARDUINO_AVR_NG)
#define BOARD "NG"
#elif defined(ARDUINO_AVR_PRO)
#define BOARD "Pro"
#elif defined(ARDUINO_AVR_ROBOT_CONTROL)
#define BOARD "Robot Ctrl"
#elif defined(ARDUINO_AVR_ROBOT_MOTOR)
#define BOARD "Robot Motor"
#elif defined(ARDUINO_AVR_UNO)
#define BOARD "Uno"
#elif defined(ARDUINO_AVR_YUN)
#define BOARD "Yun"
// These boards must be installed separately:
#elif defined(ARDUINO_SAM_DUE)
#define BOARD "Due"
#elif defined(ARDUINO_SAMD_ZERO)
#define BOARD "Zero"
#elif defined(ARDUINO_ARC32_TOOLS)
#define BOARD "101"
#else
#define BOARD "Unknown board"
#endif
#endif

boolean lcd_print_sec = true;

#if defined(LCD_ENABLED)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// lcd_print_sec   = true;
#endif
/* 005
   Se il controller utilizza il LCD
   allora i PIN 4,5,6,7,8,9 
   sono ad esso riservati
   Il caso LCD RGB, da sviluppare 
   utilizzerà altri 3 PIN come PWM
*/

boolean request_response = true;
String end_response = "Done ";
/* 006
   Il protocollo sviluppato utilizza 
   lo schema naturale request / response
   con stringhe di testo e terminate da capo riga
   Il Firmware prevede di poter terminare 
   la risposta del controller con una riga
   che inizia con Done ...
*/

// const int TIMEOUT_CICLE = 200;
int CYCLE_DELAY   = 20;
/* 007
   CYCLE_DELAY è il ritardo nel ciclo principale
   che realizza il poll mediante porta USB
   verrà gestito il comando che
   permetterà di variare il contenuto
*/

byte portType[54];
/* 008
   Matrice fondamentale che contiene la
   configurazione dei PIN del microcontroller
   che è assegnata dal comando CONFIG
*/

char incomingChar = '\0';
String incomingString = "";
String command    = "";
String parameters = "";
String parameter  = "";
String tempString = "";
String tempString1= "";
String tempString2= "";
int port = 0;
String portvalue  = "";
String portname   = "";
int pos  = 0;
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int tempInt     = 0;
char tempChar   = '\0';
int inPortMap[7];

int loop_100    = 0;
int loop_10000  = 0;
/* 009
   variabili che realizzano due cicli
   demoltiplicati rispetto al ciclo principale
   ovvero loop_100 diventa vera ogni cento 
   cicli principali   
*/


void setup() 
{

#if defined(WATCH_DOG_ENABLED)
   wdt_enable(WDTO_8S);
#endif

   Serial.begin(115200);
   delay(50);
#if defined(LCD_ENABLED)
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("IoT ");
lcd.print(FIRMWARE_VERSION);
#endif

   for (int i = 0; i <= 53; i++)
   {
      portType[i] = 0; 
   }

/* 010
   La matrice portType contine la configurazione
   dei PIN del microcontroller

   Le Schede Mega hanno
      54 port digital, from 9 to 53
      16 port AD, from 0 to 13
   
   I valori in portType significano:

      0   not defined
      1   IN
      2   OUT
      3   PWM
      4   LCD
      5   I2C
      6   SPI
      7   SERIAL
*/

#if defined(LCD_ENABLED)
// 8, 9, 4, 5, 6, 7
portType[4] = 4;
portType[5] = 4;
portType[6] = 4;
portType[7] = 4;
portType[8] = 4;
portType[9] = 4;
#endif

   // Wire.begin();

}



void loop() 
{
  loop_100 = loop_100 + 1;
  if (loop_100 = 100)
  {
    loop_100 = 0;
    loop_10000 = loop_10000 +1;
  }

  if (loop_10000 = 100)
  {
    loop_10000=0;
  }

  #if defined(WATCH_DOG_ENABLED)
     wdt_reset();
  #endif
  #if defined(LCD_ENABLED)
     if (lcd_print_sec)
     {
        lcd.setCursor(0,1);
        lcd.print(millis()/1000);
     }
  #endif

   if (Serial.available() > 0) 
   {
      incomingChar = Serial.read();
      if (incomingChar == '\n') 
      {
         execCommand();
         incomingString = "";
      }
      else 
      {
         incomingString += incomingChar;
         if (incomingString.length() > 254) 
         {
            Serial.print("Error: ");
            Serial.println(incomingString);
            incomingString = "";
         }
       }
   }
}


void execCommand() 
{
   incomingString.trim();
   command = incomingString;
   if (incomingString.indexOf(" ")>0) 
   {
      command = incomingString.substring(0,
      incomingString.indexOf(" "));
      command.trim();
      parameters = incomingString.substring(pos);
      parameters.trim();
   }
   command.toLowerCase();
   if ((command == "version") || (command == "ver"))
   {
      Serial.println(FIRMWARE_VERSION);
   }
   else 
      if ((command == "board"))
      {
         Serial.println(BOARD);
      }
      else if ((command == "help"))
      {
         PrintHelp();
      }
      else if (command == "config")
      {
         configPort();
      }
      else if (command == "write" or command == "set")
      {
         writePort();
      }
      else if (command == "read" or command == "get")
      {
         readPort();
      }
      else if (command == "lcd")
      {
         #if defined(LCD_ENABLED)
            lcdExecCommand();
         #endif
      }
      else
      {
         Serial.println("command unknown");
      }
};

void PrintHelp()
{
   Serial.println( "--------------------------------------------------------");
   Serial.println("");
   Serial.println("Commands (case not sensitive)");
   Serial.println("");
   Serial.println("ver|version");
   Serial.println("board");
   Serial.println("config port 0..53 type unused|IN|OUT|PWM|LCD|I2C|SPI|SERIAL");
   Serial.println("set|write port <n> value 0|low|1|high");
   Serial.println("get|read port <n>");
   Serial.println("lcd on|enable|off|disable");
   Serial.println("lcd clear");
   Serial.println("lcd clear row 1|2");
   Serial.println("lcd print row 1|2 <string>");
   Serial.println("lcd print seconds on|off");
   Serial.println("request_response on|off");
   Serial.println("");
   Serial.println( "------------------------------------------------");

}

void configPort() 
{
   // CONFIG PORT n TYPE out
   parameters = parameters.substring(parameters.indexOf("port") + 5);
   parameters.trim();
   pos = parameters.indexOf(" ");
   String port_number = parameters.substring(0, pos);
   port_number.trim();
   String port_type = parameters.substring(parameters.indexOf("type")+4);
   port_type.trim();
   port_type.toLowerCase();
   int int_port_number = -1;

   if(port_number.length()>0)
   {
      int_port_number = port_number[0] - '0';
   }
   if(port_number.length()>1)
   {
      int_port_number = int_port_number * 10 +    port_number[1] - '0';
   }

   if (int_port_number>=0 and (BOARD=="Mega" or (BOARD=="Uno" and int_port_number< 14)) )
   {
      if (port_type=="unused")
      {
         portType[int_port_number] = 0;
      }
      else if (port_type=="in" or port_type=="input")
      {
         portType[int_port_number] = 1;
         pinMode(int_port_number, INPUT);
      }
      else if (port_type=="out" or port_type=="output")
      {
         portType[int_port_number] = 2;
         pinMode(int_port_number, OUTPUT);
      }
      else if (port_type=="pwm")
      {
         portType[int_port_number] = 3;
         pinMode(int_port_number, OUTPUT);
      }
      else if (port_type=="i2c")
      {
         portType[int_port_number] = 5;
      }
      else if (port_type=="spi")
      {
         portType[int_port_number] = 6;
      }
      else if (port_type=="serial")
      {
         portType[int_port_number] = 7;
      }
      else
      {
         incomingString = "not "+incomingString;
      }

   } else
   {
      incomingString = " not "+incomingString;
   }

/* Mega
54 port digital, from 9 to 53
16 port AD, from 0 to 13

portType value

0 unused
1 IN
2 OUT
3 PWM
4 LCD
5 I2C
6 SPI
7 SERIAL

*/

   if (request_response)
   {
      Serial.println(end_response+ incomingString);
   }
}

void lcdExecCommand() 
{
#if defined(LCD_ENABLED)

   if (parameters.indexOf("clear")>0 or parameters.indexOf("CLEAR")>0 )
   {
      lcd_print_sec = false;
      if (parameters.indexOf("row")>0 or parameters.indexOf("ROW")>0 )
      {
         if (parameters.indexOf("1")>0 )
         {
            lcd.setCursor(0,0);
            lcd.print(" ");
         }
         if (parameters.indexOf("2")>0 )
         {
            lcd.setCursor(0,1);
            lcd.print(" ");
         }
      } 
      else
      {
         lcd.setCursor(0,0);
         lcd.print(" ");
         lcd.setCursor(0,1);
         lcd.print(" ");
      }

      if (request_response)
      {
         Serial.println(end_response+ incomingString);
      }

      } else if (parameters.indexOf("print")>0 and (parameters.indexOf("seconds")>0 or parameters.indexOf("second")>0 or parameters.indexOf("SECOND")>0 or parameters.indexOf("SECONDS")>0 ))
      {
         if (parameters.indexOf("off")>0 or parameters.indexOf("OFF")>0 )
            lcd_print_sec = false;
         else
            lcd_print_sec = true;

         if (request_response)
         {
             Serial.println(end_response+ incomingString);
         }
      } else if (parameters.indexOf("print")>0 and ( parameters.indexOf("row 1")>0) )
      {
         lcd.setCursor(0,0);
         lcd.print(parameters.substring( parameters.indexOf("row") + 6 ) ); 
         if (request_response)
         {
            Serial.println(end_response+ incomingString);
         }
      } else if (parameters.indexOf("print")>0 and (parameters.indexOf("row 1")>0) )
      {
         lcd.setCursor(0,0);
         lcd.print(parameters.substring( parameters.indexOf("row") + 7 ) ); 
         if (request_response)
         {
            Serial.println(end_response+ incomingString);
         }
      } else if (parameters.indexOf("print")>0 and (parameters.indexOf("row 2")>0) )
      {
         lcd.setCursor(0,1);
         lcd.print(parameters.substring( parameters.indexOf("row") + 6 ) ); 
         if (request_response)
         {
            Serial.println(end_response+ incomingString);
         }
     } else if (parameters.indexOf("print")>0 and (parameters.indexOf("row 2")>0) )
     {
        lcd.setCursor(0,1);
        lcd.print(parameters.substring( parameters.indexOf("row") + 7 ) ); 
        if (request_response)
        {
            Serial.println(end_response+ incomingString);
        }
        } else
        {
            Serial.println("lcd on");
        }
#endif
}


void writePort()
{
   // WRITE PORT n VALUE out

   parameters = parameters.substring( parameters.indexOf("port") + 5);
   parameters.trim();

   pos = parameters.indexOf(" ");
   String port_number = parameters.substring(0, pos); 
   port_number.trim();

   String port_value = parameters.substring( parameters.indexOf("value")+5);
   port_value.trim(); 
   port_value.toLowerCase();
   int int_port_number = -1;
   if(port_number.length()>0)
   {
      int_port_number = port_number[0] - '0';
   }
   if(port_number.length()>1)
   {
      int_port_number = int_port_number * 10 +    port_number[1] - '0';
   }

   if (int_port_number>=0 and (BOARD=="Mega" or (BOARD=="Uno" and int_port_number< 14) ) and portType[int_port_number]== 2 )
   {
      if (port_value=="1" or port_value=="true" or port_value=="high")
      {
         digitalWrite(int_port_number, HIGH);
      }
      else if (port_value=="0" or port_value=="false" or port_value=="low")
      {
         digitalWrite(int_port_number, LOW);
      }
      else
      {
         incomingString = " not "+incomingString;
      }
   } else
   {
      incomingString = " not "+incomingString;
   }
   if (request_response)
   {
      Serial.println(end_response+ incomingString);
   }
}

void readPort()
{

   // WRITE PORT n VALUE out

   parameters = parameters.substring(parameters.indexOf("port") + 5);
   parameters.trim();
   pos = parameters.indexOf(" ");
   String port_number = parameters.substring(0, pos);
   port_number.trim();
   int int_port_number = -1;
   if(port_number.length()>0)
   {
      int_port_number = port_number[0] - '0'; 
   }
   if(port_number.length()>1)
   {
      int_port_number = int_port_number * 10 + port_number[1] - '0';
   }

  if (int_port_number>=0 and (BOARD=="Mega" or (BOARD=="Uno" and int_port_number< 14) ) and portType[int_port_number]== 1 )
  {
     Serial.println(digitalRead( int_port_number));
  }
  else
  {
     incomingString = " not "+incomingString;
  }
  if (request_response)
  {
     Serial.println(end_response+incomingString);
  }
}

void getPort()
{
   pos = parameters.indexOf(" ");
   while ( pos > 0 ) 
   {
      parameter = parameters.substring(0, pos);
      parameter.trim();
      parameters = parameters.substring(pos);
      parameters.trim();
      if (parameter.length() == 1 ) 
      {
         parameter.setCharAt(1, tempChar);
         tempChar = tempChar - 48;
         if ((tempChar >= 0) && (tempChar <= 7))
         {
            port = tempChar + 22 ;
            // digitalRead(port);
         }
      }
      else 
      {  
         // Errore:
      };
   };
}

 

I.o.T. Processor Board

Revisione 0.03.

I Processori in ambito I.o.T. sono computer che gestiscono i Controller dotati di GPIO. Sono il tramite per i Controller, computer con poche risorse, ma in grado di gestire direttamente l’elettronica necessaria per utilizzare sensori ed attuatori, verso i Sistemi Remoti I.o.T., raggiungibili attraverso Internet.

I Processori che utilizziamo nel Progetto Sistema I.o.T. sono in breve di due tipi:

  • schede ARM,  32 e 64 bit, con Raspbian o Armbian,
  • Computer con schede   i386 e AMD64 con Ubuntu 18.04 Server, che comprendono laptop, computer desktop e Server

Le schede ARM con Raspbian sono della famiglia Raspeberry PI.

Raspberry Pi 3 Model B+

Le schede con Armbian, in sintesi, sono dotate di chips:

  • Allwinner A10, A20, A31, H2+, H3, H5, A64
  • Amlogic S805 and S905 (Odroid boards), S802/S812, S805, S905, S905X and S912 (fork by @balbes150)
  • Actionsemi S500
  • Freescale / NXP iMx6
  • Marvell Armada A380
  • Rockchip RK3288
  • Samsung Exynos 5422

ed alcune schede sono:

Beelink X2, Orange Pi PC plus, Orange Pi Plus 2E, Orange Pi Lite, Roseapple Pi, NanoPi M1, NanoPi M1+, NanoPi Neo, NanoPi Neo2, NanoPi Duo, Le Potato, Espressobin, Pine64, soPine64, Pinebook A64, pcDuino2, pcDuino3, Odroid C0/C1/C1+, Banana Pi M2+, Hummingboard 2, Odroid C2, Orange Pi 2, Orange Pi One, Orange Pi PC, Orange Pi PC2, Orange Pi Prime, Orange Pi Win, Orange Pi Plus 1 & 2, Clearfog, Lemaker Guitar, Odroid XU4, Odroid HC1, Udoo Neo, Banana Pi M2, Orange Pi A31S, Cubieboard 1, Cubieboard 2, Hummingboard, Lamobo R1, Banana Pi PRO, Orange Pi mini A20, Olimex Lime A10, Olimex Micro, Olimex Lime 2, pcDuino3 nano, Banana Pi Plus A20, Udoo quad, Orange Pi A20, Olimex Lime 1, Banana Pi, Cubox-i, Cubietruck, Tinker Board, Miqi, Rock64

 

Il Sistema I.o.T. che progettiamo prevede la connessione USB tra Processore e Controller.

Il protocollo USB per la sue caratteristiche uniche diventa il canale preferenziale per la comunicazione Processore – Controller:

  • è Plug & Play
  • porta l’alimentazione a 5V
  • permette di utilizzare cavi usuali fino a 5m
  • ha una velocità ottimale rispetto ad altri protocolli seriali
  • l’industria ha perfezionato e continua a perfezionare l’USB con innovazione sempre strabilianti
  • l’enorme utilizzo in vari ambiti, in particolare in ambito mobile, hanno reso lo standard USB solido, affidabile e ben supportato
  • le piccole schede  microcontroller in genere non sono munite di schede di rete e mal gestiscono il protocollo TCP-IP, ma hanno porte USB

Per appartenere a Internet delle Cose il sistema deve poter comunicare in internet. Il Processore si fa carico di questo aspetto mentre il Controller mal gestirebbe la connessione TCP-IP.

Ma servono servizi e tabelle locali oltre che servizi e basi dati remote e raggiungibili mediante internet. Il Controller con il Sistema Operativo Linux, completo in tutte le funzionalità, permette non solo di utilizzare servizi client, quali Socket Row, Telnet, HTTP, SSH, SMTP, NTP, RDBMS, …, ma anche permette di utilizzare dei Servizi Server in locale. Ed includeremo il servizio email, database, web ed altri se necessari.

I Controller gestiscono molti dati, in particolare moltissimi in certi casi, per esempio al caso particolare di misure di potenza reale. Le basi dati locali devono permettere l’accesso concorrenti a più servizi, ma allo stesso tempo devono essere affidabili. Infatti i Sistemi Remoti I.o.T. essendo raggiungibili mediante Internet possono avere degli intervalli, anche lunghi, senza connessione Internet. Quindi la base dati locale svolge la funzione essenziale di buffer in assenza di connettività.

 

Sistema I.o.T.: Processore, Controller, Sensori ed Attuatori

Revisione 0.07.

Presentiamo il progetto di Sistema I.o.T. che, nella sua struttura più essenziale, è costituito da:

  • Sistema Servizi Centrale I.o.T.
  • Processore
  • Controller
  • Shield, Sensori ed Attuatori
  • App Desktop per amministrare il sistema mediante un computer generico

IL Sistema Servizi Centrale I.o.T. è raggiungibile mediante internet ed eroga servizi quali cruscotti da utilizzare anche in ambito mobile, notifiche, rapporti ed altro.

Un Sistema Periferico I.o.T., costituito da processori, controller, sensori ed attuatori, comunque può funzionare in modo autonomo.

I Controller o microcontroller, quali AVR, sono dotati di:

  • interfaccia IO o GPIO
  • canale di comunicazione USB con il Processore
  • altri canali di comuncazione: seriali (TTL, RS232, RS422, RS485), I2C, SPI, IR, …
  • firmware che gestisce la comunicazione con il Processore

Il Processore è sostanzialmente un computer, il progetto prevede processori  ARM 32 o 64, i386 o AMD64, con:

  • Server RDBMS PostgreSQL con i database necessari
  • Servizi C++/Qt
    • il riconoscimento automatico dei controller collegati in modalità P&P con aggiornamento nella tabella iot_db.controllers del database usato
    • esecuzione dei comandi inseriti nella tabella iot_db.commands verso il controller e riporto della risposta al comando stesso
    • sincronizzazione con il Sistema Centrale I.o.T. attraverso Internet
  • servizio Apache con WEB UI per interagire con la base dati del sistema
  • ambiente di compilazione ed upload firmware di base per la famiglia di microcontroller Arduino
  • Servizi di monitoraggio in Python
    • temperature, syslog, connettività, risorse disponibili, stato SD, watch dog controller ed altro
  • la App Desktop MS WIn32 per amministrazione del sistema mediante un computer desktop con SO Microsoft e quindi di facile reperibilità, previo installazione run time MS Visual Studio e ODBC PostgreSQL

Nella prima fase utilizziamo, quali Processori, schede ARM 32 e 64   con Raspbian o Armbian, schede   i386 e AMD64 con Ubuntu 18.04 Server.

Armbian e Raspbian sono Sistemi Operativi UNIX Linux di derivazione Debian.

Il prototipo iniziale è costituito dall’immagine della SD con Raspbian per RaspeberryPi 3, disponibile nelle prima versione a breve, che realizza un processore completo per gli utilizzi di base.

Contiene tutti i servizi e loa base dati con RDBMS PostgreSQL per realizzare il Sistema Base I.o.T. :

  • Linux SO
    • desktop grafico
    • networking
      • WiFi
      • rete locale
      • USB tethering
      • DHCP
      • NTP
    • Rsyslog
    • SSH console remota per amministrazione
  • base dati in RDBMS PostgreSQL
    • libreria PL Py3 u dedicata I.o.T.
    • amministrazione pgadmin3
  • base dati locale Sqlite 3
    • amministrazione sqlite-admin
  • Servizi I.o.T.
    • riconoscimento automatico controller attivati con USB P&P
    • per ogni controller servizio di routing comandi tra processore e controller attraverso il canale USB
    • sincronizzazione locale con remoto attraverso internet
    • buffer temporaneo dati e stati in assenza di connettività
    • monitoraggio parti struttura I.o.T.
  • servizi Python 3 monitoraggio
    • connettività
    • network
    • Syslog
    • dispositivi USB
  • servizi WEB con Apache

Il servizio di riconoscimento ed aggiornamento tabella controller connessi a porte USB è eseguito mediante Linux Cron alla frequenza del minuto.

Il riconoscimento di un nuovo controller determina:

  • l’aggiornamento della tabella controllers
  • l’avvio del servizio controller_bridge ad esso dedicato e che in breve interagisce con il controller stesso e la base dati del processor.
  • il riconoscimento del tipo di controller con il seriale univoco ed i parametri USB correlati
  • la definizione corretta, in relazione alla scheda riconosciuta, del numero di porte disponibili: IO, AD, DA, I2C, serial TTL, SPI, …

La prima famiglia di controller che consideriamo è costituita, ovviamente, dai popolari AVR ed ARM Arduino.

Il processore Rpi contiene una versione del firmware di base che può compilare ed eseguire l’upload in una scheda correttamente riconosciuta.

Il linguaggio realizzato, appartenente al linguaggio I.o.T.

Il principio comunque è che il servizio in esecuzione nel processore esegue macro comandi e fa eseguire comandi elementari al controller abbinato.

Per esempio se si vuole realizza un termostato con soglia una data temperatura t, il controller_bridge decompone la macro nei comandi:

  • legge, inviando il comando adeguato al controller, il valore presenta nella data porta AD
  • confronta con la soglia t e, nel caso,
    • scrive, inviando istruzione adeguata al controller, il valore 1 alla porta OUT convenuta.

Il firmware di base prevede il comando CONFIG che permette dinamicamente di configurare le porte del controller, per esempio in Digital IN o digital  OUT o I2C o SPI. Sia il firmware che il service_controller eseguono controlli per evitare alcuni semplici errori: non superare il massimo numero di porte disponibili in relazione alla scheda riconosciuta, non usare in modo improprio porte rispetto alla configurazione assegnata, per esempio in OUT una porta configurata come digital IN, ed altro.

La seconda famiglia di controller che andremo ad utilizzare sono le stesse schede ARM che abbiamo considerato come processori. Infatti sono dotate di GPIO. Il Sistema Operativo Linux Raspbian e Armbian prevedono i moduli kernel  per gestire le interfaccie sia nella forma passiva che con eventi sollevati dai moduli kernel.

Per realizzare il servizio che connette la GPIO al Sistema I.o.T. utilizziamo C/C++ wiringpi e Qt in ambito Armbian.

 

Gli Shield e i Sensori ed Attuatori che inizialmente consideriamo, per una questione di praticità, oltre ad elettronica su millefori, appartengono alle famiglie:

 

Per informazioni.

 

Beocreate 4 channel amplifier

The Beocreate 4 channel amplifier is a very flexible DSP/DAC/amplifier combination board designed for high-quality music playback in combination with passive loudspeakers.

  • Up to 180W output power (2x30W, 2x60W)
  • Capable of driving up to four of 4-8 Ohm speakers
  • Fully controllable from the Raspberry Pi

 

Beocreate software suite
This software allows you to activate a Beovox CX50/CX100 or any generic speaker and use them to connect play music via Airplay, Bluetooth or Spotify

Raspbian Lite with the DSP toolkit installed.
This allows you to use SigmaStudio on your PC to create you own DSP programs. Note that we recommend this only to users that are experienced with DSP tools and filter designs. While this gives you the greatest flexibility with this board,

 

IoT’s Effects on IT Infrastructure Spending

There’s little argument that the explosive growth of the Internet of Things (IoT) market is having a major impact on the IT industry. For most enterprises, some of that impact will be felt on their IT budgets, suggests a new study from 451 Research.

Nearly two-thirds (65.6 percent) of the 575 IT and IoT decision-makers polled by analyst firm said they expect to increase their IT spending in the next 12 months because of planned IoT deployments. A scant 2.7 percent expect to reduce their spending instead.

internet of things

automation – Internet of Things

IoT – Internet of Things Internet delle Cose

L’Internet delle cose indica la capacità dei nuovi  dispositivi,  le cose, di comunicare, anche tra loro, attraverso internet.
Questi dispositivi sono dotati di computer ed elettronica che permettono la comunicazione e l’interazione con la realtà circostante.
Esempi di computer utilizzabili a questi scopi sono le schede ARM ed AVR, quali RaspberryPI ed Arduino.

L’Automazione ricopre la Domotica, la Building Automation, l’Automazione Industriale ed altri settori.
Tra i produttori leader indichiamo Moxa e Crestron.
In ambito di Domotica segnaliamo il prodotto MyHome della francese Legrand Bticino.

 

 

Internet of Things, Video Driving Internet Traffic, Cisco Says

The amount of global IP traffic will almost triple over the next five years, hitting 3.3 zettabytes by 2021 as multiple factors continue to accelerate the worldwide digitization trend, according to Cisco Systems officials.

According to the latest version of Cisco’s annual Internet Visual Networking Index (VNI) forecast, the internet of things (IoT) will continue to be a driving force, while video will account for more than 80 percent of the traffic running over global IP networks.

internet traffic

Internet delle cose, appunti.

IoT presuppone che:

  • internet sia ben integrata nella realtà sulla quale si voglia costruire
  • i computer utilizzati siano atti a comunicare attraverso internet con servizi remoti ed, mediante opportuna elettronica, in locale con sensori, attuatori ed altri dispositivi  d’interazione con la realtà circostante
  • i servizi risiedano in server raggiungibili attraverso internet, siano predisposti ad essere utilizzati mediante app mobile, app desktop e app client nei computer che gestiscono l’interazione con la realtà locale
  • i dispositivi mobili abbiano app che permettano di colloquiare con i servizi predisposti alla realizzazione del particolare applicazione IoT
  • l’utenza professionale abbia app desktop per specifiche elaborazioni quali elaborazioni statistiche, ricalcoli ed estrapolazione dati a fini economici, monitoraggio sistemistico, backup e molto altro
  • i computer per l’interazione locale hanno app client con doppia comunicazione: in locale ed in remoto; questi computer riportano informazioni e comandi da remoto a locale e viceversa

Possiamo aggiungere  che:

  • i computer adatti ad IoT sono a basso consumo, compatti, costo modesto, stabili, alimentazione semplificata e con predisposizione all’interazione con l’elettronica attraverso bus seriale, USB, SPI, I2C o direttamente con collegamento I/O o PWM
  • i servizi remoti permettano di evitare l’utilizzo locale di server e servizi impegnativi sotto vari profili
  • i servizi remoti aprano ad una struttura del tipo cloud
  • i dispositivi mobile interagiscono usualmente con i servizi mediante schemi richiesta/risposta, tipicamente HTTPS
  • la connettività internet deve essere affidabile, stabile, e con banda minima garantita tra ogni nodo del grafo coinvolto

 

Controller con GPIO per automazione IoT

La costruzione di un sistema IoT, Internet of Things,  deve prevedere uno spazio cloud per i dati, anche big data, con un middleware verso un’ampia collezione di servizi. Allestiremo una versione per sviluppo e test in locale con Ubuntu server virtualizzato mediante Virtualbox.

Supponiamo di voler allestire dei sistemi periferici  per il monitoraggio e l’automazione.

Il più semplice sistema è costituito da un computer, che definiamo controller, collegato mediante apposito BUS all’elettronica che realizzi una GPIO, General Purpose Input Output.

Affinché il controller sia realizzato con una tecnologia moderna, bassissimo consumo, dimensioni minime, potente, costo ridotto, unica alimentazione, per esempio 5V DC 2A, con una distribuzione Linux ben collaudata, deve essere, per esempio, ARM.

Tra le schede ARM scegliamo un modello diffuso, robusto, economico, per esempio il Raspberry Pi, RPi, in particolare la non costosa quad core versione 2. Questa scheda permette di eseguire il sistema operativo Linux completo degli ambienti di sviluppo ed è dotata delle connettività di base.

Il RPi ha una sua GPIO, ma, per dire, non ha convertitori AD, il numero di pin IO è modesto, la CPU è collegata direttamente alla GPIO …, quindi  preferiamo dotarla di microcontroller dedicato ed esterno, per essere indipendenti dalla specifica tecnologia del controller, poter godere di due sistemi autonomi, anche nel mutuo controllo. Infatti, per dire, RPi manca di un sistema di spegnimento. Definiamo gpio0 quella a bordo del RPi e gpio1 la principale, che in questa situazione, è esterna.

La miglior scheda con GPIO per diffusione, documentazione, facilità di sviluppo e costo è del tipo Arduino,  con microcontroller AVR.

Abbiniamo nel modo più conveniente la RPi con una Arduino in un contenitore del tipo utilizzato negli impianti elettrici. Utilizziamo le righe di headers per alloggiare le due schede su una basetta costruita con PCB, Printed Circuit Board, su misura. Aggiungiamo sulla stessa PCB:

  • una ventola
  • un IC con 7 oppure 8 darlington
  • un LM35 per leggere la temperatura interna al contenitore
  • un relè per gestire l’accensione e lo spegnimento del RPi
  • un led per indicare lo stato
  • un led per indicare ed errori
  • un pulsante esterno per reset (opzionale e disattivabile mediante software)
  • un pulsante esterno per accensione/spegnimento RPi (opzionale e disattivabile mediante software)
  • un pulsante interno per reset to factory.

Consideriamo il sistema di alimentazione più adatto per dispostivi del più vario genere. La tensione sia unica per semplificare il trasporto. Teniamo conto di  standard correnti per esempio in ambito automotive, pannelli solari, batterie al piombo, alimentazione di prodotti generici. Quindi scegliamo 12 V DC con corrente almeno di 5 A, meglio verso 10A, in tecnologia switching-mode.

Inseriamo l’alimentatore in un contenitore simile a quello scelto per il controller, ma di dimensioni più contenute e con una ventola sempre attiva. Una morsettiera permetta di collegare lo stesso alla f.e.m. ed ai dispositivi da alimentare.

Pertanto dobbiamo aggiungere nel contenitore del controller con GPIO con convertitore 12 V DC a 5 V DC, che regga almeno 1,5A. Ne proveremo alcuni, e cominciamo con un modello della Recom R-78B5.0-1.5 pin compatibile serie LM78xx, ma switching con il 92% di efficienza.

Raspbian, il sistema operativo derivato da Debian per RPi, permette di utilizzare Python e Qt 4.8, che costruiscono l’ambiente per lo sviluppo.

Utilizziamo come cloud middleware un RDBMS, la miglior scelta è Postgresql 9.3 o 9.4 con PL/Pythonu per la collezione necessaria di trigger.

Attiviamo un firewall ed una VPN o tunnel, tipo SSH,  per proteggere la comunicazione. Naturalmente con sistemi di backup e ridondanza adeguati.

Il primo servizio residente nel controller, RPi nel nostro caso, è di controllo dei microcontroller collegati ed operativi, per poi  aggiornare la specifica tabella. Realizziamo il programma in Qt e lo attiviamo al minuto con Cron e privilegi di root per gestire il BUS in totale libertà.

Il servizio principale realizza nel suo ciclo principale un doppio poll verso il middleware e verso la gpio1.

Caratterizziamo mediante id, identificatore unico naturale, ogni servizio del sistema specifico, detto sid.

Ogni device ed host sarà caratterizzato da un device id, detto did.

La tabella commands nel middleware permetterà l’interazione tra le parti. All’inserimento di un record in commands scatta il trigger in PL/Python, che avvia l’interprete del comando e l’esecuzione dello stesso.

Il tracciato di commands prevede oltre a campi scontati quali id, timestamp, commands, parameters e status, anche il sid del mittente e del destinatario, il campo alive che viene aggiornato dal destinatario entro un tempo stabilito altrimenti il servizio giornaliero provvederà a eliminare la riga. Dei campi permettono la ripetizione per n volte ad un dato tempo del comando stesso.

I commnadi sono raggruppati secondo le varie tipologie.

Una opportuna collezione di tabelle permette di tenere lo stato dei dispositivi.

Gli eventi sono resi come comandi.

I comandi tra il middleware ed il controller sono più strutturati di quelli dal controller alla gpio.

Particolare riguardo è data alla costruzione del firmware del microcontroller. Sono previste due possibili funzionamenti: con o senza autoreset alla comunicazione della serial principale. La tensione per lo stato alto delle porte è per ora 5V, mentre gpio0 lavora a 3.3V. Il firmware prevede due modalità di funzionamento con o senza connessione attiva al controller. Nel caso di connessione attiva, il ciclo principale legge il buffer ed esegue il parsing dei comandi ricevuti, inviando infine la risposta. Nell’altro caso attiva le funzionalità di watch dog oppure di attesa per la riaccensione della scheda ARM. In questa seconda situazione la gpio1 è isolata, ma può memorizzare dei dati.