Sommario:

Andare oltre lo standard Firmata - Rivisitato: 5 passaggi
Andare oltre lo standard Firmata - Rivisitato: 5 passaggi

Video: Andare oltre lo standard Firmata - Rivisitato: 5 passaggi

Video: Andare oltre lo standard Firmata - Rivisitato: 5 passaggi
Video: Aumenta La Velocità Di Internet Con Un Solo Gesto 2024, Luglio
Anonim
Andare oltre lo standard Firmata - Revisited
Andare oltre lo standard Firmata - Revisited

Poco tempo fa, sono stato contattato dal Dr. Martyn Wheeler, un utente pymata4, per una guida nell'aggiunta del supporto per il sensore di umidità/temperatura DHT22 alla libreria pymata4. La libreria pymata4, insieme alla sua controparte Arduino, FirmataExpress, consente agli utenti di controllare e monitorare i propri dispositivi Arduino da remoto. Nel giro di pochi scambi di e-mail, il Dr. Wheeler è riuscito a modificare sia pymata4 che FirmataExpress. Di conseguenza, il supporto per i sensori DHT22 e DHT11 è ora una parte standard di pymata4 e FirmataExpress.

Nel maggio del 2014 ho scritto un articolo sull'aggiunta del supporto a Firmata per dispositivi aggiuntivi. Riflettendo su quell'articolo, mi sono reso conto di quanto è cambiato da quando ho preso carta e penna per quell'articolo. Oltre a questo articolo, il Dr. Wheeler ha documentato i suoi sforzi e potresti voler dare un'occhiata anche a questo.

FirmataExpress si basa su StandardFirmata e la struttura della directory StandardFirmata si è evoluta. Inoltre, l'API pymata4 è anche un po' diversa dall'API PyMata originale del 2014. Ho pensato che questo sarebbe stato il momento perfetto per rivisitare e aggiornare quell'articolo. Usando il lavoro del Dr. Wheeler come base, esploriamo come estendere la funzionalità pymata4/FirmataExpress.

Prima di iniziare - Alcune informazioni di base su Arduino/Firmata

Allora, cos'è Firmata? Citando dalla pagina web di Firmata, "Firmata è un protocollo generico per comunicare con i microcontrollori dal software su un computer host".

Arduino Firmata utilizza un'interfaccia seriale per trasportare informazioni di comando e report tra un microcontrollore Arduino e un PC, in genere utilizzando un collegamento seriale/USB impostato a 57600 bps. I dati trasferiti attraverso questo collegamento sono binari e il protocollo è implementato in un modello client/server.

Il lato server viene caricato su un microcontrollore Arduino sotto forma di uno schizzo Arduino. Lo sketch StandardFirmata, incluso con l'IDE Arduino, controlla i pin I/O Arduino, come comandato dal client. Riporta inoltre al client le modifiche ai pin di input e altre informazioni di report. FirmataExpress è una versione estesa di StandardFirmata. Funziona a una velocità di collegamento seriale di 115200 bps.

Il client Arduino utilizzato per questo articolo è pymata4. È un'applicazione Python che viene eseguita su un PC. Invia comandi e riceve report dal server Arduino. Poiché pymata4 è implementato in Python, funziona su computer Windows, Linux (incluso Raspberry Pi) e macOS.

Perché usare Firmata?

I microcontrollori Arduino sono piccoli dispositivi meravigliosi, ma le risorse del processore e della memoria sono alquanto limitate. Per le applicazioni che richiedono un uso intensivo del processore o della memoria, spesso non c'è altra scelta che scaricare la richiesta di risorse su un PC affinché l'applicazione abbia successo.

Ma questo non è l'unico motivo per utilizzare StandardFirmata. Quando si sviluppano applicazioni Arduino più leggere, un PC può fornire strumenti e funzionalità di debug non direttamente disponibili su un microcontrollore Arduino. L'utilizzo di client e server "fissi" aiuta a limitare la complessità dell'applicazione a un PC, che è più facilmente gestibile. Una volta che l'applicazione è stata perfezionata, può essere tradotta in uno schizzo Arduino autonomo e personalizzato.

Perché usare pymata4?

Essendo il suo autore, ovviamente, sono di parte. Detto questo, è l'unico client Firmata basato su Python che è stato continuamente mantenuto negli ultimi anni. Fornisce un'API intuitiva e facile da usare. Oltre agli schizzi basati su StandardFirmata, supporta Firmata su WiFi per dispositivi come ESP-8266 quando si utilizza lo schizzo StandardFirmataWifI.

Inoltre, pymata4 è stato progettato per essere facilmente esteso da un utente per supportare sensori e attuatori aggiuntivi non attualmente supportati da StandardFirmata.

Passaggio 1: comprensione del protocollo Firmata

Comprendere il Protocollo Firmata
Comprendere il Protocollo Firmata

Il protocollo di comunicazione Arduino Firmata è derivato dal protocollo MIDI, che utilizza uno o più byte a 7 bit per rappresentare i dati.

Firmata è stato progettato per essere estensibile dall'utente. Il meccanismo che fornisce questa estensibilità è il protocollo di messaggistica System Exclusive (SysEx).

Il formato di un messaggio SysEx, come definito dal Protocollo Firmata, è mostrato nell'illustrazione sopra. Inizia con un byte START_SYSEX con un valore fisso di 0xF0 esadecimale ed è seguito da un byte di comando SysEx univoco. Il valore del byte di comando deve essere compreso nell'intervallo esadecimale 0x00-0x7F. Il byte di comando è quindi seguito da un numero non specificato di byte di dati a 7 bit. Infine, il messaggio viene terminato con un byte END_SYSEX, con un valore fisso di esadecimale 0xF7.

Codifica/Decodifica dati Firmata

Poiché la parte dei dati utente di un messaggio SysEx è costituita da una serie di byte a 7 bit, potresti chiederti come si rappresenta un valore maggiore di 128 (0x7f)? Firmata codifica questi valori smontandoli in più blocchi di byte da 7 bit prima che i dati vengano sottoposti a marshalling attraverso il collegamento dati. Il byte meno significativo (LSB) di un elemento di dati viene inviato per primo, seguito per convenzione dai componenti sempre più significativi dell'elemento di dati. Il byte più significativo (MSB) dell'elemento dati è l'ultimo elemento dati inviato.

Come funziona?

Supponiamo di voler incorporare un valore 525 nella porzione di dati di un messaggio SysEx. Poiché un valore di 525 è chiaramente maggiore di un valore di 128, dobbiamo dividerlo o disassemblarlo in "pezzi" di byte da 7 bit.

Ecco come è fatto.

Il valore di 525 in decimale è equivalente al valore esadecimale di 0x20D, un valore a 2 byte. Per ottenere l'LSB, mascheriamo il valore eseguendo un AND con 0x7F. Di seguito sono mostrate entrambe le implementazioni "C" e Python:

// Implementazione "C" per isolare LSB

int max_distance_LSB = max_distance & 0x7f; // maschera il byte inferiore # Implementazione Python per isolare LSB max_distance_LSB = max_distance & 0x7F # maschera il byte inferiore

Dopo il mascheramento, max_distance_LSB conterrà 0x0d. 0x20D e 0x7F = 0x0D.

Successivamente, dobbiamo isolare l'MSB per questo valore a 2 byte. Per fare ciò, sposteremo il valore di 0x20D a destra, 7 posizioni.

// Implementazione "C" per isolare MSB con un valore di 2 byte

int max_distance_MSB = max_distance >> 7; // sposta il byte più importante # Implementazione Python per isolare MSB di 2 byte valore max_distance_MSB = max_distance >> 7 # shift per ottenere il byte superiore Dopo lo spostamento, max_distance_MSB conterrà un valore di 0x04.

Quando vengono ricevuti i dati di marshalling "chunkified", devono essere riassemblati in un unico valore. Ecco come vengono riassemblati i dati sia in "C" che in Python

// Implementazione "C" per riassemblare i 2 byte, // 7 valori di bit in un unico valore int max_distance = argv[0] + (argv[1] << 7); # Implementazione Python per riassemblare i valori a 2 byte, # 7 bit in un unico valore max_distance = data[0] + (data[1] << 7)

Dopo il riassemblaggio, il valore è nuovamente uguale a 525 decimale o 0x20D esadecimale.

Questo processo di disassemblaggio/riassemblaggio può essere eseguito dal client o dal server.

Passaggio 2: iniziamo

Il supporto di un nuovo dispositivo richiede modifiche sia al server residente Arduino che al client Python residente sul PC. Il lavoro del Dr. Wheeler sarà utilizzato per illustrare le modifiche necessarie.

Forse il passo più importante è decidere se si desidera integrare una libreria di dispositivi di supporto esistente nel lato Arduino dell'equazione o scriverne una propria. Si raccomanda che se riesci a trovare una libreria esistente, è molto più semplice usarla che scriverne una da zero.

Per il supporto del dispositivo DHT, il Dr. Wheeler ha basato il suo codice di estensione sulla libreria DHTNew. Molto abilmente, il Dr. Wheeler ha diviso la funzionalità della libreria DHTNew sui lati Arduino e pymata4 dell'equazione per fornire un blocco minimo sul lato Arduino.

Se osserviamo DHTNew, esegue tutte le seguenti operazioni:

  • Imposta la modalità di uscita digitale pin selezionata.
  • Emette un segnale codificato per recuperare gli ultimi valori di umidità e temperatura.
  • Verifica e segnala eventuali errori.
  • Calcola i valori di temperatura e umidità leggibili dall'uomo dai dati grezzi recuperati.

Per mantenere le cose il più efficienti possibile sul lato FirmataExpress, il Dr. Wheeler ha scaricato le routine di conversione dei dati da Arduino a pymata4.

Passaggio 3: modifica di FirmataExpress per il supporto DHT

L'albero delle directory FirmataExpress

Di seguito sono riportati tutti i file che compongono il repository FirmataExpress. Questo albero è identico a quello di StandardFiramata, solo che alcuni dei nomi dei file riflettono il nome del repository.

I file che necessitano di modifiche sono quelli che hanno un asterisco (*) accanto a loro.

FirmataExpress

├── * Boards.h

esempi

└── FirmataExpress

├── boardx

├── * FirmataExpress.ino

├── LICENZA.txt

└── Makefile

├── * FirmataConstants.h

* FirmataDefines.h

FirmataExpress.cpp

FirmataExpress.h

FirmataMarshaller.cpp

FirmataMarshaller.h

FirmataParser.cpp

FirmataParser.h

Diamo un'occhiata a ciascuno dei file e alle modifiche apportate.

Boards.h

Questo file contiene definizioni macro di tipo pin per ciascuno dei tipi di scheda supportati. Definisce il numero massimo di dispositivi supportati quando è necessario supportare più di un dispositivo.

Per il dispositivo DHT possono essere collegati fino a 6 dispositivi alla volta e questo valore è definito come:

#ifndef MAX_DHTS

#define MAX_DHTS 6 #endif

Inoltre, le macro di tipo pin possono essere definite facoltativamente per il nuovo dispositivo, sia per tutti i tipi di scheda che solo per quelli di tuo interesse. Queste macro vengono utilizzate principalmente a scopo di reportistica e non vengono utilizzate per controllare i dispositivi. Queste macro definiscono entrambi i pin che supportano il dispositivo:

#define IS_PIN_DHT(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_DHTS)

Oltre a una macro per definire una conversione del numero pin.

#define PIN_TO_DHT(p) PIN_TO_DIGITAL(p)

FirmataConstants.h

Questo file contiene il numero di versione del firmware, che potresti voler modificare per tenere traccia di quale versione hai caricato sul tuo Arduino. Contiene anche i valori del messaggio Firmata, inclusi i messaggi Firmata SysEx.

Dovrai assegnare un nuovo messaggio o una serie di messaggi per il tuo dispositivo in questo file. Per il DHT sono stati aggiunti due messaggi. Uno configura un pin come pin "DHT" e l'altro, come messaggio di reporter, quando si inviano gli ultimi dati DHT al client.

statico const int DHT_CONFIG = 0x64;

statico const int DHT_DATA = 0x65;

Anche le modalità pin sono specificate in questo file. Per il DHT è stata creata una nuova modalità pin:

statico const int PIN_MODE_DHT = 0x0F; // pin configurato per DHT

Quando si aggiunge una nuova modalità pin, è necessario regolare TOTAL_PIN_MODES:

statico const int TOTAL_PIN_MODES = 17;

FirmataDefines.h

Questo file deve essere aggiornato per riflettere i nuovi messaggi aggiunti a FirmataConstants.h:

#ifdef DHT_CONFIG#undef DHT_CONFIG #endif #define DHT_CONFIG firmato::DHT_CONFIG // DHT request #ifdef DHT_DATA #undef DHT_DATA #endif #define DHT_DATA::DHT_DATA // DHT replica #ifdef PIN_DEF firmato_DEHT PIN_MOHT #endDE_DHT firmato_MODEHT::PIN_MODE_DHT

FirmataExpress.ino

In questa discussione, tratteremo i "punti salienti" delle modifiche apportate a questo sketch Arduino.

Affinché FirmataExpress possa supportare fino a sei dispositivi DHT contemporaneamente, sono stati creati 3 array per tenere traccia di ciascun numero di pin associato del dispositivo, il suo valore WakeUpDelay e il tipo di dispositivo, ovvero DHT22 o DHT11:

// Sensori DHT

int numActiveDHTs = 0; // numero di DHT allegati uint8_t DHT_PinNumbers[MAX_DHTS]; uint8_t DHT_WakeUpDelay[MAX_DHTS]; uint8_t DHT_TYPE[MAX_DHTS];

Poiché entrambi i tipi di dispositivo richiedono circa 2 secondi tra le letture, dobbiamo assicurarci di leggere ogni DHT solo una volta nell'intervallo di tempo di 2 secondi. Alcuni dispositivi, come i dispositivi DHT e i sensori di distanza HC-SR04, sono accessibili solo periodicamente. Questo consente loro il tempo di interagire con i loro ambienti.

uint8_t nextDHT = 0; // indicizza in dht per leggere il prossimo dispositivo

uint8_t currentDHT = 0; // Tiene traccia di quale sensore è attivo. int dhtNumLoops = 0; // Numero target di volte attraverso il ciclo b4 che accede a un DHT int dhtLoopCounter = 0; // Contatore loop

Configurazione e lettura del dispositivo DHT

Quando FirmataExpress riceve un comando SysEx per configurare un pin per il funzionamento DHT, verifica che non sia stato superato il numero massimo di dispositivi DHT. Se il nuovo DHT può essere supportato, gli array DHT vengono aggiornati. Se il tipo DHT è sconosciuto, viene creato un messaggio di stringa SysEx e ritrasmesso a pymata4

case DHT_CONFIG: int DHT_Pin = argv[0]; int DHT_type = argv[1]; if (numActiveDHTs < MAX_DHTS) { if (DHT_type == 22) { DHT_WakeUpDelay[numActiveDHTs] = 1; } else if (DHT_type == 11) { DHT_WakeUpDelay[numActiveDHTs] = 18; } else { Firmata.sendString("ERRORE: TIPO DI SENSORE SCONOSCIUTO, I SENSORI VALIDI SONO 11, 22"); rottura; } // testa il sensore DHT_PinNumbers[numActiveDHTs] = DHT_Pin; DHT_TYPE[numActiveDHTs] = DHT_type; setPinModeCallback(DHT_Pin, PIN_MODE_DHT);

FirmataExpress tenta quindi di comunicare con il dispositivo DHT. In caso di errori, forma un messaggio SysEx con i dati di errore e invia il messaggio SysEx a pymat4. La variabile _bits contiene i dati restituiti dal dispositivo DHT per un'ulteriore elaborazione da parte di pymata4, se lo si desidera.

Firmata.write(START_SYSEX);

Firmata.write(DHT_DATA); Firmata.write(DHT_Pin); Firmata.write(DHT_type); for (uint8_t i = 0; i > 7 & 0x7f); } Firmata.write(abs(rv)); Firmata.write(1); Firmata.write(END_SYSEX);

Se vengono restituiti dati validi, il numero di DHT attivi viene incrementato. Viene regolata anche una variabile che tiene traccia del numero di iterazioni del ciclo da completare prima di controllare il successivo DHT per i dati. Questa variabile assicura che, indipendentemente dal numero di DHT aggiunti al sistema, verranno tutti letti entro un periodo di 2 secondi.

int rv = readDhtSensor(numActiveDHTs);

if (rv == DHTLIB_OK) { numActiveDHTs++; dhtNumLoops = dhtNumLoops / numActiveDHTs; // tutto ok }

Se uno o più dispositivi DHT sono stati configurati nella funzione loop dello sketch, viene letto il dispositivo DHT successivo. I dati validi o il relativo stato di errore vengono restituiti a pymata4 sotto forma di messaggio SysEx:

if (dhtLoopCounter++ > dhtNumLoops) { if (numActiveDHTs) { int rv = readDhtSensor(nextDHT); uint8_t current_pin = DHT_PinNumbers[nextDHT]; uint8_t current_type = DHT_TYPE[nextDHT]; dhtLoopCounter = 0; DHT attuale = DHT successivo; if (nextDHT++ >= numActiveDHTs - 1) { nextDHT = 0; } if (rv == DHTLIB_OK) { // TEST CHECKSUM uint8_t sum = _bits[0] + _bits[1] + _bits[2] + _bits[3]; if (_bits[4] != somma) { rv = -1; } } // rinvia il messaggio con uno stato di errore Firmata.write(START_SYSEX); Firmata.write(DHT_DATA); Firmata.write(current_pin); Firmata.write(current_type); for (uint8_t i = 0; i < sizeof(_bits) - 1; ++i) { Firmata.write(_bits); // Firmata.write(_bits; } Firmata.write(abs(rv)); Firmata.write(0); Firmata.write(END_SYSEX); } }

Il codice utilizzato per comunicare con il dispositivo DHT è derivato direttamente dalla libreria DHTNew:

int readDhtSensor(int index){

// INIT BUFFERVAR PER RICEVERE DATI uint8_t mask = 128; uint8_t idx = 0; // BUFFER VUOTO // memset(_bits, 0, sizeof(_bits)); for (uint8_t i = 0; i 5 BYTES for (uint8_t i = 40; i != 0; i--) { loopCnt = DHTLIB_TIMEOUT; while (digitalRead(pin) == LOW) { if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; } uint32_t t = micros(); loopCnt = DHTLIB_TIMEOUT; while (digitalRead(pin) == HIGH) { if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; } if ((micros() - t) > 40) { _bits[idx] |= mask; } mask >>= 1; if (mask == 0) // byte successivo? { mask = 128; idx++; } } return DHTLIB_OK; }

Passaggio 4: modifica Pymata4 per il supporto DHT

private_constants.h

Per supportare il DHT, dobbiamo aggiungere sia il nuovo tipo di pin che i messaggi SysEx a questo file:

# pin modalità INPUT = 0x00 # pin impostato come input OUTPUT = 0x01 # pin impostato come output ANALOG = 0x02 # pin analogico in modalità analogInput PWM = 0x03 # pin digitale in modalità uscita PWM SERVO = 0x04 # pin digitale in modalità uscita Servo I2C = 0x06 # pin incluso nella configurazione I2C STEPPER = 0x08 # qualsiasi pin in modalità stepper SERIAL = 0x0a PULLUP = 0x0b # Qualsiasi pin in modalità pullup SONAR = 0x0c # Qualsiasi pin in modalità SONAR TONE = 0x0d # Qualsiasi pin in modalità tone PIXY = 0x0e # riservato alla modalità fotocamera pixy DHT = 0x0f # sensore DHT IGNORE = 0x7f # messaggi di comando DHT SysEx DHT_CONFIG = 0x64 # comando dht config DHT_DATA = 0x65 # risposta sensore dht

Il tipo di pin aggiunto e i comandi SysEx devono corrispondere ai valori in FirmataConstants.h aggiunti a FirmataExpress.

pymata4.py

Pymata4 utilizza un dizionario Python per associare rapidamente un messaggio Firmata in arrivo a un gestore di messaggi. Il nome di questo dizionario è report_dispatch.

Il formato per una voce del dizionario è:

{MessageID: [message_handler, numero di byte di dati da elaborare]}

È stata aggiunta una voce al dizionario per gestire i messaggi DHT in arrivo:

{PrivateConstants. DHT_DATA: [self._dht_read_response, 7]}

I 7 byte di dati nel messaggio sono il numero del pin digitale Arduino, il tipo di dispositivo DHT (22 o 11) e i 5 byte di dati grezzi.

Il metodo _dht_read_response verifica la presenza di eventuali errori segnalati. Se non vengono segnalati errori, l'umidità e la temperatura vengono calcolate utilizzando l'algoritmo portato dalla libreria Arduino DHTNew.

I valori calcolati vengono riportati tramite un metodo di callback fornito dall'utente. Sono inoltre memorizzati nella struttura dati interna pin_data. L'ultimo valore riportato può essere richiamato interrogando pin_data utilizzando il metodo dht_read.

Configurazione di un nuovo dispositivo DHT

Quando si aggiunge un nuovo dispositivo DHT, viene chiamato il metodo set_pin_mode_dht. Questo metodo aggiorna i pin_data per i pin digitali. Crea e invia anche un messaggio SysEx DHT_CONFIG a FirmataExpress.

Passaggio 5: concludere

Come abbiamo visto, l'aggiunta del supporto Firmata per un nuovo dispositivo richiede la modifica del codice del server Arduino FirmataExpress e del codice del client pymata4 basato su Python. Il codice FirmataExpress può essere difficile da eseguire il debug. Un metodo chiamato printData è stato aggiunto a FirmataExpress per facilitare il debug. Questo metodo consente di inviare i valori dei dati da FirmataExpress e di stamparli sulla console pymata4.

Questa funzione richiede sia un puntatore a una stringa di caratteri sia il valore che si desidera visualizzare. Se il valore dei dati è contenuto in una variabile chiamata argc, potresti chiamare printData con i seguenti parametri.

printData((char*)"argc= ", argc);

Se hai domande, lascia un commento e sarò felice di rispondere.

Buona codifica!

Consigliato: