Inhoudsopgave:

Verder gaan dan StandardFirmata - Revisited - Ajarnpa
Verder gaan dan StandardFirmata - Revisited - Ajarnpa

Video: Verder gaan dan StandardFirmata - Revisited - Ajarnpa

Video: Verder gaan dan StandardFirmata - Revisited - Ajarnpa
Video: Установка отлива на цоколь дома | БЫСТРО и ЛЕГКО 2024, Juli-
Anonim
Verder gaan dan standaardFirmata - Revisited
Verder gaan dan standaardFirmata - Revisited

Een tijdje geleden werd ik benaderd door Dr. Martyn Wheeler, een pymata4-gebruiker, voor advies bij het toevoegen van ondersteuning voor de DHT22-vochtigheids-/temperatuursensor aan de pymata4-bibliotheek. De pymata4-bibliotheek, in combinatie met zijn Arduino-tegenhanger, FirmataExpress, stelt gebruikers in staat om hun Arduino-apparaten op afstand te besturen en te bewaken. Binnen een paar rondes van e-mailuitwisselingen was Dr. Wheeler erin geslaagd om zowel pymata4 als FirmataExpress aan te passen. Als gevolg hiervan is ondersteuning voor de DHT22- en DHT11-sensoren nu een standaard onderdeel van pymata4 en FirmataExpress.

In mei 2014 schreef ik een artikel over het toevoegen van ondersteuning aan Firmata voor extra apparaten. Toen ik nadacht over dat artikel, realiseerde ik me hoeveel er is veranderd sinds ik de pen op papier zette voor dat artikel. Naast dit artikel heeft Dr. Wheeler zijn inspanningen gedocumenteerd, en misschien wilt u dat ook eens bekijken.

FirmataExpress is gebaseerd op StandardFirmata en de directorystructuur van StandardFirmata is geëvolueerd. Bovendien is de pymata4 API ook heel wat anders dan de originele PyMata API van 2014. Ik dacht dat dit het perfecte moment zou zijn om dat artikel opnieuw te bekijken en bij te werken. Laten we, met het werk van Dr. Wheeler als basis, onderzoeken hoe we de functionaliteit van pymata4/FirmataExpress kunnen uitbreiden.

Voordat we beginnen - wat achtergrondinformatie over Arduino/Firmata

Dus wat is Firmata? Citaat van de Firmata-webpagina: "Firmata is een generiek protocol voor communicatie met microcontrollers vanuit software op een hostcomputer."

Arduino Firmata gebruikt een seriële interface om zowel commando- als rapportinformatie tussen een Arduino-microcontroller en een pc te transporteren, meestal met behulp van een seriële/USB-link ingesteld op 57600 bps. De gegevens die via deze link worden overgedragen, zijn binair en het protocol is geïmplementeerd in een client/server-model.

De serverkant wordt geüpload naar een Arduino-microcontroller in de vorm van een Arduino-schets. De StandardFirmata-schets, meegeleverd met de Arduino IDE, bestuurt de Arduino I/O-pinnen, zoals opgedragen door de client. Het rapporteert ook wijzigingen in de invoerpin en andere rapportinformatie aan de klant. FirmataExpress is een uitgebreide versie van StandardFirmata. Het draait op een seriële verbindingssnelheid van 115200 bps.

De Arduino-client die voor dit artikel wordt gebruikt, is pymata4. Het is een Python-toepassing die op een pc wordt uitgevoerd. Het verzendt zowel opdrachten naar als ontvangt rapporten van de Arduino-server. Omdat pymata4 in Python is geïmplementeerd, werkt het op Windows-, Linux- (inclusief Raspberry Pi) en macOS-computers.

Waarom Firmata gebruiken?

Arduino-microcontrollers zijn prachtige kleine apparaten, maar de processor- en geheugenbronnen zijn enigszins beperkt. Voor applicaties die veel processor- of geheugenintensief zijn, is er vaak weinig andere keuze dan de vraag naar bronnen over te hevelen naar een pc om de applicatie succesvol te laten zijn.

Maar dat is niet de enige reden om StandardFirmata te gebruiken. Bij het ontwikkelen van lichtere Arduino-applicaties kan een pc tools en foutopsporingsmogelijkheden bieden die niet direct beschikbaar zijn op een Arduino-microcontroller. Het gebruik van een "vaste" client en server helpt de complexiteit van de applicatie te beperken tot een pc, die gemakkelijker te beheren is. Zodra de applicatie is geperfectioneerd, kan deze worden vertaald in een aangepaste, zelfstandige Arduino-schets.

Waarom pymata4 gebruiken?

Als auteur ben ik natuurlijk bevooroordeeld. Dat gezegd hebbende, het is de enige op Python gebaseerde Firmata-client die de afgelopen jaren continu is onderhouden. Het biedt een intuïtieve en gebruiksvriendelijke API. Naast op StandardFirmata gebaseerde schetsen, ondersteunt het Firmata via WiFi voor apparaten zoals de ESP-8266 bij gebruik van de StandardFirmataWifI-schets.

pymata4 is ook ontworpen om eenvoudig door een gebruiker te kunnen worden uitgebreid om extra sensoren en actuatoren te ondersteunen die momenteel niet worden ondersteund door StandardFirmata.

Stap 1: Het Firmata-protocol begrijpen

Het Firmata-protocol begrijpen
Het Firmata-protocol begrijpen

Het Arduino Firmata-communicatieprotocol is afgeleid van het MIDI-protocol, dat een of meer 7-bits bytes gebruikt om gegevens weer te geven.

Firmata is ontworpen om door de gebruiker uit te breiden. Het mechanisme dat deze uitbreidbaarheid biedt, is het System Exclusive (SysEx) messaging-protocol.

Het formaat van een SysEx-bericht, zoals gedefinieerd door het Firmata-protocol, wordt weergegeven in de bovenstaande afbeelding. Het begint met een START_SYSEX-byte met een vaste waarde van hexadecimaal 0xF0 en wordt gevolgd door een unieke SysEx-opdrachtbyte. De waarde van de opdrachtbyte moet in het bereik van hexadecimaal 0x00-0x7F liggen. De opdrachtbyte wordt dan gevolgd door een niet-gespecificeerd aantal 7-bits databytes. Ten slotte wordt het bericht beëindigd met een END_SYSEX-byte, met een vaste waarde van hexadecimaal 0xF7.

Firmata-gegevenscodering/decodering

Aangezien het gebruikersgegevensgedeelte van een SysEx-bericht bestaat uit een reeks van 7-bits bytes, vraagt u zich misschien af hoe men een waarde groter dan 128 (0x7f) voorstelt? Firmata codeert die waarden door ze uit elkaar te halen in meerdere 7-bits bytes voordat de gegevens over de datalink worden gerangeerd. De minst significante byte (LSB) van een data-item wordt eerst verzonden, gevolgd door in toenemende mate significante componenten van het data-item volgens afspraak. De meest significante byte (MSB) van het data-item is het laatst verzonden data-item.

Hoe werkt dit?

Laten we zeggen dat we een waarde 525 willen opnemen in het gegevensgedeelte van een SysEx-bericht. Aangezien een waarde van 525 duidelijk groter is dan een waarde van 128, moeten we deze splitsen of demonteren in 7-bits byte "brokken".

Hier is hoe dat wordt gedaan.

De waarde van 525 in decimalen is gelijk aan de hexadecimale waarde van 0x20D, een waarde van 2 bytes. Om de LSB te krijgen, maskeren we de waarde door deze te AND'en met 0x7F. Zowel de "C"- als de Python-implementaties worden hieronder weergegeven:

// "C" implementatie om LSB. te isoleren

int max_distance_LSB = max_distance & 0x7f; // maskeer de lagere byte # Python-implementatie om LSB te isoleren max_distance_LSB = max_distance & 0x7F # maskeer de lagere byte

Na het maskeren zal max_distance_LSB 0x0d bevatten. 0x20D & 0x7F = 0x0D.

Vervolgens moeten we de MSB isoleren voor deze 2-byte-waarde. Om dit te doen, verschuiven we de waarde van 0x20D naar rechts, 7 plaatsen.

// "C" implementatie om MSB van 2 byte waarde te isoleren

int max_distance_MSB = max_distance >> 7; // verschuif de byte van hoge orde # Python-implementatie om MSB van 2 byte-waarde te isoleren max_distance_MSB = max_distance >> 7 # shift om de bovenste byte te krijgen Na het verschuiven bevat max_distance_MSB een waarde van 0x04.

Wanneer de "chunkified" gemarshalde gegevens worden ontvangen, moeten deze opnieuw worden samengevoegd tot een enkele waarde. Hier is hoe de gegevens opnieuw worden samengesteld in zowel "C" als Python

// "C" implementatie om de 2 byte weer in elkaar te zetten, // 7 bit-waarden in een enkele waarde int max_distance = argv[0] + (argv[1] << 7); # Python-implementatie om de 2-byte, # 7 bit-waarden opnieuw samen te stellen in een enkele waarde max_distance = data[0] + (data[1] << 7)

Na hermontage is de waarde weer gelijk aan 525 decimaal of 0x20D hexadecimaal.

Dit proces van demontage/hermontage kan worden uitgevoerd door de client of de server.

Stap 2: Laten we beginnen

Het ondersteunen van een nieuw apparaat vereist wijzigingen in zowel de Arduino-residente server als de pc-residente Python-client. Het werk van Dr. Wheeler zal worden gebruikt om de noodzakelijke aanpassingen te illustreren.

Misschien wel de belangrijkste stap is om te beslissen of je een bestaande bibliotheek met ondersteunende apparaten in de Arduino-kant van de vergelijking wilt integreren of je eigen bibliotheek wilt schrijven. Het wordt aanbevolen dat als u een bestaande bibliotheek kunt vinden, het veel eenvoudiger is om deze te gebruiken dan uw eigen bibliotheek helemaal opnieuw te schrijven.

Voor ondersteuning van DHT-apparaten baseerde Dr. Wheeler zijn extensiecode op de DHTNew-bibliotheek. Heel slim verdeelde Dr. Wheeler de functionaliteit van de DHTNew-bibliotheek over de Arduino- en pymata4-kanten van de vergelijking om minimale blokkering aan de Arduino-kant te bieden.

Als we naar DHTNew kijken, voert het al het volgende uit:

  • Stelt de geselecteerde pin digitale uitgangsmodus in.
  • Klokt een gecodeerd signaal uit om de laatste vochtigheids- en temperatuurwaarden op te halen.
  • Controleert en rapporteert eventuele fouten.
  • Berekent door mensen leesbare temperatuur- en vochtigheidswaarden uit de opgehaalde onbewerkte gegevens.

Om de zaken zo efficiënt mogelijk te houden aan de kant van FirmataExpress, heeft Dr. Wheeler de gegevensconversieroutines van de Arduino naar pymata4 verplaatst.

Stap 3: FirmataExpress aanpassen voor DHT-ondersteuning

De FirmataExpress-directorystructuur

Hieronder staan alle bestanden die deel uitmaken van de FirmataExpress-repository. Deze boomstructuur is identiek aan die van StandardFiramata, alleen dat sommige bestandsnamen de naam van de repository weerspiegelen.

De bestanden die moeten worden gewijzigd, zijn de bestanden met een asterisk (*) ernaast.

FirmataExpress

├── * Boards.h

├── voorbeelden

└── FirmataExpress

├── bordx

├── * FirmataExpress.ino

│ ├── LICENSE.txt

│ └── Makefile

├── * FirmataConstants.h

├── * FirmataDefines.h

├── FirmataExpress.cpp

├── FirmataExpress.h

├── FirmataMarshaller.cpp

├── FirmataMarshaller.h

├── FirmataParser.cpp

└── FirmataParser.h

Laten we eens kijken naar elk van de bestanden en de wijzigingen die zijn aangebracht.

Boards.h

Dit bestand bevat pin-type macrodefinities voor elk van de ondersteunde bordtypes. Het definieert het maximale aantal apparaten dat wordt ondersteund wanneer meer dan één apparaat moet worden ondersteund.

Voor het DHT-apparaat kunnen maximaal 6 apparaten tegelijk worden aangesloten en deze waarde wordt gedefinieerd als:

#ifndef MAX_DHTS

#define MAX_DHTS 6 #endif

Ook kunnen pin-type macro's optioneel worden gedefinieerd voor het nieuwe apparaat, ofwel voor alle bordtypes of alleen degene die voor u van belang zijn. Deze macro's worden meestal gebruikt voor rapportagedoeleinden en worden niet gebruikt voor het aansturen van de apparaten. Deze macro's definiëren beide pinnen die het apparaat ondersteunen:

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

Evenals een macro om een pin-nummer conversie te definiëren.

#define PIN_TO_DHT(p) PIN_TO_DIGITAL(p)

FirmataConstants.h

Dit bestand bevat het firmwareversienummer, dat u mogelijk wilt wijzigen om bij te houden welke versie u op uw Arduino hebt geladen. Het bevat ook de Firmata-berichtwaarden, inclusief de Firmata SysEx-berichten.

U moet in dit bestand een nieuw bericht of een reeks berichten voor uw apparaat toewijzen. Voor de DHT zijn twee berichten toegevoegd. De ene configureert een pin als een "DHT" -pin en de andere, als een reporterbericht, bij het terugsturen van de nieuwste DHT-gegevens naar de client.

statische const int DHT_CONFIG = 0x64;

statische const int DHT_DATA = 0x65;

In dit bestand worden ook pin-modi gespecificeerd. Voor de DHT is een nieuwe pin-modus gemaakt:

statische const int PIN_MODE_DHT = 0x0F; // pin geconfigureerd voor DHT

Bij het toevoegen van een nieuwe pin-modus moet de TOTAL_PIN_MODES worden aangepast:

statische const int TOTAL_PIN_MODES = 17;

FirmataDefines.h

Dit bestand moet worden bijgewerkt om de nieuwe berichten weer te geven die zijn toegevoegd aan FirmataConstants.h:

#ifdef DHT_CONFIG#undef DHT_CONFIG #endif #define DHT_CONFIG firmata::DHT_CONFIG // DHT-verzoek #ifdef DHT_DATA #undef DHT_DATA #endif #define DHT_DATA firmata::DHT_DATA // DHT-antwoord #ifdef PIN_MODE_MODE::PIN_MODE_DHT

FirmataExpress.ino

In deze discussie bespreken we de "hoogtepunten" van de wijzigingen die in deze Arduino-schets zijn aangebracht.

Om ervoor te zorgen dat FirmataExpress tot zes DHT-apparaten tegelijk kan ondersteunen, zijn er 3 arrays gemaakt om de bijbehorende pincode van elk apparaat, de WakeUpDelay-waarde en het apparaattype, dat wil zeggen DHT22 of DHT11, bij te houden:

// DHT-sensoren

int numActiveDHTs = 0; // aantal bijgevoegde DHT's uint8_t DHT_PinNumbers[MAX_DHTS]; uint8_t DHT_WakeUpDelay[MAX_DHTS]; uint8_t DHT_TYPE[MAX_DHTS];

Omdat beide apparaattypen ongeveer 2 seconden nodig hebben tussen het lezen, moeten we ervoor zorgen dat we elke DHT slechts één keer in het tijdsbestek van 2 seconden lezen. Sommige apparaten, zoals de DHT-apparaten en HC-SR04-afstandssensoren, worden alleen periodiek gebruikt. Dit geeft hen de tijd om te communiceren met hun omgeving.

uint8_t nextDHT = 0; // index in dht voor het volgende apparaat dat moet worden gelezen

uint8_t huidigeDHT = 0; // Houdt bij welke sensor actief is. int dhtNumLoops = 0; // Doel aantal keren via lus b4 toegang tot een DHT int dhtLoopCounter = 0; // Lusteller

Het DHT-apparaat configureren en uitlezen

Wanneer FirmataExpress een SysEx-opdracht ontvangt om een pin voor DHT-werking te configureren, wordt gecontroleerd of het maximale aantal DHT-apparaten niet is overschreden. Als de nieuwe DHT kan worden ondersteund, worden de DHT-arrays bijgewerkt. Als het DHT-type onbekend is, wordt een SysEx-tekenreeksbericht gemaakt en teruggestuurd naar pymata

geval 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("FOUT: ONBEKEND SENSORTYPE, GELDIGE SENSOREN ZIJN 11, 22"); pauze; } // test de sensor DHT_PinNumbers [numActiveDHTs] = DHT_Pin; DHT_TYPE[numActiveDHTs] = DHT_type; setPinModeCallback (DHT_Pin, PIN_MODE_DHT);

FirmataExpress probeert vervolgens te communiceren met het DHT-apparaat. Als er fouten zijn, vormt het een SysEx-bericht met de foutgegevens en stuurt het het SysEx-bericht terug naar pymat4. De variabele _bits bevat de gegevens die door het DHT-apparaat worden geretourneerd voor aanvullende verwerking door pymata4, indien gewenst.

Firmata.write(START_SYSEX);

Firmata.write(DHT_DATA); Firmata.write(DHT_Pin); Firmata.write(DHT_type); voor (uint8_t ik = 0; ik > 7 & 0x7f); } Firmata.write(abs(rv)); Firma.schrijven(1); Firmata.write(END_SYSEX);

Als geldige gegevens worden geretourneerd, wordt het aantal actieve DHT's verhoogd. Een variabele die bijhoudt hoeveel lus-iteraties moeten worden voltooid voordat de volgende DHT op gegevens wordt gecontroleerd, wordt ook aangepast. Deze variabele zorgt ervoor dat het niet uitmaakt hoeveel DHT's er aan het systeem worden toegevoegd, ze allemaal binnen een periode van 2 seconden worden gelezen.

int rv = readDhtSensor(aantalActiveDHTs);

if (rv == DHTLIB_OK) { numActiveDHTs++; dhtNumLoops = dhtNumLoops / numActiveDHTs; // alles goed }

Als een of meer DHT-apparaten zijn geconfigureerd in de lusfunctie van de schets, wordt het volgende DHT-apparaat gelezen. De geldige gegevens of de foutstatus worden teruggestuurd naar pymata4 in de vorm van een SysEx-bericht:

if (dhtLoopCounter++ > dhtNumLoops) {if (numActiveDHTs) {int rv = readDhtSensor (nextDHT); uint8_t current_pin = DHT_PinNumbers[nextDHT]; uint8_t huidig_type = DHT_TYPE[volgendeDHT]; dhtLoopCounter = 0; huidigeDHT = volgendeDHT; 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] != som) { rv = -1; } } // stuur het bericht terug met een foutstatus Firmata.write(START_SYSEX); Firmata.write(DHT_DATA); Firmata.write(current_pin); Firmata.write (huidig_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); } }

De code die wordt gebruikt om met het DHT-apparaat te communiceren, is rechtstreeks afgeleid van de DHTNew-bibliotheek:

int readDhtSensor(int index){

// INIT BUFFERVAR OM GEGEVENS TE ONTVANGEN uint8_t mask = 128; uint8_t idx = 0; // LEGE 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) retourneer DHTLIB_ERROR_TIMEOUT; } uint32_t t = micros(); loopCnt = DHTLIB_TIMEOUT; while (digitalRead(pin) == HIGH) { if (--loopCnt == 0) retourneer DHTLIB_ERROR_TIMEOUT; } if ((micros() - t) > 40) { _bits[idx] |= mask; } mask >>= 1; if (mask == 0) // volgende byte? { mask = 128; idx++; } } return DHTLIB_OK; }

Stap 4: Pymata4 aanpassen voor DHT-ondersteuning

private_constants.h

Om de DHT te ondersteunen, moeten we zowel het nieuwe pin-type als SysEx-berichten aan dit bestand toevoegen:

# pinmodi INPUT = 0x00 # pin ingesteld als invoer OUTPUT = 0x01 # pin ingesteld als uitvoer ANALOG = 0x02 # analoge pin in analoge invoermodus PWM = 0x03 # digitale pin in PWM-uitvoermodus SERVO = 0x04 # digitale pin in servo-uitvoermodus I2C = 0x06 # pin in I2C setup STEPPER = 0x08 # elke pin in stepper-modus SERIAL = 0x0a PULLUP = 0x0b # Elke pin in pullup-modus SONAR = 0x0c # Elke pin in SONAR-modus TONE = 0x0d # Elke pin in toonmodus PIXY = 0x0e # gereserveerd voor pixy-cameramodus DHT = 0x0f # DHT-sensor IGNORE = 0x7f # DHT SysEx-opdrachtberichten DHT_CONFIG = 0x64 # dht-configuratieopdracht DHT_DATA = 0x65 # dht-sensorantwoord

Het toegevoegde pintype en de SysEx-opdrachten moeten overeenkomen met de waarden in FirmataConstants.h die aan FirmataExpress zijn toegevoegd.

pymata4.py

Pymata4 gebruikt een Python-woordenboek om snel een inkomend Firmata-bericht te koppelen aan een berichthandler. De naam van dit woordenboek is report_dispatch.

Het formaat voor een woordenboekitem is:

{MessageID: [message_handler, aantal te verwerken databytes]}

Er is een item aan het woordenboek toegevoegd om inkomende DHT-berichten te verwerken:

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

De 7 bytes aan gegevens in het bericht zijn het Arduino digitale pinnummer, het type DHT-apparaat (22 of 11) en de 5 bytes aan onbewerkte gegevens.

De methode _dht_read_response controleert op gerapporteerde fouten. Als er geen gerapporteerde fouten zijn, worden de vochtigheid en temperatuur berekend met behulp van het algoritme dat is overgedragen vanuit de Arduino DHTNew-bibliotheek.

De berekende waarden worden gerapporteerd via een door de gebruiker geleverde callback-methode. Ze worden ook opgeslagen in de interne pin_data-gegevensstructuur. De laatst gerapporteerde waarde kan worden opgeroepen door pin_data te pollen met behulp van de dht_read-methode.

Een nieuw DHT-apparaat configureren

Bij het toevoegen van een nieuw DHT-apparaat wordt de methode set_pin_mode_dht aangeroepen. Deze methode werkt de pin_data voor digitale pinnen bij. Het creëert en verzendt ook een DHT_CONFIG SysEx-bericht naar FirmataExpress.

Stap 5: Afronden

Zoals we hebben gezien, vereist het toevoegen van Firmata-ondersteuning voor een nieuw apparaat dat u de Arduino FirmataExpress-servercode en de op Python gebaseerde pymata4-clientcode wijzigt. FirmataExpress-code kan een uitdaging zijn om te debuggen. Een methode genaamd printData is toegevoegd aan FirmataExpress om te helpen bij het opsporen van fouten. Met deze methode kunt u gegevenswaarden verzenden vanuit FirmataExpress en deze afdrukken op de pymata4-console.

Deze functie vereist zowel een aanwijzer naar een tekenreeks als de waarde die u wilt bekijken. Als de gegevenswaarde is opgenomen in een variabele met de naam argc, kunt u printData aanroepen met de volgende parameters.

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

Als je vragen hebt, laat dan een reactie achter, ik zal ze graag beantwoorden.

Veel plezier met coderen!

Aanbevolen: