Картинка: Mitch, r/3Dprinting
Так как я уже некоторое время являюсь владельцем 3D-принтера, меня всё чаще стала посещать интересная мысль: а ведь было бы очень полезно поставить систему на печать и удалённо её мониторить. Уверен, что эта идея терзала многих. Давайте порассуждаем, как этот вопрос можно было бы решить.
Тут следует сделать небольшое отступление и сказать вот что:
Это, как говорится, «была преамбула, а теперь начинается амбула».
Так как большинство принтеров соединяется с компьютером через USB, то мне видится достаточно разумным шагом использовать именно этот канал связи для создания универсальной системы мониторинга телеметрии принтера. Этот способ также хорош тем, что он не привязан к особенностям устройства принтера. USB, похоже, есть почти у всех, если не у всех.
Для начала постараемся дать полное определение самой задачи: необходимо мониторить телеметрию принтера удалённо, желательно не находясь с принтером даже в одной квартире (например, как часто бывает у меня — пошёл бегать рядом с домом в небольшом парке, а принтер оставил на печать. Да, «Риск — моё второе имя!», но, тем не менее — было бы интересно мониторить в процессе бега, что же там происходит).
Таким образом, понятно, что необходимо некое устройство, которое будет общаться с принтером и являться для него ведущим, так называемым USB-хостом. Он, в свою очередь, будет посылать на принтер соответствующие команды, на которые принтер будет отвечать и посылать в ответ телеметрию.
Теоретически, если «совсем-пресовсем» заморочиться, то можно изменить саму прошивку принтера таким образом, чтобы она выполняла, в том числе и функции USB-хоста, то есть ведущего устройства, а мы бы подключались в качестве ведомого. Однако я посчитал, что это задача будет чересчур замороченной, и решил её пока отложить.
Почему я так много говорю о USB-хосте и USB-клиенте? Всё это определено спецификациями USB-протокола, в рамках которого между собой общаются только ведущее и ведомые устройства. Таким образом, мы будем видоизменять подключённое к 3D-принтеру устройство, которое превратится в USB-хост, а принтер мы трогать не будем.
Процесс погружения в эту тему привёл меня к пониманию следующих вещей. Если мы используем Arduino USB Host Shield и будем строить своё устройство на базе платы Arduino — можно реализовать аппаратный USB-хост:
Картинка: docs.arduino.cc
Это аппаратное устройство позволяет превратить Arduino в USB-хост и подключать к нему любые HID-устройства (джойстики, мыши, клавиатуры) и много чего ещё — внешние накопители и т. д.
Всё это, конечно, очень интересно, но было бы гораздо лучше, если бы оно было в рамках того же ТРИЗа — «чтобы само устройство отсутствовало, а его функция — выполнялась».
И я стал искать некий программный USB-хост. Как выяснилось, подобного добра совсем негусто. Например, имеется USB-хост для Arduino Due, предоставляющий следующий API для общения с устройствами:
General
MouseController
Keyboard Controller
Где, например, Task() — это функция опроса подключённых устройств, по поводу их статуса:
Так как Arduino Due — не слишком широко распространённая вещь (по сравнению с той же самой Uno, на основе которой построено много чего), то нельзя назвать это решение удачным выбором.
И тут я наткнулся на одну замечательную вещь, которая была разработана Дмитрием Самсоновым — чистый софтовый USB-хост, работающий через стандартные GPIO-выходы esp32 и поддерживающий до 4х устройств одновременно.
На базе этой библиотеки и уже другим разработчикам была создана библиотека-надстройка, с использованием операционной системы реального времени freeRTOS, демонстрационный пример которой выводит характеристики подключённого устройства:
В принципе, это уже достаточно интересно, так как использование esp32 позволяет в полной мере реализовать удалённый мониторинг, не находясь непосредственно рядом с принтером.
Но что же сама компания Espressif — неужели у неё нет никакого решения для этого вопроса? Есть.
Полноценный API USB-хоста расположен здесь.
Однако, библиотека, предоставляемая компанией, даёт возможности не только использовать относительно высокоуровневые функции API, но и спускаться на более низкие уровни, если того требуют ресурсы/задержки.
Характеристики библиотеки приведены на картинке ниже.
Картинка: docs.espressif.com
Единственный минус этого решения заключается в том, что это API среды разработки ESP-IDF (Espressif IoT Development Framework). Например, я привык работать в Arduino IDE, и поэтому мне было неудобно, но вам, может, и «зайдёт» :).
А плюс, безусловно, в том, что всё очень хорошо документировано и собрано в одном месте.
То есть, вам придётся установить фирменную среду разработки от Espressif и работать в ней, и тогда вам станут доступны все функции её API. Но есть и лайфхак — эта среда в качестве модуля может быть встроена и в стандартную Arduino IDE! Как именно — написано тут.
Теперь, когда нам более-менее понятно, каким образом в этом процессе USB-обмена сделать нашу подключаемую плату esp32 главной, нам, собственно, необходимо каким-то образом отдавать команды принтеру, чтобы он возвращал нам свою телеметрию.
Поначалу я даже хотел приспособить некое своё решение, но вовремя вспомнил, что в комплекте с моим принтером, который прошит прошивкой Marlin, шла стандартная программа для калибровки печатного стола, и через эту программу можно было отдавать текстовые команды в виде g-код команд (парковка головки и т.д.), то есть прошивка уже поддерживает отправку отчётов при поступлении запроса.
Так как прошивка Marlin является достаточно распространённой, итоговые решения будут интересными для очень широкого круга людей.
Я начал копать в направлении стандартных команд этой прошивки и нашёл те, что могут представлять интерес. Они расположены вот здесь.
Отправку команд я протестировал через стандартный монитор порта Arduino IDE, настроив его следующим образом:
Например, можно запросить отчёт о текущей температуре:
Или отправить команду, которая позволит получать отчёт о текущем статусе печати с флешки, например, каждые 4 секунды:
ОК, с этим всё понятно — отправляя подобные команды на принтер, в ответ мы получаем отчёт в текстовом виде, из которого нам следует только спарсить необходимые нам числа.
К слову, команды отправляются в ASCII-формате и поэтому, если требуется отправить команду G28 («парковка головки»), в коде Arduino IDE это будет выглядеть как-то так (шлём коды из ASCII-таблицы + байт перевода строки LF (10) (почитать про него можно тут)):
Однако, возможно, потребуется учесть и ещё один нюанс — необходимость соединения USB-хоста и USB клиента с использованием OTG кабеля. Вполне вероятно, этот пункт и не понадобится, но знать о нём следует.
Подобный кабель в принципе можно и купить, он не является редкостью, однако вполне может быть изготовлен и самостоятельно.
Для этого всего лишь необходимо соединить на стороне мини USB разъёма четвёртый и пятый контакты, как рассказано здесь.
Картинка: pikabu.ru
Ну вот, допустим, отчёт уже имеется у нас на руках, и мы спарсили из него все необходимые значения.
После этого у нас останется нерешённым только последний вопрос — каким образом информировать человека о состоянии печати?
Для этого просто запрашивается отправка этих значений на MQTT-брокер, с которого эти значения впоследствии будут прочитаны приложением на смартфоне.
В качестве кода для отправки сообщений на MQTT-брокер, можно использовать следующий код из примера по ссылке. Там же подробно рассказано (и показано), что такое MQTT брокер.
В качестве примера приложения, которое мониторит соответствующий топик/топики брокера, я обычно пользуюсь MQTT Dash, хотя подойдёт и любое аналогичное.
Таким образом, на выходе должна получиться достаточно интересная вещь: плата esp32 с небольшим USB кабелем, который может подключаться к абсолютно любому 3D-принтеру и мониторить состояние его печати удалённо.
На самом деле, как вы могли видеть по ссылке выше, этих команд, которые могут отправляться на принтер — достаточно много, поэтому работа с принтером не ограничивается только мониторингом его состояния. Можно вполне попытаться реализовать и полноценное удалённое управление. Мне не кажется это излишним, а скорее даже, наоборот это необходимый элемент, если уж решили браться за реализацию всего этого.
Вот примерно такие мысли у меня по этому поводу. Надеюсь, кому-то будет интересно продолжить мои исследования и дописать код общения с принтером.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.
Так как я уже некоторое время являюсь владельцем 3D-принтера, меня всё чаще стала посещать интересная мысль: а ведь было бы очень полезно поставить систему на печать и удалённо её мониторить. Уверен, что эта идея терзала многих. Давайте порассуждаем, как этот вопрос можно было бы решить.
Тут следует сделать небольшое отступление и сказать вот что:
- Мой 3d-принтер (AnycubicKossell Linear Plus) обладает встроенным портом UART, который позволяет много чего и сразу, но это же не так интересно! Гораздо интереснее было бы разработать некое универсальное решение, не привязанное к конкретному принтеру и его аппаратным особенностям.
- Базируясь на собранном материале и проведённых экспериментах — создать своё решение вполне возможно. Остаётся только написать непосредственно сам код, который будет общаться с принтером. Однако, это удовольствие я решил оставить для вас. Напрягаться одному мне неохота :) К тому же — задача достаточно интересна сама по себе, что позволит вам прочувствовать сопричастность к классному проекту.
Это, как говорится, «была преамбула, а теперь начинается амбула».
Так как большинство принтеров соединяется с компьютером через USB, то мне видится достаточно разумным шагом использовать именно этот канал связи для создания универсальной системы мониторинга телеметрии принтера. Этот способ также хорош тем, что он не привязан к особенностям устройства принтера. USB, похоже, есть почти у всех, если не у всех.
Для начала постараемся дать полное определение самой задачи: необходимо мониторить телеметрию принтера удалённо, желательно не находясь с принтером даже в одной квартире (например, как часто бывает у меня — пошёл бегать рядом с домом в небольшом парке, а принтер оставил на печать. Да, «Риск — моё второе имя!», но, тем не менее — было бы интересно мониторить в процессе бега, что же там происходит).
Таким образом, понятно, что необходимо некое устройство, которое будет общаться с принтером и являться для него ведущим, так называемым USB-хостом. Он, в свою очередь, будет посылать на принтер соответствующие команды, на которые принтер будет отвечать и посылать в ответ телеметрию.
Теоретически, если «совсем-пресовсем» заморочиться, то можно изменить саму прошивку принтера таким образом, чтобы она выполняла, в том числе и функции USB-хоста, то есть ведущего устройства, а мы бы подключались в качестве ведомого. Однако я посчитал, что это задача будет чересчур замороченной, и решил её пока отложить.
Почему я так много говорю о USB-хосте и USB-клиенте? Всё это определено спецификациями USB-протокола, в рамках которого между собой общаются только ведущее и ведомые устройства. Таким образом, мы будем видоизменять подключённое к 3D-принтеру устройство, которое превратится в USB-хост, а принтер мы трогать не будем.
Процесс погружения в эту тему привёл меня к пониманию следующих вещей. Если мы используем Arduino USB Host Shield и будем строить своё устройство на базе платы Arduino — можно реализовать аппаратный USB-хост:
Картинка: docs.arduino.cc
Это аппаратное устройство позволяет превратить Arduino в USB-хост и подключать к нему любые HID-устройства (джойстики, мыши, клавиатуры) и много чего ещё — внешние накопители и т. д.
Всё это, конечно, очень интересно, но было бы гораздо лучше, если бы оно было в рамках того же ТРИЗа — «чтобы само устройство отсутствовало, а его функция — выполнялась».
И я стал искать некий программный USB-хост. Как выяснилось, подобного добра совсем негусто. Например, имеется USB-хост для Arduino Due, предоставляющий следующий API для общения с устройствами:
General
- Task()
MouseController
- mouseMoved()
- mouseDragged()
- mousePressed()
- mouseReleased()
- getXChange()
- getYChange()
- getButton()
Keyboard Controller
- KeyboardController
- keyPressed()
- keyReleased()
- getModifiers()
- getKey()
- getOemKey()
Где, например, Task() — это функция опроса подключённых устройств, по поводу их статуса:
#include <MouseController.h>
// Initialize USB Controller
USBHost usb;
// Attach mouse controller to USB
MouseController mouse(usb);
void setup(){
Serial.begin(9600);
}
void loop(){
usb.Task();
}
Так как Arduino Due — не слишком широко распространённая вещь (по сравнению с той же самой Uno, на основе которой построено много чего), то нельзя назвать это решение удачным выбором.
И тут я наткнулся на одну замечательную вещь, которая была разработана Дмитрием Самсоновым — чистый софтовый USB-хост, работающий через стандартные GPIO-выходы esp32 и поддерживающий до 4х устройств одновременно.
На базе этой библиотеки и уже другим разработчикам была создана библиотека-надстройка, с использованием операционной системы реального времени freeRTOS, демонстрационный пример которой выводит характеристики подключённого устройства:
Код примера
static void my_USB_DetectCB( uint8_t usbNum, void * dev )
{
sDevDesc *device = (sDevDesc*)dev;
printf("New device detected on USB#%d\n", usbNum);
printf("desc.bcdUSB = 0x%04x\n", device->bcdUSB);
printf("desc.bDeviceClass = 0x%02x\n", device->bDeviceClass);
printf("desc.bDeviceSubClass = 0x%02x\n", device->bDeviceSubClass);
printf("desc.bDeviceProtocol = 0x%02x\n", device->bDeviceProtocol);
printf("desc.bMaxPacketSize0 = 0x%02x\n", device->bMaxPacketSize0);
printf("desc.idVendor = 0x%04x\n", device->idVendor);
printf("desc.idProduct = 0x%04x\n", device->idProduct);
printf("desc.bcdDevice = 0x%04x\n", device->bcdDevice);
printf("desc.iManufacturer = 0x%02x\n", device->iManufacturer);
printf("desc.iProduct = 0x%02x\n", device->iProduct);
printf("desc.iSerialNumber = 0x%02x\n", device->iSerialNumber);
printf("desc.bNumConfigurations = 0x%02x\n", device->bNumConfigurations);
// if( device->iProduct == mySupportedIdProduct && device->iManufacturer == mySupportedManufacturer ) {
// myListenUSBPort = usbNum;
// }
}
static void my_USB_PrintCB(uint8_t usbNum, uint8_t byte_depth, uint8_t* data, uint8_t data_len)
{
// if( myListenUSBPort != usbNum ) return;
printf("in: ");
for(int k=0;k<data_len;k++) {
printf("0x%02x ", data[k] );
}
printf("\n");
}
usb_pins_config_t USB_Pins_Config =
{
DP_P0, DM_P0,
DP_P1, DM_P1,
DP_P2, DM_P2,
DP_P3, DM_P3
};
void setup()
{
Serial.begin(115200);
delay(200);
Serial.printf("USB Soft Host Test for %s\n", PROFILE_NAME );
delay(1000);
USH.init( USB_Pins_Config, my_USB_DetectCB, my_USB_PrintCB );
}
void loop()
{
vTaskDelete(NULL);
}
В принципе, это уже достаточно интересно, так как использование esp32 позволяет в полной мере реализовать удалённый мониторинг, не находясь непосредственно рядом с принтером.
Но что же сама компания Espressif — неужели у неё нет никакого решения для этого вопроса? Есть.
Полноценный API USB-хоста расположен здесь.
Однако, библиотека, предоставляемая компанией, даёт возможности не только использовать относительно высокоуровневые функции API, но и спускаться на более низкие уровни, если того требуют ресурсы/задержки.
Характеристики библиотеки приведены на картинке ниже.
Картинка: docs.espressif.com
Единственный минус этого решения заключается в том, что это API среды разработки ESP-IDF (Espressif IoT Development Framework). Например, я привык работать в Arduino IDE, и поэтому мне было неудобно, но вам, может, и «зайдёт» :).
А плюс, безусловно, в том, что всё очень хорошо документировано и собрано в одном месте.
То есть, вам придётся установить фирменную среду разработки от Espressif и работать в ней, и тогда вам станут доступны все функции её API. Но есть и лайфхак — эта среда в качестве модуля может быть встроена и в стандартную Arduino IDE! Как именно — написано тут.
Отправка команд на принтер
Теперь, когда нам более-менее понятно, каким образом в этом процессе USB-обмена сделать нашу подключаемую плату esp32 главной, нам, собственно, необходимо каким-то образом отдавать команды принтеру, чтобы он возвращал нам свою телеметрию.
Поначалу я даже хотел приспособить некое своё решение, но вовремя вспомнил, что в комплекте с моим принтером, который прошит прошивкой Marlin, шла стандартная программа для калибровки печатного стола, и через эту программу можно было отдавать текстовые команды в виде g-код команд (парковка головки и т.д.), то есть прошивка уже поддерживает отправку отчётов при поступлении запроса.
Так как прошивка Marlin является достаточно распространённой, итоговые решения будут интересными для очень широкого круга людей.
Я начал копать в направлении стандартных команд этой прошивки и нашёл те, что могут представлять интерес. Они расположены вот здесь.
Отправку команд я протестировал через стандартный монитор порта Arduino IDE, настроив его следующим образом:
Например, можно запросить отчёт о текущей температуре:
Или отправить команду, которая позволит получать отчёт о текущем статусе печати с флешки, например, каждые 4 секунды:
ОК, с этим всё понятно — отправляя подобные команды на принтер, в ответ мы получаем отчёт в текстовом виде, из которого нам следует только спарсить необходимые нам числа.
К слову, команды отправляются в ASCII-формате и поэтому, если требуется отправить команду G28 («парковка головки»), в коде Arduino IDE это будет выглядеть как-то так (шлём коды из ASCII-таблицы + байт перевода строки LF (10) (почитать про него можно тут)):
Serial.write (71);
Serial.write (50);
Serial.write (56);
Serial.write (10);
Однако, возможно, потребуется учесть и ещё один нюанс — необходимость соединения USB-хоста и USB клиента с использованием OTG кабеля. Вполне вероятно, этот пункт и не понадобится, но знать о нём следует.
Подобный кабель в принципе можно и купить, он не является редкостью, однако вполне может быть изготовлен и самостоятельно.
Для этого всего лишь необходимо соединить на стороне мини USB разъёма четвёртый и пятый контакты, как рассказано здесь.
Картинка: pikabu.ru
Ну вот, допустим, отчёт уже имеется у нас на руках, и мы спарсили из него все необходимые значения.
После этого у нас останется нерешённым только последний вопрос — каким образом информировать человека о состоянии печати?
Для этого просто запрашивается отправка этих значений на MQTT-брокер, с которого эти значения впоследствии будут прочитаны приложением на смартфоне.
В качестве кода для отправки сообщений на MQTT-брокер, можно использовать следующий код из примера по ссылке. Там же подробно рассказано (и показано), что такое MQTT брокер.
В качестве примера приложения, которое мониторит соответствующий топик/топики брокера, я обычно пользуюсь MQTT Dash, хотя подойдёт и любое аналогичное.
Таким образом, на выходе должна получиться достаточно интересная вещь: плата esp32 с небольшим USB кабелем, который может подключаться к абсолютно любому 3D-принтеру и мониторить состояние его печати удалённо.
На самом деле, как вы могли видеть по ссылке выше, этих команд, которые могут отправляться на принтер — достаточно много, поэтому работа с принтером не ограничивается только мониторингом его состояния. Можно вполне попытаться реализовать и полноценное удалённое управление. Мне не кажется это излишним, а скорее даже, наоборот это необходимый элемент, если уж решили браться за реализацию всего этого.
Вот примерно такие мысли у меня по этому поводу. Надеюсь, кому-то будет интересно продолжить мои исследования и дописать код общения с принтером.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.