Innholdsfortegnelse:

Going Beyond Standard Firmata - Revidert: 5 trinn
Going Beyond Standard Firmata - Revidert: 5 trinn

Video: Going Beyond Standard Firmata - Revidert: 5 trinn

Video: Going Beyond Standard Firmata - Revidert: 5 trinn
Video: Part 1 - Anne of Avonlea Audiobook by Lucy Maud Montgomery (Chs 01-11) 2024, Juli
Anonim
Going Beyond Standard Firmata - Revidert
Going Beyond Standard Firmata - Revidert

For kort tid siden ble jeg kontaktet av Dr. Martyn Wheeler, en pymata4 -bruker, for veiledning i å legge til støtte for DHT22 fuktighets-/temperatursensor i pymata4 -biblioteket. Pymata4 -biblioteket, sammen med Arduino -motstykket FirmataExpress, lar brukerne styre og overvåke Arduino -enhetene eksternt. Innen noen få runder med e -postutvekslinger, var Dr. Wheeler vellykket med å modifisere både pymata4 og FirmataExpress. Som et resultat er støtte for DHT22- og DHT11 -sensorene nå en standard del av pymata4 og FirmataExpress.

I mai 2014 skrev jeg en artikkel om å legge til støtte for Firmata for flere enheter. Når jeg reflekterte over den artikkelen, innså jeg hvor mye som har endret seg siden jeg tok penn til papir for den artikkelen. I tillegg til denne artikkelen, dokumenterte Dr. Wheeler sin innsats, og det kan være lurt å sjekke det også.

FirmataExpress er basert på StandardFirmata, og StandardFirmata -katalogstrukturen har utviklet seg. I tillegg er pymata4 API også ganske annerledes enn det opprinnelige PyMata API fra 2014. Jeg trodde dette ville være det perfekte tidspunktet for å gå tilbake til og oppdatere artikkelen. Ved å bruke Dr. Wheelers arbeid som grunnlag, la oss utforske hvordan vi kan utvide pymata4/FirmataExpress -funksjonaliteten.

Før vi begynner - litt bakgrunnsinformasjon om Arduino/Firmata

Så hva er Firmata? Sitater fra Firmata -nettsiden, "Firmata er en generisk protokoll for kommunikasjon med mikrokontrollere fra programvare på en vertsmaskin."

Arduino Firmata bruker et serielt grensesnitt for å transportere både kommando- og rapportinformasjon mellom en Arduino -mikrokontroller og en PC, vanligvis ved å bruke en seriell/USB -kobling satt til 57600 bps. Dataene som overføres over denne lenken er binære, og protokollen er implementert i en klient/server -modell.

Serversiden lastes opp til en Arduino -mikrokontroller i form av en Arduino -skisse. StandardFirmata -skissen, som følger med Arduino IDE, styrer Arduino I/O -pinnene, slik kommandoen befaler. Den rapporterer også endringer i inngangsnål og annen rapportinformasjon tilbake til klienten. FirmataExpress er en utvidet versjon av StandardFirmata. Den kjører med en seriell koblingshastighet på 115200 bps.

Arduino -klienten som ble brukt for denne artikkelen er pymata4. Det er et Python -program som kjøres på en PC. Den både sender kommandoer til og mottar rapporter fra Arduino -serveren. Fordi pymata4 er implementert i Python, kjører den på Windows, Linux (inkludert Raspberry Pi) og macOS -datamaskiner.

Hvorfor bruke Firmata?

Arduino mikrokontrollere er fantastiske små enheter, men prosessor- og hukommelsesressurser er noe begrenset. For programmer som er prosessor- eller minneintensive, er det ofte lite annet valg enn å laste ned ressursbehovet på en PC for at programmet skal lykkes.

Men det er ikke den eneste grunnen til å bruke StandardFirmata. Når du utvikler lettere Arduino -applikasjoner, kan en PC tilby verktøy og feilsøkingsfunksjoner som ikke er direkte tilgjengelige på en Arduino -mikrokontroller. Ved å bruke en "fast" klient og server hjelper du å begrense applikasjonskompleksiteten til en PC, som er lettere å administrere. Når programmet er perfeksjonert, kan det oversettes til en tilpasset, frittstående Arduino -skisse.

Hvorfor bruke pymata4?

Å være forfatter, selvfølgelig, er jeg partisk. Når det er sagt, er det den eneste Python-baserte Firmata-klienten som har blitt vedlikeholdt kontinuerlig de siste årene. Det gir et intuitivt og brukervennlig API. I tillegg til StandardFirmata-baserte skisser, støtter den Firmata over WiFi for enheter som ESP-8266 når du bruker StandardFirmataWifI-skissen.

Pymata4 ble også designet for å enkelt kunne utvides av en bruker for å støtte flere sensorer og aktuatorer som for øyeblikket ikke støttes av StandardFirmata.

Trinn 1: Forstå Firmata -protokollen

Forstå Firmata -protokollen
Forstå Firmata -protokollen

Arduino Firmata-kommunikasjonsprotokollen er avledet fra MIDI-protokollen, som bruker en eller flere 7-bits byte for å representere data.

Firmata er designet for å være brukerutvidelig. Mekanismen som gir denne utvidelsen, er System Exclusive (SysEx) meldingsprotokoll.

Formatet til en SysEx -melding, som definert av Firmata -protokollen, er vist i illustrasjonen ovenfor. Den begynner med en START_SYSEX -byte med en fast verdi på heksadesimal 0xF0, og etterfølges av en unik SysEx -kommandobyte. Verdien av kommandobyten må være i området heksadesimalt 0x00-0x7F. Kommandobyte blir deretter etterfulgt av et uspesifisert antall 7-biters databyte. Til slutt avsluttes meldingen med en END_SYSEX -byte, med en fast verdi på heksadesimal 0xF7.

Firmata Data Encoding/Decoding

Siden brukerdatadelen av en SysEx-melding består av en serie med 7-bits byte, kan du lure på hvordan en representerer en verdi større enn 128 (0x7f)? Firmata koder disse verdiene ved å demontere dem i flere 7-bits byte-biter før dataene sendes ut over datalinken. Den minst signifikante byten (LSB) for et dataelement sendes først, etterfulgt av stadig mer betydningsfulle komponenter i dataelementet etter konvensjon. Den viktigste byten (MSB) for dataelementet er det siste dataelementet som ble sendt.

Hvordan virker dette?

La oss si at vi ønsker å innlemme en verdi 525 i datadelen av en SysEx -melding. Siden verdien på 525 er klart større enn verdien 128, må vi dele den eller demontere den i 7-bit byte "biter".

Her er hvordan det gjøres.

Verdien på 525 i desimal tilsvarer den heksadesimale verdien på 0x20D, en 2-byte verdi. For å få LSB, maskerer vi verdien ved å ANDE den med 0x7F. Både "C" og Python -implementeringer er vist nedenfor:

// "C" -implementering for å isolere LSB

int max_distance_LSB = max_distance & 0x7f; // masker nedre byte # Python -implementering for å isolere LSB max_distance_LSB = max_distance & 0x7F # maskere den nedre byten

Etter maskering vil max_distance_LSB inneholde 0x0d. 0x20D og 0x7F = 0x0D.

Deretter må vi isolere MSB for denne 2-byte-verdien. For å gjøre dette, vil vi flytte verdien av 0x20D til høyre, 7 steder.

// "C" -implementering for å isolere MSB med 2 byte -verdi

int max_distance_MSB = max_distance >> 7; // skift byten for høy rekkefølge # Python -implementering for å isolere MSB med 2 byte -verdi max_distance_MSB = max_distance >> 7 # shift for å få den øvre byte Etter skifting, vil max_distance_MSB inneholde en verdi på 0x04.

Når de "chunkified" marshaled dataene er mottatt, må de settes sammen til en enkelt verdi. Her er hvordan dataene settes sammen igjen i både "C" og Python

// "C" -implementering for å sette sammen 2 byte igjen, // 7 bitverdier i en enkelt verdi int max_distance = argv [0] + (argv [1] << 7); # Python -implementering for å sette sammen 2 byte, # 7 bitverdier til en enkelt verdi max_distance = data [0] + (data [1] << 7)

Etter montering er verdien igjen 525 desimaler eller 0x20D heksadesimal.

Denne demonterings-/monteringsprosessen kan utføres av enten klienten eller serveren.

Trinn 2: La oss komme i gang

Støtte for en ny enhet krever endringer i både Arduino resident -serveren og PC -resident Python -klienten. Dr. Wheelers arbeid vil bli brukt til å illustrere de nødvendige modifikasjonene.

Det kanskje viktigste trinnet er å bestemme om du ønsker å integrere et eksisterende bibliotek for støttende enheter i Arduino -siden av ligningen eller skrive ditt eget. Det anbefales at hvis du finner et eksisterende bibliotek, er det langt enklere å bruke det enn å skrive ditt eget fra bunnen av.

For støtte for DHT -enheter, baserte Dr. Wheeler utvidelseskoden på DHTNew -biblioteket. Veldig smart delte Dr. Wheeler funksjonaliteten til DHTNew -biblioteket over Arduino- og pymata4 -sidene av ligningen for å gi minimal blokkering på Arduino -siden.

Hvis vi ser på DHTNew, utfører den alt av følgende:

  • Angir valgt digital pin -utgangsmodus.
  • Klokker ut et kodet signal for å hente de siste fuktighets- og temperaturverdiene.
  • Kontrollerer og rapporterer eventuelle feil.
  • Beregner verdier som kan leses av temperatur og fuktighet fra rådataene som er hentet.

For å holde tingene så effektive som mulig på FirmataExpress -siden, lastet Dr. Wheeler ned datakonverteringsrutinene fra Arduino til pymata4.

Trinn 3: Endre FirmataExpress for DHT -støtte

FirmataExpress -katalogtreet

Nedenfor er alle filene som inneholder FirmataExpress -depotet. Dette treet er identisk med det for StandardFiramata, bare at noen av filnavnene gjenspeiler depotets navn.

Filene som trenger endring er de som har en stjerne (*) ved siden av.

FirmataExpress

├── * Tavler.h

├── eksempler

│ └── FirmataExpress

│ ├── boardx

│ ├── * FirmataExpress.ino

│ ├── LISENS.txt

│ └── Makefile

├── * FirmataConstants.h

├── * FirmataDefines.h

├── FirmataExpress.cpp

├── FirmataExpress.h

├── FirmataMarshaller.cpp

├── FirmataMarshaller.h

├── FirmataParser.cpp

└── FirmataParser.h

La oss se på hver av filene og endringene som ble gjort.

Tavler. H

Denne filen inneholder makrot definisjoner av pin-type for hver av de støttede brettypene. Den definerer maksimalt antall enheter som støttes når mer enn én enhet må støttes.

For DHT -enheten kan opptil 6 enheter kobles til om gangen, og denne verdien er definert som:

#ifndef MAX_DHTS

#define MAX_DHTS 6 #endif

Også makroer av pin-type kan eventuelt defineres for den nye enheten, enten for alle brettypene eller bare de som er av interesse for deg. Disse makroene brukes hovedsakelig til rapporteringsformål og brukes ikke til å kontrollere enhetene. Disse makroene definerer begge pinnene som støtter enheten:

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

Samt en makro for å definere en pin-nummer konvertering.

#define PIN_TO_DHT (p) PIN_TO_DIGITAL (p)

FirmataConstants.h

Denne filen inneholder versjonsnummeret til fastvaren, som du kan endre for å holde oversikt over hvilken versjon du har lastet inn på Arduino. Den inneholder også Firmata -meldingsverdiene, inkludert Firmata SysEx -meldingene.

Du må tilordne en ny melding eller et sett med meldinger for enheten din i denne filen. For DHT ble to meldinger lagt til. Den ene konfigurerer en pinne som en "DHT" -nål, og den andre, som en reportermelding, når du sender de siste DHT -dataene tilbake til klienten.

statisk const int DHT_CONFIG = 0x64;

statisk const int DHT_DATA = 0x65;

Pin -moduser er også spesifisert i denne filen. For DHT ble det opprettet en ny pin -modus:

statisk const int PIN_MODE_DHT = 0x0F; // pin konfigurert for DHT

Når du legger til en ny pin -modus, må TOTAL_PIN_MODES justeres:

statisk const int TOTAL_PIN_MODES = 17;

FirmataDefines.h

Denne filen må oppdateres for å gjenspeile de nye meldingene som er lagt til i FirmataConstants.h:

# ifdef DHT_CONFIG # udef DHT_CONFIG #endif #define DHT_CONFIG firmata:: DHT_CONFIG // DHT forespørsel # ifdef DHT_DATA #undef DHT_DATA #endif #define DHT_DATA firmata:: DHT_DATA // DHT svare # ifdef PIN_MODE_DHT #undef PIN_MODE_DHT #endif #define PIN_MODE_DHT firmata:: PIN_MODE_DHT

FirmataExpress.ino

I denne diskusjonen vil vi dekke "høydepunktene" av endringene i denne Arduino-skissen.

For at FirmataExpress kunne støtte opptil seks DHT -enheter samtidig, ble det laget 3 matriser for å holde oversikt over hver av enhetens tilhørende pin -nummer, dens WakeUpDelay -verdi og enhetstypen, det vil si DHT22 eller DHT11:

// DHT -sensorer

int numActiveDHTs = 0; // antall vedlagte DHT -er uint8_t DHT_PinNumbers [MAX_DHTS]; uint8_t DHT_WakeUpDelay [MAX_DHTS]; uint8_t DHT_TYPE [MAX_DHTS];

Fordi begge enhetstyper krever omtrent 2 sekunder mellom lesingene, må vi sørge for at vi leser hver DHT bare én gang i tidsrammen på 2 sekunder. Noen enheter, for eksempel DHT-enheter og HC-SR04 avstandssensorer, er bare tilgjengelig med jevne mellomrom. Dette gir dem tid til å samhandle med omgivelsene.

uint8_t nextDHT = 0; // indekser i dht for neste enhet som skal leses

uint8_t currentDHT = 0; // Holder oversikt over hvilken sensor som er aktiv. int dhtNumLoops = 0; // Mål antall ganger gjennom loop b4 som får tilgang til en DHT int dhtLoopCounter = 0; // Sløyfedisk

Konfigurere og lese DHT -enheten

Når FirmataExpress mottar en SysEx -kommando for å konfigurere en pin for DHT -drift, bekrefter den at maksimalt antall DHT -enheter ikke er overskredet. Hvis den nye DHT kan støttes, oppdateres DHT -matrisene. Hvis DHT -typen er ukjent, opprettes en SysEx -strengmelding og sendes tilbake til pymata4

sak DHT_CONFIG: int DHT_Pin = argv [0]; int DHT_type = argv [1]; if (numActiveDHTs <MAX_DHTS) {if (DHT_type == 22) {DHT_WakeUpDelay [numActiveDHTs] = 1; } annet hvis (DHT_type == 11) {DHT_WakeUpDelay [numActiveDHTs] = 18; } annet {Firmata.sendString ("FEIL: UKjent sensortype, Gyldige sensorer er 11, 22"); gå i stykker; } // test sensoren DHT_PinNumbers [numActiveDHTs] = DHT_Pin; DHT_TYPE [numActiveDHTs] = DHT_type; setPinModeCallback (DHT_Pin, PIN_MODE_DHT);

FirmataExpress prøver deretter å kommunisere med DHT -enheten. Hvis det er noen feil, danner den en SysEx -melding med feildataene og sender SysEx -meldingen tilbake til pymat4. Variabelen _bits inneholder dataene som returneres av DHT -enheten for ytterligere behandling av pymata4 hvis ønskelig.

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

Hvis gyldige data returneres, økes antallet aktive DHT -er. En variabel som holder oversikt over hvor mange loop -iterasjoner som skal fullføres før du sjekker neste DHT for data, blir også justert. Denne variabelen sikrer at uansett hvor mange DHT -er som blir lagt til i systemet, vil de alle bli lest i løpet av en periode på 2 sekunder.

int rv = readDhtSensor (numActiveDHTs);

hvis (rv == DHTLIB_OK) {numActiveDHTs ++; dhtNumLoops = dhtNumLoops / numActiveDHTs; // alt ok}

Hvis en eller flere DHT -enheter er konfigurert i sløyfefunksjonen til skissen, leses den neste DHT -enheten. Enten gyldige data eller feilstatus blir returnert til pymata4 i form av en SysEx -melding:

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; currentDHT = nextDHT; if (nextDHT ++> = numActiveDHTs - 1) {nextDHT = 0; } if (rv == DHTLIB_OK) {// TEST CHECKSUM uint8_t sum = _bits [0] + _bits [1] + _bits [2] + _bits [3]; hvis (_bits [4]! = sum) {rv = -1; }}} // send meldingen tilbake med en feilstatus 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);}}

Koden som brukes til å kommunisere med DHT -enheten, stammer direkte fra DHTNew -biblioteket:

int readDhtSensor (int index) {

// INIT BUFFERVAR FOR Å MOTTA DATA uint8_t mask = 128; uint8_t idx = 0; // EMPTY BUFFER // 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) returner 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] | = maske;} maske >> = 1; hvis (mask == 0) // neste byte? {Mask = 128; idx ++;}} returner DHTLIB_OK;}

Trinn 4: Endre Pymata4 for DHT -støtte

private_constants.h

For å støtte DHT må vi legge til både den nye pin-type og SysEx-meldingen i denne filen:

# pin -modus INPUT = 0x00 # pin satt som inngang OUTPUT = 0x01 # pin satt som output ANALOG = 0x02 # analog pin i analog Input mode PWM = 0x03 # digital pin i PWM output mode SERVO = 0x04 # digital pin i Servo output mode I2C = 0x06 # pin inkludert i I2C -oppsett STEPPER = 0x08 # hvilken som helst pin i stepper -modus SERIAL = 0x0a PULLUP = 0x0b # En hvilken som helst pin i pullup -modus SONAR = 0x0c # En hvilken som helst pin i SONAR -modus TONE = 0x0d # En hvilken som helst pinne i tonemodus PIXY = 0x0e # reservert for pixy kameramodus DHT = 0x0f # DHT sensor IGNORE = 0x7f # DHT SysEx kommandomeldinger DHT_CONFIG = 0x64 # dht config kommando DHT_DATA = 0x65 # dht sensor svar

Den ekstra pin -typen og SysEx -kommandoene må samsvare med verdiene i FirmataConstants.h som er lagt til i FirmataExpress.

pymata4.py

Pymata4 bruker en Python -ordbok for raskt å knytte en innkommende Firmata -melding til en meldingsbehandler. Navnet på denne ordboken er report_dispatch.

Formatet for en ordbokoppføring er:

{MessageID: [message_handler, antall databytes som skal behandles]}

En oppføring ble lagt til i ordlisten for å håndtere innkommende DHT -meldinger:

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

De 7 byte med data i meldingen er Arduino digital pin -nummer, type DHT -enhet (22 eller 11) og 5 byte med rådata.

Metoden _dht_read_response ser etter eventuelle rapporterte feil. Hvis det ikke er rapporterte feil, beregnes fuktighet og temperatur ved hjelp av algoritmen som er sendt fra Arduino DHTNew -biblioteket.

De beregnede verdiene rapporteres via en tilbakeringingsmetode fra brukeren. De er også lagret i den interne pin_data datastrukturen. Den siste verdien som ble rapportert kan tilbakekalles ved å avstemme pin_data ved hjelp av dht_read -metoden.

Konfigurere en ny DHT -enhet

Når du legger til en ny DHT -enhet, kalles metoden set_pin_mode_dht. Denne metoden oppdaterer pin_data for digitale pins. Den oppretter og sender også en DHT_CONFIG SysEx -melding til FirmataExpress.

Trinn 5: Innpakning

Som vi har sett, krever å legge til Firmata-støtte for en ny enhet at du endrer Arduino FirmataExpress-serverkoden og den Python-baserte pymata4-klientkoden. FirmataExpress -kode kan være utfordrende å feilsøke. En metode kalt printData ble lagt til FirmataExpress for å hjelpe til med feilsøking. Denne metoden lar deg sende dataverdier fra FirmataExpress og skrive dem ut på pymata4 -konsollen.

Denne funksjonen krever både en peker til en tegnstreng og verdien du ønsker å se. Hvis dataverdien er inneholdt i en variabel som heter argc, kan du ringe printData med følgende parametere.

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

Hvis du har spørsmål, er det bare å legge igjen en kommentar, så svarer jeg gjerne.

God koding!

Anbefalt: