Tabla de contenido:

Yendo más allá de StandardFirmata - Revisada: 5 pasos
Yendo más allá de StandardFirmata - Revisada: 5 pasos

Video: Yendo más allá de StandardFirmata - Revisada: 5 pasos

Video: Yendo más allá de StandardFirmata - Revisada: 5 pasos
Video: 64-0719E | Yendo Más Allá Del Campamento | William Marrion Branham 2024, Mes de julio
Anonim
Yendo más allá de lo estándarFirmata - Revisitado
Yendo más allá de lo estándarFirmata - Revisitado

Hace poco, el Dr. Martyn Wheeler, un usuario de pymata4, me contactó para recibir orientación sobre cómo agregar soporte para el sensor de humedad / temperatura DHT22 a la biblioteca pymata4. La biblioteca pymata4, junto con su contraparte Arduino, FirmataExpress, permite a los usuarios controlar y monitorear sus dispositivos Arduino de forma remota. En unas pocas rondas de intercambios de correo electrónico, el Dr. Wheeler logró modificar tanto pymata4 como FirmataExpress. Como resultado, la compatibilidad con los sensores DHT22 y DHT11 ahora es una parte estándar de pymata4 y FirmataExpress.

En mayo de 2014, escribí un artículo sobre cómo agregar soporte a Firmata para dispositivos adicionales. Reflexionando sobre ese artículo, me di cuenta de cuánto ha cambiado desde que tomé el lápiz y el papel para ese artículo. Además de este artículo, el Dr. Wheeler documentó sus esfuerzos y es posible que desee comprobarlo también.

FirmataExpress se basa en StandardFirmata y la estructura de directorios de StandardFirmata ha evolucionado. Además, la API de pymata4 también es bastante diferente de la API de PyMata original de 2014. Pensé que este sería el momento perfecto para volver a visitar y actualizar ese artículo. Usando el trabajo del Dr. Wheeler como base, exploremos cómo extender la funcionalidad pymata4 / FirmataExpress.

Antes de comenzar: información básica sobre Arduino / Firmata

Entonces, ¿qué es Firmata? Citando de la página web de Firmata, "Firmata es un protocolo genérico para comunicarse con microcontroladores desde un software en una computadora host".

Arduino Firmata utiliza una interfaz en serie para transportar tanto la información de comando como la información de informe entre un microcontrolador Arduino y una PC, normalmente utilizando un enlace serie / USB configurado en 57600 bps. Los datos transferidos a través de este enlace son binarios y el protocolo se implementa en un modelo cliente / servidor.

El lado del servidor se carga en un microcontrolador Arduino en forma de boceto Arduino. El boceto StandardFirmata, incluido con el IDE de Arduino, controla los pines de E / S de Arduino, según lo ordena el cliente. También informa al cliente sobre los cambios en los pines de entrada y otra información de informe. FirmataExpress es una versión extendida de StandardFirmata. Funciona a una velocidad de enlace en serie de 115200 bps.

El cliente Arduino utilizado para este artículo es pymata4. Es una aplicación de Python que se ejecuta en una PC. Envía comandos y recibe informes del servidor Arduino. Debido a que pymata4 está implementado en Python, se ejecuta en computadoras Windows, Linux (incluida Raspberry Pi) y macOS.

¿Por qué utilizar Firmata?

Los microcontroladores Arduino son pequeños dispositivos maravillosos, pero los recursos del procesador y la memoria son algo limitados. Para las aplicaciones que requieren un uso intensivo del procesador o la memoria, a menudo no hay más remedio que descargar la demanda de recursos en una PC para que la aplicación tenga éxito.

Pero esa no es la única razón para usar StandardFirmata. Al desarrollar aplicaciones Arduino más ligeras, una PC puede proporcionar herramientas y capacidades de depuración que no están disponibles directamente en un microcontrolador Arduino. El uso de un cliente y un servidor "fijos" ayuda a limitar la complejidad de la aplicación a una PC, que se administra más fácilmente. Una vez que se perfecciona la aplicación, se puede traducir a un boceto Arduino personalizado e independiente.

¿Por qué utilizar pymata4?

Siendo su autor, por supuesto, soy parcial. Dicho esto, es el único cliente Firmata basado en Python que se ha mantenido continuamente durante los últimos años. Proporciona una API intuitiva y fácil de usar. Además de los bocetos basados en StandardFirmata, admite Firmata a través de WiFi para dispositivos como el ESP-8266 cuando se usa el boceto StandardFirmataWifI.

Además, pymata4 fue diseñado para ser extendido fácilmente por un usuario para admitir sensores y actuadores adicionales que actualmente no son compatibles con StandardFirmata.

Paso 1: Comprensión del Protocolo Firmata

Entendiendo el Protocolo Firmata
Entendiendo el Protocolo Firmata

El protocolo de comunicaciones Arduino Firmata se deriva del protocolo MIDI, que utiliza uno o más bytes de 7 bits para representar datos.

Firmata fue diseñado para ser extensible por el usuario. El mecanismo que proporciona esta extensibilidad es el protocolo de mensajería System Exclusive (SysEx).

El formato de un mensaje SysEx, según lo define el Protocolo Firmata, se muestra en la ilustración anterior. Comienza con un byte START_SYSEX con un valor fijo de 0xF0 hexadecimal, y es seguido por un byte de comando SysEx único. El valor del byte de comando debe estar en el rango hexadecimal 0x00-0x7F. El byte de comando va seguido de un número no especificado de bytes de datos de 7 bits. Finalmente, el mensaje termina con un byte END_SYSEX, con un valor fijo de 0xF7 hexadecimal.

Codificación / decodificación de datos Firmata

Dado que la porción de datos de usuario de un mensaje SysEx consta de una serie de bytes de 7 bits, puede preguntarse cómo se representa un valor mayor que 128 (0x7f). Firmata codifica esos valores desensamblándolos en múltiples fragmentos de bytes de 7 bits antes de que los datos se clasifiquen a través del enlace de datos. El byte menos significativo (LSB) de un elemento de datos se envía primero, seguido de los componentes cada vez más significativos del elemento de datos por convención. El byte más significativo (MSB) del elemento de datos es el último elemento de datos enviado.

¿Como funciona esto?

Digamos que deseamos incorporar un valor 525 en la porción de datos de un mensaje SysEx. Dado que un valor de 525 es claramente mayor que un valor de 128, debemos dividirlo o desensamblarlo en "fragmentos" de bytes de 7 bits.

Así es como se hace.

El valor de 525 en decimal es equivalente al valor hexadecimal de 0x20D, un valor de 2 bytes. Para obtener el LSB, enmascaramos el valor haciendo un AND con 0x7F. Las implementaciones de "C" y Python se muestran a continuación:

// Implementación "C" para aislar LSB

int distancia_máxima_LSB = distancia_máxima & 0x7f; // enmascarar el byte inferior # Implementación de Python para aislar LSB max_distance_LSB = max_distance & 0x7F # enmascarar el byte inferior

Después del enmascaramiento, max_distance_LSB contendrá 0x0d. 0x20D y 0x7F = 0x0D.

A continuación, necesitamos aislar el MSB para este valor de 2 bytes. Para hacer esto, desplazaremos el valor de 0x20D a la derecha, 7 lugares.

// Implementación "C" para aislar MSB de valor de 2 bytes

int distancia_máxima_MSB = distancia_máxima >> 7; // cambia el byte de orden superior # implementación de Python a isoloate MSB de valor de 2 bytes max_distance_MSB = max_distance >> 7 # cambia para obtener el byte superior Después de cambiar, max_distance_MSB contendrá un valor de 0x04.

Cuando se reciben los datos calculados "fragmentados", es necesario volver a ensamblarlos en un solo valor. Así es como se vuelven a ensamblar los datos tanto en "C" como en Python

// Implementación "C" para reensamblar los 2 bytes, // Valores de 7 bits en un solo valor int max_distance = argv [0] + (argv [1] << 7); # Implementación de Python para reensamblar los valores de 2 bytes y # 7 bits en un solo valor max_distance = data [0] + (data [1] << 7)

Después del reensamblaje, el valor vuelve a ser igual a 525 decimal o 0x20D hexadecimal.

Este proceso de desmontaje / montaje puede ser realizado por el cliente o el servidor.

Paso 2: comencemos

La compatibilidad con un nuevo dispositivo requiere cambios tanto en el servidor residente de Arduino como en el cliente Python residente de la PC. El trabajo del Dr. Wheeler se utilizará para ilustrar las modificaciones necesarias.

Quizás el paso más importante es decidir si desea integrar una biblioteca de dispositivos de soporte existente en el lado de Arduino de la ecuación o escribir la suya propia. Se recomienda que, si puede encontrar una biblioteca existente, sea mucho más sencillo usarla que escribir la suya propia desde cero.

Para compatibilidad con dispositivos DHT, el Dr. Wheeler basó su código de extensión en la biblioteca DHTNew. Muy hábilmente, Dr. Wheeler dividió la funcionalidad de la biblioteca DHTNew en los lados Arduino y pymata4 de la ecuación para proporcionar un bloqueo mínimo en el lado Arduino.

Si miramos DHTNew, realiza todo lo siguiente:

  • Establece el modo de salida digital del pin seleccionado.
  • Registra una señal codificada para recuperar los últimos valores de humedad y temperatura.
  • Comprueba e informa cualquier error.
  • Calcula valores de temperatura y humedad legibles por humanos a partir de los datos sin procesar recuperados.

Para mantener las cosas lo más eficientes posible en el lado de FirmataExpress, Dr. Wheeler descargó las rutinas de conversión de datos del Arduino a pymata4.

Paso 3: Modificación de FirmataExpress para soporte DHT

El árbol de directorios de FirmataExpress

A continuación se muestran todos los archivos que componen el repositorio de FirmataExpress. Este árbol es idéntico al de StandardFiramata, solo que algunos de los nombres de archivo reflejan el nombre del repositorio.

Los archivos que necesitan modificación son los que tienen un asterisco (*) junto a ellos.

FirmataExpress

├── * Tableross.h

├── ejemplos

│ └── FirmataExpress

│ ├── tablerox

│ ├── * FirmataExpress.ino

│ ├── LICENCIA.txt

│ └── Makefile

├── * FirmataConstants.h

├── * FirmataDefines.h

├── FirmataExpress.cpp

├── FirmataExpress.h

├── FirmataMarshaller.cpp

├── FirmataMarshaller.h

├── FirmataParser.cpp

└── FirmataParser.h

Veamos cada uno de los archivos y los cambios que se realizaron.

Boards.h

Este archivo contiene definiciones de macros de tipo pin para cada uno de los tipos de placa admitidos. Define el número máximo de dispositivos admitidos cuando es necesario admitir más de un dispositivo.

Para el dispositivo DHT, se pueden conectar hasta 6 dispositivos a la vez y este valor se define como:

#ifndef MAX_DHTS

#define MAX_DHTS 6 #endif

Además, las macros de tipo pin pueden definirse opcionalmente para el nuevo dispositivo, ya sea para todos los tipos de placas o solo para las que le interesen. Estas macros se utilizan principalmente con fines de generación de informes y no para controlar los dispositivos. Estas macros definen los dos pines que soportan el dispositivo:

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

Así como una macro para definir una conversión de número pin.

#define PIN_TO_DHT (p) PIN_TO_DIGITAL (p)

FirmataConstants.h

Este archivo contiene el número de versión del firmware, que quizás desee modificar para realizar un seguimiento de la versión que ha cargado en su Arduino. También contiene los valores de los mensajes Firmata, incluidos los mensajes Firmata SysEx.

Deberá asignar un mensaje nuevo o un conjunto de mensajes para su dispositivo en este archivo. Para el DHT, se agregaron dos mensajes. Uno configura un pin como un pin "DHT", y el otro, como un mensaje de reportero, al enviar los últimos datos DHT al cliente.

estática const int DHT_CONFIG = 0x64;

estática const int DHT_DATA = 0x65;

Los modos de pin también se especifican en este archivo. Para el DHT, se creó un nuevo modo pin:

estática const int PIN_MODE_DHT = 0x0F; // pin configurado para DHT

Al agregar un nuevo modo de pin, se deben ajustar TOTAL_PIN_MODES:

estática constante int TOTAL_PIN_MODES = 17;

FirmataDefines.h

Este archivo debe actualizarse para reflejar los nuevos mensajes agregados a FirmataConstants.h:

#ifdef DHT_CONFIG # undef DHT_CONFIG #endif #define DHT_CONFIG firmata:: DHT_CONFIG // Solicitud DHT #ifdef DHT_DATA #undef DHT_DATA #endif #define DHT_DATA firmata:: DHT_DATA // DHT_TODMETE #ifdef:: PIN_MODE_DHT

FirmataExpress.ino

En esta discusión, cubriremos los "puntos altos" de los cambios realizados en este boceto de Arduino.

Para que FirmataExpress admita hasta seis dispositivos DHT simultáneamente, se crearon 3 matrices para realizar un seguimiento de cada número de pin asociado del dispositivo, su valor WakeUpDelay y el tipo de dispositivo, es decir, DHT22 o DHT11:

// Sensores DHT

int numActiveDHTs = 0; // número de DHT adjuntos uint8_t DHT_PinNumbers [MAX_DHTS]; uint8_t DHT_WakeUpDelay [MAX_DHTS]; uint8_t DHT_TYPE [MAX_DHTS];

Debido a que ambos tipos de dispositivos requieren aproximadamente 2 segundos entre lecturas, debemos asegurarnos de leer cada DHT solo una vez en el período de tiempo de 2 segundos. Algunos dispositivos, como los dispositivos DHT y los sensores de distancia HC-SR04, solo se acceden periódicamente. Esto les da tiempo para interactuar con sus entornos.

uint8_t nextDHT = 0; // indexar en dht para leer el siguiente dispositivo

uint8_t currentDHT = 0; // Realiza un seguimiento de qué sensor está activo. int dhtNumLoops = 0; // Número objetivo de veces a través del bucle b4 accediendo a un DHT int dhtLoopCounter = 0; // Contador de bucles

Configuración y lectura del dispositivo DHT

Cuando FirmataExpress recibe un comando SysEx para configurar un pin para la operación DHT, verifica que no se haya superado el número máximo de dispositivos DHT. Si se puede admitir el nuevo DHT, las matrices de DHT se actualizan. Si se desconoce el tipo de DHT, se crea un mensaje de cadena SysEx y se transmite 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; } más si (DHT_type == 11) {DHT_WakeUpDelay [numActiveDHTs] = 18; } else {Firmata.sendString ("ERROR: TIPO DE SENSOR DESCONOCIDO, LOS SENSORES VÁLIDOS SON 11, 22"); rotura; } // prueba el sensor DHT_PinNumbers [numActiveDHTs] = DHT_Pin; DHT_TYPE [numActiveDHTs] = DHT_type; setPinModeCallback (DHT_Pin, PIN_MODE_DHT);

FirmataExpress luego intenta comunicarse con el dispositivo DHT. Si hay algún error, forma un mensaje SysEx con los datos del error y envía el mensaje SysEx a pymat4. La variable _bits contiene los datos devueltos por el dispositivo DHT para procesamiento adicional por pymata4 si se desea.

Firmata.write (START_SYSEX);

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

Si se devuelven datos válidos, se incrementa el número de DHT activos. También se ajusta una variable que realiza un seguimiento de cuántas iteraciones de bucle se deben completar antes de verificar los datos del siguiente DHT. Esta variable asegura que no importa cuántos DHT se agreguen al sistema, todos se leerán en un período de 2 segundos.

int rv = readDhtSensor (numActiveDHTs);

if (rv == DHTLIB_OK) {numActiveDHTs ++; dhtNumLoops = dhtNumLoops / numActiveDHTs; // todo bien }

Si se han configurado uno o más dispositivos DHT en la función de bucle del esquema, se lee el siguiente dispositivo DHT. Los datos válidos o su estado de error se devuelven a pymata4 en forma de mensaje 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; 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]; si (_bits [4]! = suma) {rv = -1; }} // devuelve el mensaje con un estado de error Firmata.write (START_SYSEX); Firmata.write (DHT_DATA); Firmata.write (actual_pin); Firmata.write (tipo_actual); para (uint8_t i = 0; i <tamaño de (_bits) - 1; ++ i) {Firmata.write (_bits ); // Firmata.write (_bits ;} Firmata.write (abs (rv)); Firmata.write (0); Firmata.write (END_SYSEX);}}

El código utilizado para comunicarse con el dispositivo DHT se deriva directamente de la biblioteca DHTNew:

int readDhtSensor (int índice) {

// INICIAR BUFFERVAR PARA RECIBIR DATOS uint8_t mask = 128; uint8_t idx = 0; // BÚFER VACÍO // memset (_bits, 0, sizeof (_bits)); para (uint8_t i = 0; i 5 BYTES para (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] | = máscara;} máscara >> = 1; if (máscara == 0) // siguiente byte? {Máscara = 128; idx ++;}} return DHTLIB_OK;}

Paso 4: Modificación de Pymata4 para compatibilidad con DHT

private_constants.h

Para admitir el DHT, debemos agregar tanto el nuevo tipo de pin como los mensajes SysEx a este archivo:

# modos de pin INPUT = 0x00 # pin configurado como entrada OUTPUT = 0x01 # pin configurado como salida ANALOG = 0x02 # pin analógico en modo de entrada analógica PWM = 0x03 # pin digital en modo de salida PWM SERVO = 0x04 # pin digital en modo de salida Servo I2C = 0x06 # pin incluido en la configuración I2C STEPPER = 0x08 # cualquier pin en modo paso a paso SERIAL = 0x0a PULLUP = 0x0b # Cualquier pin en modo pullup SONAR = 0x0c # Cualquier pin en modo SONAR TONE = 0x0d # Cualquier pin en modo tono PIXY = 0x0e # reservado para el modo de cámara pixy DHT = 0x0f # sensor DHT IGNORE = 0x7f # mensajes de comando DHT SysEx DHT_CONFIG = 0x64 # comando dht config DHT_DATA = 0x65 # respuesta del sensor dht

El tipo de pin agregado y los comandos SysEx deben coincidir con los valores en FirmataConstants.h agregados a FirmataExpress.

pymata4.py

Pymata4 usa un diccionario de Python para asociar rápidamente un mensaje entrante de Firmata con un controlador de mensajes. El nombre de este diccionario es report_dispatch.

El formato para una entrada de diccionario es:

{MessageID: [message_handler, número de bytes de datos que se procesarán]}

Se agregó una entrada al diccionario para manejar los mensajes DHT entrantes:

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

Los 7 bytes de datos en el mensaje son el número de pin digital de Arduino, el tipo de dispositivo DHT (22 u 11) y los 5 bytes de datos sin procesar.

El método _dht_read_response comprueba los errores informados. Si no se informan errores, la humedad y la temperatura se calculan utilizando el algoritmo transferido desde la biblioteca Arduino DHTNew.

Los valores calculados se informan mediante un método de devolución de llamada proporcionado por el usuario. También se almacenan en la estructura de datos interna pin_data. El último valor informado puede recuperarse sondeando pin_data utilizando el método dht_read.

Configuración de un nuevo dispositivo DHT

Al agregar un nuevo dispositivo DHT, se llama al método set_pin_mode_dht. Este método actualiza pin_data para pines digitales. También crea y envía un mensaje DHT_CONFIG SysEx a FirmataExpress.

Paso 5: Conclusión

Como hemos visto, agregar soporte Firmata para un nuevo dispositivo requiere que modifique el código del servidor Arduino FirmataExpress y el código del cliente pymata4 basado en Python. El código FirmataExpress puede ser difícil de depurar. Se agregó un método llamado printData a FirmataExpress para ayudar en la depuración. Este método le permite enviar valores de datos desde FirmataExpress y los imprimirá en la consola de pymata4.

Esta función requiere tanto un puntero a una cadena de caracteres como el valor que desea ver. Si el valor de los datos está contenido en una variable llamada argc, puede llamar a printData con los siguientes parámetros.

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

Si tiene alguna pregunta, deje un comentario y con gusto le responderé.

¡Feliz codificación!

Recomendado: