Оглавление:

Выходя за рамки StandardFirmata - еще раз: 5 шагов
Выходя за рамки StandardFirmata - еще раз: 5 шагов

Видео: Выходя за рамки StandardFirmata - еще раз: 5 шагов

Видео: Выходя за рамки StandardFirmata - еще раз: 5 шагов
Видео: ВЕРШИНА МИРА и ГОРНОЕ БЕЗУМИЕ 2024, Июль
Anonim
Выходя за рамки StandardFirmata - еще раз
Выходя за рамки StandardFirmata - еще раз

Некоторое время назад со мной связался доктор Мартин Уиллер, пользователь pymata4, за советом по добавлению поддержки датчика влажности / температуры DHT22 в библиотеку pymata4. Библиотека pymata4 в сочетании со своим аналогом для Arduino, FirmataExpress, позволяет пользователям удаленно контролировать и контролировать свои устройства Arduino. В течение нескольких раундов обмена электронными письмами доктор Уиллер успешно модифицировал как pymata4, так и FirmataExpress. В результате поддержка датчиков DHT22 и DHT11 теперь является стандартной частью pymata4 и FirmataExpress.

В мае 2014 года я написал статью о добавлении в Firmata поддержки дополнительных устройств. Размышляя над этой статьей, я понял, как много изменилось с тех пор, как я перешел на бумагу для этой статьи. В дополнение к этой статье доктор Уиллер задокументировал свои усилия, и вы можете также это проверить.

FirmataExpress основан на StandardFirmata, и структура каталогов StandardFirmata претерпела изменения. Кроме того, pymata4 API также немного отличается от оригинального PyMata API 2014 года. Я подумал, что сейчас самое время вернуться к этой статье и обновить ее. Взяв за основу работу доктора Уиллера, давайте рассмотрим, как расширить функциональность pymata4 / FirmataExpress.

Прежде чем мы начнем - некоторая справочная информация об Arduino / Firmata

Так что же такое Firmata? Цитата с веб-страницы Firmata: «Firmata - это общий протокол для связи с микроконтроллерами из программного обеспечения на главном компьютере».

Arduino Firmata использует последовательный интерфейс для передачи команд и отчетов между микроконтроллером Arduino и ПК, обычно с использованием последовательного / USB-канала, установленного на 57600 бит / с. Данные, передаваемые по этой ссылке, являются двоичными, а протокол реализован в модели клиент / сервер.

Сторона сервера загружается в микроконтроллер Arduino в виде скетча Arduino. Скетч StandardFirmata, включенный в IDE Arduino, управляет выводами ввода-вывода Arduino по команде клиента. Он также сообщает клиенту об изменениях входных контактов и другой отчетной информации. FirmataExpress - это расширенная версия StandardFirmata. Он работает со скоростью последовательного канала 115200 бит / с.

В этой статье используется клиент Arduino pymata4. Это приложение Python, которое выполняется на ПК. Он как отправляет команды, так и получает отчеты от сервера Arduino. Поскольку pymata4 реализован на Python, он работает на компьютерах Windows, Linux (включая Raspberry Pi) и macOS.

Зачем использовать Firmata?

Микроконтроллеры Arduino - замечательные маленькие устройства, но ресурсы процессора и памяти несколько ограничены. Для приложений, интенсивно использующих процессор или память, часто нет другого выбора, кроме как переложить потребность в ресурсах на ПК, чтобы приложение было успешным.

Но это не единственная причина использования StandardFirmata. При разработке более легких приложений Arduino ПК может предоставлять инструменты и возможности отладки, которые напрямую не доступны на микроконтроллере Arduino. Использование «фиксированного» клиента и сервера помогает ограничить сложность приложения ПК, которым легче управлять. Как только приложение будет усовершенствовано, его можно будет преобразовать в индивидуальный автономный скетч Arduino.

Зачем использовать pymata4?

Я, как его автор, конечно, пристрастен. При этом это единственный клиент Firmata на основе Python, который постоянно поддерживается в течение последних нескольких лет. Он предоставляет интуитивно понятный и простой в использовании API. Помимо скетчей на основе StandardFirmata, он поддерживает Firmata через WiFi для таких устройств, как ESP-8266, при использовании скетча StandardFirmataWifI.

Кроме того, pymata4 был разработан так, чтобы пользователь мог легко расширить его для поддержки дополнительных датчиков и исполнительных механизмов, которые в настоящее время не поддерживаются StandardFirmata.

Шаг 1: понимание протокола Firmata

Понимание протокола Firmata
Понимание протокола Firmata

Протокол связи Arduino Firmata является производным от протокола MIDI, который использует один или несколько 7-битных байтов для представления данных.

Фирмы были разработаны с возможностью расширения пользователем. Механизмом, обеспечивающим эту расширяемость, является протокол обмена сообщениями System Exclusive (SysEx).

Формат сообщения SysEx, определенный протоколом Firmata Protocol, показан на иллюстрации выше. Он начинается с байта START_SYSEX с фиксированным шестнадцатеричным значением 0xF0, за которым следует уникальный командный байт SysEx. Значение байта команды должно быть в диапазоне шестнадцатеричных 0x00-0x7F. Затем за байтом команды следует неопределенное количество 7-битных байтов данных. Наконец, сообщение заканчивается байтом END_SYSEX с фиксированным шестнадцатеричным значением 0xF7.

Кодирование / декодирование данных фирмы

Поскольку часть пользовательских данных сообщения SysEx состоит из серии 7-битных байтов, вы можете задаться вопросом, как они представляют значение больше 128 (0x7f)? Firmata кодирует эти значения, разбирая их на несколько 7-битных байтовых блоков, прежде чем данные будут маршалированы по каналу передачи данных. Младший байт (LSB) элемента данных отправляется первым, за ним по соглашению следуют все более значимые компоненты элемента данных. Старший байт (MSB) элемента данных - это последний отправленный элемент данных.

Как это работает?

Допустим, мы хотим включить значение 525 в часть данных сообщения SysEx. Поскольку значение 525 явно больше значения 128, нам необходимо разделить или разобрать его на 7-битные байтовые «куски».

Вот как это делается.

Десятичное значение 525 эквивалентно шестнадцатеричному значению 0x20D, 2-байтовому значению. Чтобы получить младший бит, мы маскируем значение, связывая его с 0x7F. Реализации как C, так и Python показаны ниже:

// реализация "C" для выделения младшего разряда

int max_distance_LSB = max_distance & 0x7f; // маскируем младший байт # реализация Python для изоляции LSB max_distance_LSB = max_distance & 0x7F # маскируем младший байт

После маскирования max_distance_LSB будет содержать 0x0d. 0x20D и 0x7F = 0x0D.

Затем нам нужно изолировать MSB для этого 2-байтового значения. Для этого сдвинем значение 0x20D вправо на 7 позиций.

// реализация "C" для выделения MSB 2-байтового значения

int max_distance_MSB = max_distance >> 7; // сдвигаем старший байт # реализация Python для выделения MSB из 2 байтов max_distance_MSB = max_distance >> 7 # сдвиг для получения старшего байта После сдвига max_distance_MSB будет содержать значение 0x04.

Когда "разбитые" на части маршалированные данные получены, их необходимо повторно собрать в одно значение. Вот как данные собираются заново как в "C", так и в Python.

// реализация "C" для повторной сборки 2 байтов, // 7-битные значения в одно значение int max_distance = argv [0] + (argv [1] << 7); # Реализация Python для повторной сборки 2-байтовых # 7-битных значений в одно значение max_distance = data [0] + (data [1] << 7)

После повторной сборки значение снова равно 525 в десятичной системе счисления или в шестнадцатеричной системе счисления 0x20D.

Этот процесс разборки / повторной сборки может выполняться клиентом или сервером.

Шаг 2. Приступим

Для поддержки нового устройства требуется внести изменения как в резидентный сервер Arduino, так и в резидентный клиент Python на ПК. Работа доктора Уиллера будет использована для иллюстрации необходимых изменений.

Возможно, наиболее важным шагом является решение, хотите ли вы интегрировать существующую библиотеку поддерживающих устройств в часть уравнения Arduino или написать свою собственную. Если вы можете найти существующую библиотеку, рекомендуется использовать ее гораздо проще, чем писать свою собственную с нуля.

Для поддержки устройств DHT доктор Уиллер основал свой код расширения на библиотеке DHTNew. Очень умно доктор Уиллер разделил функциональность библиотеки DHTNew на части уравнения Arduino и pymata4, чтобы обеспечить минимальную блокировку на стороне Arduino.

Если мы посмотрим на DHTNew, он выполняет все следующие действия:

  • Устанавливает выбранный режим вывода цифрового вывода.
  • Синхронизирует закодированный сигнал для получения последних значений влажности и температуры.
  • Проверяет и сообщает о любых ошибках.
  • Вычисляет удобочитаемые значения температуры и влажности на основе полученных необработанных данных.

Чтобы обеспечить максимальную эффективность работы на стороне FirmataExpress, доктор Уиллер перенес подпрограммы преобразования данных с Arduino на pymata4.

Шаг 3. Изменение FirmataExpress для поддержки DHT

Дерево каталогов FirmataExpress

Ниже представлены все файлы, входящие в репозиторий FirmataExpress. Это дерево идентично дереву StandardFiramata, только некоторые имена файлов отражают имя репозитория.

К файлам, требующим изменения, относятся те, которые отмечены звездочкой (*) рядом с ними.

ФирмаЭкспресс

├── * Boards.h

├── примеры

│ └── FirmataExpress

│ ├── доска

│ ├── * FirmataExpress.ino

│ ├── LICENSE.txt

│ └── Makefile

├── * FirmataConstants.h

├── * FirmataDefines.h

├── FirmataExpress.cpp

├── FirmataExpress.h

├── FirmataMarshaller.cpp

├── FirmataMarshaller.h

├── FirmataParser.cpp

└── FirmataParser.h

Давайте посмотрим на каждый из файлов и внесенные изменения.

Boards.h

Этот файл содержит определения макросов типа контактов для каждого из поддерживаемых типов плат. Он определяет максимальное количество поддерживаемых устройств, когда необходимо поддерживать более одного устройства.

Для устройства DHT одновременно может быть подключено до 6 устройств, и это значение определяется как:

#ifndef MAX_DHTS

#define MAX_DHTS 6 #endif

Кроме того, макросы контактного типа могут быть дополнительно определены для нового устройства либо для всех типов плат, либо только для тех, которые вас интересуют. Эти макросы используются в основном для целей отчетности и не используются для управления устройствами. Эти макросы определяют оба контакта, которые поддерживают устройство:

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

А также макрос для определения преобразования номера вывода.

#define PIN_TO_DHT (p) PIN_TO_DIGITAL (p)

FirmataConstants.h

Этот файл содержит номер версии прошивки, которую вы можете изменить, чтобы отслеживать, какую версию вы загрузили на свой Arduino. Он также содержит значения сообщений Firmata, включая сообщения Firmata SysEx.

В этом файле вам нужно будет назначить новое сообщение или набор сообщений для вашего устройства. Для DHT было добавлено два сообщения. Один настраивает контакт как контакт «DHT», а другой - как сообщение репортера при отправке последних данных DHT обратно клиенту.

статическая константа int DHT_CONFIG = 0x64;

статическая константа int DHT_DATA = 0x65;

В этом файле также указаны режимы вывода. Для DHT был создан новый режим вывода:

статическая константа int PIN_MODE_DHT = 0x0F; // вывод настроен для DHT

При добавлении нового режима вывода необходимо настроить TOTAL_PIN_MODES:

статическая константа int TOTAL_PIN_MODES = 17;

FirmataDefines.h

Этот файл необходимо обновить, чтобы отразить новые сообщения, добавленные в FirmataConstants.h:

#ifdef DHT_CONFIG # undef DHT_CONFIG #endif #define DHT_CONFIG firmata:: DHT_CONFIG // DHT-запрос #ifdef DHT_DATA #undef DHT_DATA #endif #define DHT_DATA firmata_ DHT_DATA_HTDE # PIN_DIFDATA_INDIFDATA_INDIFDATA_INDIFDATA_INDIFDATA_PIN_DATA_PIN_DATA_PIN_DATA_PIN_DATA_INDEFDATA:: PIN_MODE_DHT

FirmataExpress.ino

В этом обсуждении мы рассмотрим «основные моменты» изменений, внесенных в этот скетч Arduino.

Чтобы FirmataExpress мог поддерживать до шести устройств DHT одновременно, было создано 3 массива для отслеживания каждого из связанных номеров контактов устройства, его значения WakeUpDelay и типа устройства, то есть DHT22 или DHT11:

// Датчики DHT

int numActiveDHTs = 0; // количество подключенных DHT uint8_t DHT_PinNumbers [MAX_DHTS]; uint8_t DHT_WakeUpDelay [MAX_DHTS]; uint8_t DHT_TYPE [MAX_DHTS];

Поскольку для обоих типов устройств требуется примерно 2 секунды между чтениями, нам нужно убедиться, что мы читаем каждый DHT только один раз за 2-секундный временной интервал. Некоторые устройства, такие как устройства DHT и датчики расстояния HC-SR04, доступны только периодически. Это дает им время для взаимодействия со своим окружением.

uint8_t nextDHT = 0; // индексируем в dht для чтения следующего устройства

uint8_t currentDHT = 0; // Отслеживает, какой датчик активен. int dhtNumLoops = 0; // Целевое количество обращений к DHT через цикл b4 int dhtLoopCounter = 0; // Счетчик циклов

Настройка и чтение устройства DHT

Когда FirmataExpress получает команду SysEx для настройки вывода для работы DHT, он проверяет, не превышено ли максимальное количество устройств DHT. Если новый DHT может поддерживаться, массивы DHT обновляются. Если тип DHT неизвестен, создается строковое сообщение SysEx, которое передается обратно в pymata4.

case DHT_CONFIG: int DHT_Pin = argv [0]; int DHT_type = argv [1]; если (numActiveDHTs <MAX_DHTS) {если (DHT_type == 22) {DHT_WakeUpDelay [numActiveDHTs] = 1; } иначе, если (DHT_type == 11) {DHT_WakeUpDelay [numActiveDHTs] = 18; } else {Firmata.sendString ("ОШИБКА: НЕИЗВЕСТНЫЙ ТИП ДАТЧИКА, ДЕЙСТВУЮЩИЕ ДАТЧИКИ 11, 22"); перерыв; } // тестируем датчик DHT_PinNumbers [numActiveDHTs] = DHT_Pin; DHT_TYPE [numActiveDHTs] = DHT_type; setPinModeCallback (DHT_Pin, PIN_MODE_DHT);

Затем FirmataExpress пытается связаться с устройством DHT. Если есть какие-либо ошибки, он формирует сообщение SysEx с данными об ошибке и отправляет сообщение SysEx обратно в pymat4. Переменная _bits содержит данные, возвращаемые устройством DHT, для дополнительной обработки pymata4, если это необходимо.

Firmata.write (START_SYSEX);

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

Если возвращаются действительные данные, количество активных DHT увеличивается. Также корректируется переменная, которая отслеживает, сколько итераций цикла нужно завершить перед проверкой следующего DHT на предмет данных. Эта переменная гарантирует, что независимо от того, сколько DHT добавлено в систему, все они будут прочитаны в течение 2-секундного периода.

int rv = readDhtSensor (numActiveDHTs);

если (rv == DHTLIB_OK) {numActiveDHTs ++; dhtNumLoops = dhtNumLoops / numActiveDHTs; // все хорошо }

Если одно или несколько устройств DHT были настроены в функции цикла эскиза, то считывается следующее устройство DHT. В pymata4 возвращаются действительные данные или статус ошибки в виде сообщения SysEx:

если (dhtLoopCounter ++> dhtNumLoops) {если (numActiveDHTs) {int rv = readDhtSensor (nextDHT); uint8_t current_pin = DHT_PinNumbers [nextDHT]; uint8_t current_type = DHT_TYPE [nextDHT]; dhtLoopCounter = 0; currentDHT = nextDHT; если (nextDHT ++> = numActiveDHTs - 1) {nextDHT = 0; } if (rv == DHTLIB_OK) {// КОНТРОЛЬНАЯ СУММА ТЕСТА uint8_t sum = _bits [0] + _bits [1] + _bits [2] + _bits [3]; если (_bits [4]! = сумма) {rv = -1; }} // отправляем сообщение обратно со статусом ошибки Firmata.write (START_SYSEX); Firmata.write (DHT_DATA); Firmata.write (текущий_контакт); Firmata.write (текущий_тип); 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);}}

Код, используемый для связи с устройством DHT, получен непосредственно из библиотеки DHTNew:

int readDhtSensor (int index) {

// ЗАПУСК БУФЕРА ДЛЯ ПОЛУЧЕНИЯ ДАННЫХ uint8_t mask = 128; uint8_t idx = 0; // ПУСТОЙ БУФЕР // memset (_bits, 0, sizeof (_bits)); for (uint8_t i = 0; i 5 БАЙТОВ 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) // следующий байт? {Mask = 128; idx ++;}} return DHTLIB_OK;}

Шаг 4: изменение Pymata4 для поддержки DHT

private_constants.h

Для поддержки DHT нам нужно добавить в этот файл сообщения нового типа и SysEx:

# режимы вывода INPUT = 0x00 # вывод установлен как ввод OUTPUT = 0x01 # вывод установлен как вывод ANALOG = 0x02 # аналоговый вывод в аналоговом режиме ввода PWM = 0x03 # цифровой вывод в режиме вывода PWM SERVO = 0x04 # цифровой вывод в режиме вывода сервопривода I2C = 0x06 # вывод, включенный в настройку I2C STEPPER = 0x08 # любой вывод в пошаговом режиме SERIAL = 0x0a PULLUP = 0x0b # Любой вывод в режиме подтяжки SONAR = 0x0c # Любой вывод в режиме SONAR TONE = 0x0d # Любой вывод в тональном режиме PIXY = 0x0e # зарезервировано для режима камеры pixy DHT = 0x0f # Датчик DHT IGNORE = 0x7f # Сообщения команды DHT SysEx DHT_CONFIG = 0x64 # Команда конфигурации dht DHT_DATA = 0x65 # Ответ датчика dht

Добавленный тип вывода и команды SysEx должны соответствовать значениям в FirmataConstants.h, добавленном в FirmataExpress.

pymata4.py

Pymata4 использует словарь Python, чтобы быстро связать входящее сообщение Firmata с обработчиком сообщений. Имя этого словаря - report_dispatch.

Формат словарной статьи:

{MessageID: [message_handler, количество байтов данных для обработки]}

В словарь была добавлена запись для обработки входящих сообщений DHT:

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

7 байтов данных в сообщении - это номер цифрового вывода Arduino, тип устройства DHT (22 или 11) и 5 байтов необработанных данных.

Метод _dht_read_response проверяет сообщения об ошибках. Если ошибок нет, влажность и температура рассчитываются с использованием алгоритма, перенесенного из библиотеки Arduino DHTNew.

Вычисленные значения сообщаются с помощью метода обратного вызова, предоставляемого пользователем. Они также хранятся во внутренней структуре данных pin_data. Последнее сообщенное значение может быть вызвано опросом pin_data с использованием метода dht_read.

Настройка нового устройства DHT

При добавлении нового устройства DHT вызывается метод set_pin_mode_dht. Этот метод обновляет pin_data для цифровых контактов. Он также создает и отправляет сообщение DHT_CONFIG SysEx в FirmataExpress.

Шаг 5: Заключение

Как мы видели, добавление поддержки Firmata для нового устройства требует изменения кода сервера Arduino FirmataExpress и клиентского кода pymata4 на основе Python. Код FirmataExpress может быть сложным для отладки. Для помощи в отладке в FirmataExpress был добавлен метод printData. Этот метод позволяет отправлять значения данных из FirmataExpress и распечатывать их на консоли pymata4.

Для этой функции требуется указатель на символьную строку и значение, которое вы хотите просмотреть. Если значение данных содержится в переменной с именем argc, вы можете вызвать printData со следующими параметрами.

printData ((char *) «argc =», argc);

Если у вас есть вопросы, оставьте комментарий, и я с радостью отвечу.

Удачного кодирования!

Рекомендуемые: