Картинка: Mitch, r/3Dprinting

Так как я уже некоторое время являюсь владельцем 3D-принтера, меня всё чаще стала посещать интересная мысль: а ведь было бы очень полезно поставить систему на печать и удалённо её мониторить. Уверен, что эта идея терзала многих. Давайте порассуждаем, как этот вопрос можно было бы решить.

Тут следует сделать небольшое отступление и сказать вот что:

  • Мой 3d-принтер (AnycubicKossell Linear Plus) обладает встроенным портом UART, который позволяет много чего и сразу, но это же не так интересно! Гораздо интереснее было бы разработать некое универсальное решение, не привязанное к конкретному принтеру и его аппаратным особенностям.
  • Базируясь на собранном материале и проведённых экспериментах — создать своё решение вполне возможно. Остаётся только написать непосредственно сам код, который будет общаться с принтером. Однако, это удовольствие я решил оставить для вас. Напрягаться одному мне неохота :) К тому же — задача достаточно интересна сама по себе, что позволит вам прочувствовать сопричастность к классному проекту.

Это, как говорится, «была преамбула, а теперь начинается амбула».

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

Для начала постараемся дать полное определение самой задачи: необходимо мониторить телеметрию принтера удалённо, желательно не находясь с принтером даже в одной квартире (например, как часто бывает у меня — пошёл бегать рядом с домом в небольшом парке, а принтер оставил на печать. Да, «Риск — моё второе имя!», но, тем не менее — было бы интересно мониторить в процессе бега, что же там происходит).

Таким образом, понятно, что необходимо некое устройство, которое будет общаться с принтером и являться для него ведущим, так называемым USB-хостом. Он, в свою очередь, будет посылать на принтер соответствующие команды, на которые принтер будет отвечать и посылать в ответ телеметрию.

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

Почему я так много говорю о USB-хосте и USB-клиенте? Всё это определено спецификациями USB-протокола, в рамках которого между собой общаются только ведущее и ведомые устройства. Таким образом, мы будем видоизменять подключённое к 3D-принтеру устройство, которое превратится в USB-хост, а принтер мы трогать не будем.

Процесс погружения в эту тему привёл меня к пониманию следующих вещей. Если мы используем Arduino USB Host Shield и будем строить своё устройство на базе платы Arduino — можно реализовать аппаратный USB-хост:

image
Картинка: 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 разъёма четвёртый и пятый контакты, как рассказано здесь.

image
Картинка: pikabu.ru

Ну вот, допустим, отчёт уже имеется у нас на руках, и мы спарсили из него все необходимые значения.

После этого у нас останется нерешённым только последний вопрос — каким образом информировать человека о состоянии печати?

Для этого просто запрашивается отправка этих значений на MQTT-брокер, с которого эти значения впоследствии будут прочитаны приложением на смартфоне.

В качестве кода для отправки сообщений на MQTT-брокер, можно использовать следующий код из примера по ссылке. Там же подробно рассказано (и показано), что такое MQTT брокер.

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

Таким образом, на выходе должна получиться достаточно интересная вещь: плата esp32 с небольшим USB кабелем, который может подключаться к абсолютно любому 3D-принтеру и мониторить состояние его печати удалённо.

На самом деле, как вы могли видеть по ссылке выше, этих команд, которые могут отправляться на принтер — достаточно много, поэтому работа с принтером не ограничивается только мониторингом его состояния. Можно вполне попытаться реализовать и полноценное удалённое управление. Мне не кажется это излишним, а скорее даже, наоборот это необходимый элемент, если уж решили браться за реализацию всего этого.

Вот примерно такие мысли у меня по этому поводу. Надеюсь, кому-то будет интересно продолжить мои исследования и дописать код общения с принтером.


НЛО прилетело и оставило здесь промокод для читателей нашего блога:

15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

Комментарии (9)


  1. TheRaven
    22.06.2022 11:31
    +6

    По своему опыту печати могу сказать, что принтер по USB не нужно подключать ни к чему примерно никогда. Запороть многочасовую печать из-за того, что USB вдруг переинициализировался и отправил в перезагрузку марлина легче лёгкого.

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

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


    1. bschepan
      22.06.2022 15:04
      +1

      Печатал на Picaso 3D Designer через USB шнурок с 2014 по 2018 год, ни разу печать не запорол, а на том компе я при этом и рисовал в солиде, и браузер был открыт с кучей вкладок, и чего то ещё фоном работало. Я тогда только вкатывался в мир 3д печати и вообще не знал, что надо напрямую с флешки печатать. Когда на другой работе оказался принтер без USB, первое время было крайне неудобно.


  1. joger
    22.06.2022 11:40
    +14

    мне кажется или вы изобрели https://octoprint.org/ ?


  1. Rober
    22.06.2022 12:08
    +4

    Также некоторое время являюсь владельцем 3D-принтера и не представляю, зачем видеть телеметрию дистанционно. Что мне с ней делать? Бежать через весь город нажимать на выключатель, если не понравится смена температуры стола?

    Если задача состоит в том, чтобы вручную остановить печать в случае проблем - с этим справятся камера и умная розетка с удалённым доступом. Для всего более продвинутого существует отличный проект Octoprint с плагинами.


  1. bschepan
    22.06.2022 15:06

    А ещё лучше октопринта будет клиппер - хоть и сложнее настроить, зато возможностей больше. Хотя я сам пока так и не добрался до хотя бы попробовать :)


    1. C4ET4uK
      22.06.2022 17:00
      +1

      Октопринт и клиппер это вообще ортогональные истории. Клиппер это альтернативная прошивка, а октопринт это средство удаленного контроля/управления. При этом они замечательно работают вместе через плагин для Octoptinta OctoKlipper


    1. danamir522
      22.06.2022 22:00
      +1

      Уже больше года использую klipper вместо марлина. Есть, конечно, сложности с установкой, но после этого каждый день радуюсь, когда пользуюсь 3d принтером. Попробуйте и вы, может понравиться.


    1. Creo2005
      23.06.2022 12:02

      Уже давно использую Клиппер, удаленно можно получать телеметрию и управлять через бота в телеге, даже не нужно принтер в сеть выставлять