3D-печать — это типичный пример аддитивного производства. Принцип работы заключается в том, что с помощью специального программного обеспечения для нарезки модель преобразуется в код, который может распознать система управления 3D-принтером. После загрузки кода система управления анализирует каждую строку и управляет печатью модели на 3D-принтере. Например, принцип печати FDM-принтера показан на рисунке 1-1.
Рисунок 1-1: Принцип 3D-печати
STL/Obj (и многие другие форматы) — это файлы моделей. Они могут быть созданы дизайнерами трёхмерных моделей или инженерами-конструкторами, а также получены с помощью 3D-сканеров. GCode — это набор команд, которые позволяют 3D-принтеру понять, как выполнять печать. Он сообщает 3D-принтеру, как работать, например, следующий открытый исходный код, полученный с помощью программного обеспечения Cura для нарезки FDM, представляет собой GCode-код для печати подвижного дракона (см. рисунок 1-2):
Рисунок 1-2: Модель STL-файла подвижного дракона
Код GCode для подвижного дракона после нарезки (см. рисунок 1-3):
Рисунок 1-3: Код GCode подвижного дракона после нарезки
Скачать с открытым исходным кодом:
https://www.bilibili.com/video/BV1HM4y1A73r?spm_id_from=333.337.search-card.all.click
Технология 3D-печати уже хорошо развита в области аддитивного производства по всему миру. Однако по сравнению с европейскими странами, технология 3D-печати в Китае всё ещё отстаёт, особенно в применении к сетевому управлению в области интернета вещей.
Этот проект, основанный на TencentOS Tiny, представляет собой систему облачного управления FDM 3D-печатными машинами. Система предназначена для управления и обмена данными с FDM 3D-печатными машинами через облако. По сравнению с 3D-печатными машинами, эта облачная система управления похожа на компьютер, которым можно управлять удалённо. Типичная архитектура связи для популярных принтеров с последовательным интерфейсом показана на рисунке 1-4:
Рисунок 1-4: Типичная коммуникационная архитектура 3D-принтер
Цель этого проекта — заложить основу для интеграции TencentOS-tiny и IoT Explorer в приложениях 3D-печати с использованием интернета вещей. TencentOS-Tiny и IoT Explorer обеспечивают комплексное решение от конца до облака и от облака до конца для встраиваемых устройств. В будущем, благодаря поддержке TencentOS-tiny и IoT Explorer, приложения для 3D-печати и интернета вещей смогут развиваться более инновационно и эффективно, способствуя развитию интеллектуального производства, промышленных кластеров и искусственного интеллекта, помогая предприятиям повышать эффективность исследований и разработок, снижать затраты на рабочую силу и производство, и достигать экономии за счёт масштаба.
Говоря о 3D-печати, у меня есть друг, который продаёт аксессуары для 3D-печатных машин. Это его новый магазин Taobao: https://shop65931018.taobao.com/
. Раньше он управлял старым магазином, чтобы изучить технологию 3D-печати. Он купил некоторые аксессуары из своего магазина, качество которых было довольно хорошим, все они были оригинальными продуктами, и отзывы были хорошими! Теперь, когда он открыл новый магазин, я должен поддержать его!
Разделение бизнес-логики программного обеспечения, высокая масштабируемость
Поддержка мультиплатформенной быстрой адаптации и переноса проектов
Поддержка функции сканирования и подключения Wi-Fi Smart Config от Tencent
Поддержка передачи данных вверх (температура, координаты, выравнивание данных и т. д.) через приложение Tencent Connect
Поддержка нисходящей передачи данных (температура, перемещение оси, скорость вращения вентилятора и т.д.) через приложение Tencent Connect
Поддержка просмотра данных в реальном времени и отправки команд управления через платформу Tencent Cloud IoT Explorer (соответствует данным восходящей передачи приложения Tencent Connect)
Поддержка отправки команд управления вниз через платформу Tencent Cloud IoT Explorer (соответствует данным нисходящей передачи приложения Tencent Connect)
Поддержка push-уведомлений о предупреждениях о превышении температуры через публичный аккаунт WeChat и приложение Tencent Connect
Впервые используется визуальный редактор Tencent для создания интерфейса приложения Tencent Connect, включая макет, события и привязку свойств.
Реализует основные функции управления и взаимодействия с 3D-печатными машинами и имеет потенциал для развития в направлении облачной печати для реализации сетевого управления 3D-печатными машинами.
Адрес репозитория проекта Github:
https://github.com/Yangyuanxin/IoT_3DPrinter
Адрес репозитория проекта Gitee:
https://gitee.com/morixinguan/IoT_3DPrinter
Демонстрационный адрес:
https://cloud.tencent.com/developer/video/32150
Аппаратная часть состоит из 3D-печатной машины (Anycubic Vyper 3D-печатная машина) и системы сетевого управления 3D-печатной машиной (на основе CH32V_EVB, платформы разработки MCU CH32V307VCT6 RISC-V). CH32V_EVB (как показано на рисунке 2-2) действует как компьютер верхнего уровня, а Anycubic Vyper — как компьютер нижнего уровня (как показано на рисунке 2-1):
Рисунок 2-1: Аппаратный состав системы управления 3D-печатной машиной
Anycubic Vyper — это выдающаяся 3D-печатная машина с точки зрения внешнего вида, скорости печати и качества печати. Его встроенное программное обеспечение основано на известном открытом программном обеспечении Marlin. Исходный код также является открытым, и его можно найти в репозитории GitHub:
https://github.com/ANYCUBIC-3D/Vyper
Пользователи могут настраивать и модифицировать встроенное ПО Marlin в соответствии со своими потребностями, даже объединять его с другими аксессуарами для создания других решений, таких как гравировальные станки. CH32V_EVB — это платформа разработки, разработанная Tencent и RISV совместно с Renshengwei, основанная на чипе RISC-V. Она показана на рисунке 2-3:
Рисунок 2-2: Платформа разработки CH32V_EVB
Программное обеспечение объединяет 3D-печатную машину с TencentOS Tiny, Tencent Cloud IoT Explorer и приложением Tencent Connect для реализации основных функций сетевого управления и обмена данными 3D-печатной машины. Оно состоит из трёх основных частей, как показано на рисунке 2–3:
Рисунок 2-3: Схема взаимодействия
Основной упор в проекте делается на разработку программного обеспечения. Основными компонентами являются приложение Tencent Connect и встроенная аппаратная часть.
Приложение Tencent Connect использует новейший визуальный редактор панелей IoT Explorer для разработки. Визуальный редактор панелей более мощный, чем стандартный интерфейс (как показано на рисунке 3-1), позволяя разработчикам создавать функциональные, красивые и удобные интерфейсы взаимодействия без необходимости глубокого понимания разработки приложений Tencent Connect. Просто комбинируя свойства, предоставляемые шаблонами данных, можно легко и быстро создать богатый функциями, красивый и удобный интерфейс взаимодействия.
Из-за нехватки времени в настоящее время только две страницы были разработаны с использованием визуального редактора панелей, как показано на рисунке 3-2:
Рисунок 3-2: Интерфейс приложения Tencent Connect
Встроенная аппаратная часть включает в себя Tencent Cloud IoT Explorer, приложение, общую часть, операционную систему, оборудование, Bsp, платформу микроконтроллера и так далее. Общая структура проектирования программного обеспечения предназначена для облегчения непрерывного функционального обновления и будущего развития проекта, как показано на рисунке 3-3: Рисунок 3-3. Структура программного фреймворка
TencentCloud IoT Explorer — платформа управления устройствами интернета вещей (IoT) от компании Tencent. Платформа интегрирована с мини-приложениями Tencent, а также с публичными аккаунтами WeChat для предоставления услуг IoT.
APP — основная часть бизнес-логики проекта. Включает в себя анализ данных последовательного порта, пересылку команд GCode, обработку подписки и публикации MQTT и другие функции.
Common — объединяет программные компоненты, используемые проектом. Включает библиотеки ringbuffer, cJSON, MQTT, систему логирования и другие компоненты.
OperatingSystem — операционная система. В настоящее время поддерживается только TencentOS-tiny, которая представляет собой операционную систему реального времени с минимальными требованиями к памяти, богатыми возможностями расширения и высокой производительностью.
Hardware — реализует некоторые обязательные аппаратные драйверы для проекта, включая драйверы кнопок, LCD и Wi-Fi.
Bsp — в основном это пакет поддержки на уровне платы, предоставляемый платформой микроконтроллера (Mcu). В настоящее время поддерживает только платформу CH32V_EVB, но в будущем планируется добавить поддержку других платформ.
McuPlatform — конкретная платформа микроконтроллера. В настоящее время поддерживает только CH32_EVB, в будущем возможно расширение поддержки других платформ.
3.3. Основной поток бизнес-процессов
В основном потоке бизнес-процесса приложения создаются три потока для обработки различных задач. Потоки взаимодействуют через очередь сообщений, предоставленную операционной системой TencentOS-Tiny. Когда поток не получает сообщение, он блокируется в ожидании сообщения, пока не получит его, после чего возобновляет работу. Это позволяет эффективно управлять ресурсами процессора и избегать их ненужного использования.
В дизайне основного потока бизнес-процесса используется очередь сообщений для обеспечения развязки между потоками и повышения расширяемости системы. Кроме того, очередь сообщений может переносить данные и формат данных может быть настроен пользователем.
Дизайн основного потока бизнес-процесса представлен на рисунке 3–4:
Рисунок 3–4. Дизайн основного потока бизнес-процесса
Данные передаются между очередями сообщений через структуру сообщения:
/*Сообщение структуры упаковки*/
#define MSG_LEN 50
struct Msg_t
{
//Тип сообщения
uint8_t Type;
//Данные сообщения
char Data[MSG_LEN];
};
Типы сообщений включают команды для обновления температуры, оси координат, токена и команды выравнивания.
//Команды, отправленные в сетевой поток
enum MsgCmd_t
{
MSG_CMD_UPDATE_TEMP=0,
MSG_CMD_UPDATE_AXIS,
MSG_CMD_UPDATE_TOKEN,
MSG_CMD_LEVELING_1,
MSG_CMD_LEVELING_2,
MSG_CMD_LEVELING_3,
MSG_CMD_LEVELING_4,
};
//Команды, отправляемые в поток пересылки GCode
enum Msg2GCode_t
{
MSG_2_GCODE_CMD_AUTO_GET_TEMP = 0,
MSG_2_GCODE_CMD_PLA_PRE,
MSG_2_GCODE_CMD_ABS_PRE,
MSG_2_GCODE_CMD_TEMP_DROP,
MSG_2_GCODE_CMD_X_MOVE_ADD,
MSG_2_GCODE_CMD_X_MOVE_SUB,
MSG_2_GCODE_CMD_Y_MOVE_ADD,
MSG_2_GCODE_CMD_Y_MOVE_SUB,
MSG_2_GCODE_CMD_Z_MOVE_ADD,
MSG_2_GCODE_KT_Z_MOVE_SUB,
MSG_2_GCODE_CMD_ZERO_OF_X,
MSG_2_GCODE_CMD_ZERO_OF_Y,
MSG_2_GCODE_CMD_ZERO_OF_Z,
MSG_2_GCODE_CMD_ZERO_OF_ALL,
MSG_2_GCODE_CMD_LEVEL_DATA,
MSG_2_GCODE_CMD_FAN_SETTING,
MSG_2_GCODE_CMD_START_PRINT
};
Тип сообщения определяет тип данных, которые будут переданы. Данные могут быть пустыми, строковыми или представлять собой структуру или другой тип. Тип данных зависит от типа сообщения и бизнес-логики приложения. Такой дизайн обеспечивает высокую гибкость и расширяемость.
3.3.1. Задачи основного потока
(1) Создание очередей сообщений, сетевых потоков и потоков пересылки GCode.
#define DEFAULT_TASK_SIZE 2048
void StartMainTask(void *pdata);
osThreadDef(StartMainTask, osPriorityLow, 1, DEFAULT_TASK_SIZE);
#define GCODE_FORWARD_TASK_SIZE 1024
void StartGCodeForWardTask(void *arg);
osThreadDef(StartGCodeForWardTask, osPriorityHigh, 1, GCODE_FORWARD_TASK_SIZE);
#define MQTT_TASK_SIZE 2048
void StartNetworkTask(void *pdata);
osThreadDef(StartNetworkTask, osPriorityLow, 1, MQTT_TASK_SIZE);
//Основной поток в очередь сообщений сетевого потока
k_msg_q_t DataMsg;
uint8_t DataMsgPool[50];
//Очередь сообщений сетевого потока в поток пересылки GCode
k_msg_q_t GCodeMsg;
uint8_t GCodeMsgPool[50];
.....Опущено
//Создание очереди сообщений основного потока в сетевой поток
err = tos_msg_q_create(&DataMsg, DataMsgPool, 50);
if (K_ERR_NONE != err)
{
printf("Create DataMsg Fail:%d!\n", err);
return;
}
//Создаём очередь сообщений сетевого потока в поток пересылки GCode
err = tos_msg_q_create(&GCodeMsg, GCodeMsgPool, 50);
if (K_ERR_NONE != err)
{
printf("Create GCodeMsg Fail:%d!\n", err);
return;
}
//Создать сетевой поток
if (NULL == osThreadCreate(osThread(StartNetworkTask), NULL))
{
printf("osThreadCreate Mqtt Fail!\n");
return;
}
//Создать поток пересылки GCode
if (NULL == osThreadCreate(osThread(StartGCodeForWardTask), NULL))
{
printf("osThreadCreate StartGCodeForWardTask Fail!\n");
return;
}
(2) Отправка команды автоматического получения температуры для периодического получения данных о температуре сопла и нагревательного стола и отправки их обратно.
Отправка команды автоматического получения температуры основана на протоколе передачи команд GCode. Связь с 3D-принтером осуществляется через последовательный порт, и когда принтер получает команду, внутренняя прошивка обрабатывает её и возвращает соответствующие данные. Таким образом, можно найти соответствующую команду GCode на официальном сайте Marlin и настроить её в программе, чтобы принтер автоматически отправлял данные о температуре. Официальный сайт Marlin для поиска команд GCode:
https://marlinfw.org/meta/gcode/
Существует два способа получения данных о температуре с помощью 3D-принтера: один из них — использовать таймер для отправки команды M105 каждые 3–4 секунды, что заставит принтер возвращать данные о температуре, но Marlin не рекомендует этот метод. Вместо этого рекомендуется использовать команду M155 для автоматической отправки данных о температуре. Однако для этого необходимо, чтобы прошивка принтера поддерживала функцию AUTO_REPORT_TEMPRATURES. Если нет, то придётся модифицировать прошивку принтера, чтобы включить эту функцию. Получение данных о температуре от 3D-принтера и их отправка в сеть
В этом разделе описывается логика работы программы, которая автоматически получает данные о температуре с 3D-принтера через команды GCode.
Сначала устанавливается тип сообщения для автоматического получения данных о температуре. Затем это сообщение отправляется в очередь сообщений для дальнейшей передачи в поток обработки команд GCode (GCodeMsg).
После этого происходит получение данных о температуре с принтера через последовательный порт. Данные имеют следующий формат:
T:27.00 /0.00 B:27.80 /0.00 @:0 B@:0(конец строки обозначается символом \n) // Первый байт — пробел
ok T:27.03 /0.00 B:27.78 /0.00 @:0 B@:0 (конец строки обозначается двумя байтами ok)
Данные принимаются через прерывание, обрабатываются основным потоком и сохраняются в кольцевом буфере. Основной поток считывает данные из буфера и обрабатывает их. Если данные не заканчиваются символом перевода строки, то они добавляются в конец буфера. Когда данные заканчиваются переводом строки, они обрабатываются.
Для обработки данных создаётся структура, содержащая информацию о температуре:
typedef struct Temperature
{
// Текущая температура сопла
double nozzle_cur_temp;
// Целевая температура сопла
double nozzle_target_temp;
// Текущая температура стола
double hotbed_cur_temp;
// Целевая температура стола
double hotbed_target_temp;
} marlin_temp;
Затем создаётся функция, которая извлекает данные о температуре из строки и сохраняет их в структуре:
void Get_Temperature(char *str, marlin_temp *temp_info)
{
char buf[10] = { 0 };
int cut_out_len = 0;
char *data_field = NULL;
char *space_field = NULL;
if (str[0] == ' ' && str[1] == 'T')
str += 1;
if (str[0] == 'o' && str[1] == 'k')
str += 3;
data_field = strstr(str, ":");
space_field = strstr(str, " ");
cut_out_len = space_field - data_field - 1;
memcpy(buf, data_field + 1, cut_out_len);
temp_info->nozzle_cur_temp = atof(buf);
data_field = strstr(space_field, "/");
space_field = strstr(space_field + 1, " ");
cut_out_len = space_field - data_field - 1;
marlin_data_buffer_bzero(buf, 10);
memcpy(buf, data_field + 1, cut_out_len);
temp_info->nozzle_target_temp = atof(buf);
data_field = strstr(space_field, ":");
space_field = strstr(space_field + 1, " ");
cut_out_len = space_field - data_field - 1;
marlin_data_buffer_bzero(buf, 10);
memcpy(buf, data_field + 1, cut_out_len);
temp_info->hotbed_cur_temp = atof(buf);
data_field = strstr(space_field, "/");
space_field = strstr(space_field + 1, " ");
cut_out_len = space_field - data_field - 1;
marlin_data_buffer_bzero(buf, 10);
memcpy(buf, data_field + 1, cut_out_len);
temp_info->hotbed_target_temp = atof(buf);
}
Также можно использовать более простой способ тестирования — подключить принтер к компьютеру через последовательный порт и использовать программное обеспечение для последовательной отладки. Инициализация ESP8266 и функция SmartConfig для настройки сети
Все операции, связанные с WIFI на ESP8266, основаны на AT-фреймворке. Прошивка ESP8266 от Tencent позволяет быстро подключаться к платформе IoT explorer и использовать функцию SmartConfig для настройки сети. Как записать прошивку Tencent Cloud на устройство, будет описано в следующем разделе. Логика кода для этого раздела выглядит следующим образом:
// Регистрируем Sal, здесь автоматически вызывается внутренняя функция init для завершения инициализации ESP8266
ret = esp8266_tencent_firmware_sal_init(HAL_UART_PORT_2);
if (ret < 0) {
printf("esp8266 tencent firmware sal init fail, ret is %d\r\n", ret);
NVIC_SystemReset();
}
tos_task_delay(6000);
/* Выполняем логику настройки сети WIFI */
WifiSmartConfig();
// Опускаем часть кода...
// Логика настройки сети WIFI Smart Config
static void WifiSmartConfig() {
int rssi;
int channel = -1;
static uint8_t ConfigWifi = 0;
char ssid[50] = { 0 };
char bssid[50] = { 0 };
/* Получаем информацию о WIFI AP, если возвращается -1, это означает, что получение не удалось */
/* Когда перед включением долго нажимаем кнопку 3, переходим в режим настройки сети WIFI */
if (-1 == tos_tf_module_get_info(ssid, bssid, &channel, &rssi) || 3 == Key_Scan()) {
/* Переходим в режим настройки сети и отображаем QR-код для настройки сети */
LCD_Fill(0, 0, 240, 240, WHITE);
GPIO_WriteBit(GPIOE, GPIO_Pin_5, 0); // Зажигаем индикатор
LCD_ShowString(30, 10, "3D Printer Add", BLACK, WHITE, 24, 0);
LCD_ShowPicture((240 - 150) / 2, (240 - 150) / 2, 150, 150, gImage_wifi_config);
if (0 == tos_tf_module_smartconfig_start()) {
ConfigWifi = 1;
LCD_Fill(0, 0, 240, 240, BLACK);
tos_tf_module_smartconfig_stop();
} else {
LCD_ShowString(10, 10, "WifiConfig Error!", WHITE, BLACK, 32, 0);
NVIC_SystemReset();
}
}
if(0 == ConfigWifi)
LCD_Fill(0, 0, 240, 120, BLACK);
GPIO_WriteBit(GPIOE, GPIO_Pin_5, 1);
// Получаем сетевую информацию и выводим её через LCD
snprintf(esp8266_info.ssid, sizeof(esp8266_info.ssid), "ssid:%s", ssid);
snprintf(esp8266_info.bssid, sizeof(esp8266_info.bssid), "bssid:%s", bssid);
snprintf(esp8266_info.channel, sizeof(esp8266_info.channel), "channel:%d",channel);
snprintf(esp8266_info.rssi, sizeof(esp8266_info.rssi), "rssi:%d", rssi);
LCD_ShowString(10, 10, "Wifi Connect OK", WHITE, BLACK, 16, 0);
LCD_ShowString(10, 26, esp8266_info.ssid, WHITE, BLACK, 16, 0);
LCD_ShowString(10, 26 + 16, esp8266_info.bssid, WHITE, BLACK, 16, 0);
LCD_ShowString(10, 26 + 16 + 16, esp8266_info.channel, WHITE, BLACK, 16, 0);
LCD_ShowString(10, 26 + 16 + 16 + 16, esp8266_info.rssi, WHITE, BLACK, 16,0);
LCD_ShowPicture(0,190, 240, 50,gImage_icon_for_tencentos_tiny);
}
(2) Конфигурация тройки устройств на платформе Tencent Cloud, подключение к серверу MQTT, подписка на тему и обработка обратного вызова
После успешного подключения модуля ESP8266 к сети, необходимо выполнить операцию подключения к Iot Explorer серверу Tencent Cloud. Здесь нам нужно получить соответствующую тройку устройств на Iot Explorer сервере, которая состоит из идентификатора продукта, имени устройства и ключа. При подключении к серверу эта тройка передаётся интерфейсу подключения сервера, чтобы успешно подключиться к Iot Explorer серверу Tencent. Тройка устройств служит для аутентификации устройства на сервере. Без неё, даже если устройство знает адрес и порт сервера и может подключиться, сервер не будет знать, какое именно устройство подключено, и не сможет управлять им или взаимодействовать с ним. Логика реализации кода для этой части выглядит следующим образом:
// Устанавливаем тройку устройств в модуль, затем выполняем операцию соединения с сервером MQTT
strncpy(dev_info.product_id, product_id, PRODUCT_ID_MAX_SIZE);
strncpy(dev_info.device_name, device_name, DEVICE_NAME_MAX_SIZE);
strncpy(dev_info.device_serc, key, DEVICE_SERC_MAX_SIZE);
tos_tf_module_info_set(&dev_info, TLS_MODE_PSK);
mqtt_param_t init_params = DEFAULT_MQTT_PARAMS;
if (tos_tf_module_mqtt_conn(init_params) != 0) {
printf("module mqtt conn fail\n");
NVIC_SystemReset();
}
if (tos_tf_module_mqtt_state_get(&state) != -1) {
printf("MQTT: %s\n",state == MQTT_STATE_CONNECTED ? "CONNECTED" : "DISCONNECTED");
}
Когда соединение с сервером успешно установлено, устройству необходимо подписаться на темы, публикуемые сервером, чтобы получать команды управления от сервера. В настоящее время для устройств IoT Explorer Tencent предоставляет три типа тем: темы модели устройства, системные темы и пользовательские темы.
В этом проекте используется подписка на тему модели устройства:
$thing/down/property/99LPJ2KWLM/${deviceName}
Конкретная логика кода выглядит следующим образом:
/* Начинаем подписку на тему */
size = snprintf(report_reply_topic_name, TOPIC_NAME_MAX_SIZE,
"$thing/down/property/%s/%s", product_id, device_name);
if (size < 0 || size > sizeof(report_reply_topic_name) - 1) {
printf("sub topic content length not enough! content size:%d buf size:%d",
size, (int) sizeof(report_reply_topic_name));
return;
}
if (tos_tf_module_mqtt_sub(report_reply_topic_name, QOS0,
MessageParamsHandler) != 0)
``` ```
printf("module mqtt sub fail\n");
NVIC_SystemReset();
}
Когда Iot Explorer отправляет сообщение, оно будет обработано функцией обратного вызова MessageParamsHandler. Часть кода выглядит следующим образом:
void MessageParamsHandler(mqtt_message_t* msg)
{
struct Msg_t Msg;
cJSON *root = NULL;
cJSON *token = NULL;
cJSON *params = NULL;
cJSON *method = NULL;
cJSON *led_control = NULL;
cJSON *printer_control = NULL;
cJSON *printer_fan_speed = NULL;
char GCodeBuf[15] = { 0 };
double result_fan_speed;
#if 0
printf("mqtt callback:\r\n");
printf("---------------------------------------------------------\r\n");
printf("\ttopic:%s\r\n", msg->topic);
printf("\tpayload:%s\r\n", msg->payload);
printf("---------------------------------------------------------\r\n");
#endif
/*1. Анализ полученной информации от облачного сервера*/
root = cJSON_Parse(msg->payload + 1);
if (!root)
{
printf("Invalid json root\r\n");
return;
}
/*2. Анализ метода*/
method = cJSON_GetObjectItem(root, "method");
if (!method)
{
printf("Invalid json method\r\n");
cJSON_Delete(root);
return;
}
/*3. Обрабатываем только данные управления, отправленные облачным сервером, данные отчета не обрабатываем*/
if (0 != strncmp(method->valuestring, "control", strlen("control")))
{
cJSON_Delete(root);
return;
}
/*4. Анализируем параметры*/
params = cJSON_GetObjectItem(root, "params");
if (!params)
{
printf("Invalid json params\r\n");
cJSON_Delete(root);
return;
}
/*5. Согласно параметрам, анализируем "params":{"power_switch":0}*/
led_control = cJSON_GetObjectItem(params, "power_switch");
если (led_control)
{
if (led_control->valueint)
{
DEBUG_LED(1)
}
else
{
DEBUG_LED(0)
}
}
/*6. Согласно параметрам, анализируем "params":{"printing_control":3}*/
printer_control = cJSON_GetObjectItem(params, "printing_control");
если (printer_control)
{
//Преобразуем конкретное значение атрибута в тип сообщения и отправляем его в очередь сообщений GCodeMsg.
Msg.Type = printer_control->valueint;
tos_msg_q_post(&GCodeMsg, (void *) &Msg);
}
printer_fan_speed = cJSON_GetObjectItem(params, "fan_speed");
если (printer_fan_speed)
{
memset(GCodeBuf, 0, 15);
result_fan_speed = (double) printer_fan_speed->valueint / 255 * 2.55
* 100 * 2.55;
snprintf(GCodeBuf, sizeof(GCodeBuf), GCODE_FAN_SETTING,
(int) result_fan_speed);
//Устанавливаем тип сообщения, копируем обработанную строку в полезную нагрузку сообщения.
//Отправляем сообщение через очередь сообщений в поток обработки GCode.
Msg.Type = MSG_2_GCODE_CMD_FAN_SETTING;
memcpy(Msg.Data, GCodeBuf, sizeof(GCodeBuf));
tos_msg_q_post(&GCodeMsg, (void *) &Msg);
}
/*7. Устанавливаем ответ clientToken*/
token = cJSON_GetObjectItem(root, "clientToken");
если (token)
{
//Устанавливаем тип сообщения как MSG_CMD_UPDATE_TOKEN и отправляем в сетевой поток для обработки.
Msg.Type = MSG_CMD_UPDATE_TOKEN;
tos_msg_q_post(&DataMsg, (void *) &Msg);
}
cJSON_Delete(root);
root = NULL;
}
Управление 3D-принтером осуществляется с помощью свойства printing_control, которое определяется сценарием модели объекта Iot Explorer. Эта часть будет представлена позже в разделе о подключении к платформе. Как показано на рисунке 3-8:
Рисунок 3–8, модель объекта JSON
Эта часть отвечает за обработку сообщений, отправляемых основным потоком. Если нет сообщения, она блокируется до тех пор, пока не получит конкретное сообщение, после чего изменит состояние и продолжит выполнение. Затем сообщение публикуется с использованием темы модели объекта, как показано ниже:
$thing/up/property/99LPJ2KWLM/${deviceName}
Формат публикуемого сообщения в основном определяется в app_main.h:
/*Отчёт о температуре сопла*/
#define REPORT_NOZZLE_TEMP_DATA_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"nozzle_temp\\\":\\\"%s\\\"}}"
/*Отчёт об аварийной температуре сопла*/
#define REPORT_NOZZLE_TEMP_ALARM_DATA_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"nozzle_temp_alarm\\\":\\\"%s\\\"}}"
/*Отчёт о температуре горячей кровати*/
#define REPORT_HOTBED_TEMP_DATA_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"hotbed_temp\\\":\\\"%s\\\"}}"
/*Отчёт о положении сопла*/
#define REPORT_POS_DATA_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"axis_text\\\":\\\"%s\\\"}}"
/*Ответное сообщение*/
#define CONTROL_REPLY_DATA_TEMPLATE \
"{\\\"method\\\":\\\"control_reply\\\"\\,\\\"clientToken\\\":\\\"%s\\\"\\,\\\"code\\\":0\\,\\\"status\\\":\\\"ok\\\"}"
/*Данные выравнивания*/
#define REPORT_LEVELING_DATA1_TEMPLATE \
``` ```
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"level1_data\\\":\\\"%s\\\"}}",
#define REPORT_LEVELING_DATA2_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"level2_data\\\":\\\"%s\\\}}",
#define REPORT_LEVELING_DATA3_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"level3_data\\\":\\\"%s\\\}}",
#define REPORT_LEVELING_DATA4_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"level4_data\\\":\\\"%s\\\}}",
#define REPORT_LEVELING_DATA_STATUS_TEMPLATE \
"{\\\"method\\\":\\\"report\\\"\\,\\\"clientToken\\\":\\\"00000001\\\"\\,\\\"params\\\":{\\\"levelDataStatus\\\":\\\"%s\\\}}"```
Здесь необходимо объединить определённые данные с определёнными строками, определёнными макросами, а затем вызвать функцию tos_tf_module_mqtt_pub для публикации сообщения. Логика кода примерно следующая:
```c
//....省略部分代码
memset(report_topic_name, 0, sizeof(report_topic_name));
size = snprintf(report_topic_name, TOPIC_NAME_MAX_SIZE,
"$thing/up/property/%s/%s", product_id, device_name);
if (size < 0 || size > sizeof(report_topic_name) - 1)
{
printf("pub topic content length not enough! content size:%d buf size:%d",
size, (int) sizeof(report_topic_name));
}
//....省略部分代码
while (1)
{
//阻塞等待消息
err = tos_msg_q_pend(&DataMsg, &MsgRecv, TOS_TIME_FOREVER);
if(K_ERR_NONE == err)
{
if(K_ERR_NONE == err)
{
//将接收到的数据载体转换为消息类型结构体
memcpy(&Msg,MsgRecv,sizeof(struct Msg_t));
//匹配具体的消息类型并进行不同消息类型的处理
switch(Msg.Type)
{
//上报温度数据
case MSG_CMD_UPDATE_TEMP:
ReportDeviceTemp((marlin_temp *)&Msg.Data);
break;
//上报轴移动坐标
case MSG_CMD_UPDATE_AXIS:
ReportDeviceAxis((marlin_coordinate *)&Msg.Data);
break;
//上报Client Token信息
case MSG_CMD_UPDATE_TOKEN:
ReportClientToken();
break;
//上报获取调平信息的数据
case MSG_CMD_LEVELING_1:case MSG_CMD_LEVELING_2:
case MSG_CMD_LEVELING_3:case MSG_CMD_LEVELING_4:
ReportDeviceLevelData(Msg.Type,Msg.Data);
break;
default:
printf("Msg.Type is Unknow!\n");
break;
}
}
}
osDelay(5);
}```
**3.3.3 GCode-поток обработки**
Поток обработки GCode будет преобразовывать полученные сообщения, проверять их на соответствие типу, и затем преобразовывать сообщение в команду GCode и отправлять её на последовательный порт 3D-принтера:
```c
//.....省略部分代码
typedef struct GCodeCmdHandler_t
{
//命令类型
uint8_t Type;
//GCode命令
char *GcodeCmd;
}GCodeCmdHandler_t;
//.....省略部分代码
//消息类型对应GCode代码映射表
GCodeCmdHandler_t Msg2GCodeTab[] =
{
{MSG_2_GCODE_CMD_AUTO_GET_TEMP,GCODE_AUTO_GET_TEMP },
{MSG_2_GCODE_CMD_PLA_PRE, GCODE_PLA_PRE },
{MSG_2_GCODE_CMD_ABS_PRE, GCODE_ABS_PRE },
{MSG_2_GCODE_CMD_TEMP_DROP,GCODE_TEMP_DROP },
{MSG_2_GCODE_CMD_X_MOVE_ADD, GCODE_X_MOVE_ADD },
{MSG_2_GCODE_CMD_X_MOVE_SUB, GCODE_X_MOVE_SUB },
{MSG_2_GCODE_CMD_Y_MOVE_ADD, GCODE_Y_MOVE_ADD },
{MSG_2_GCODE_CMD_Y_MOVE_SUB, GCODE_Y_MOVE_SUB },
{MSG_2_GCODE_CMD_Z_MOVE_ADD, GCODE_Z_MOVE_ADD },
{MSG_2_GCODE_CMD_Z_MOVE_SUB, GCODE_Z_MOVE_SUB },
{MSG_2_GCODE_CMD_ZERO_OF_X, GCODE_ZERO_OF_X },
{MSG_2_GCODE_CMD_ZERO_OF_Y, GCODE_ZERO_OF_Y },
{MSG_2_GCODE_CMD_ZERO_OF_Z, GCODE_ZERO_OF_Z },
{MSG_2_GCODE_CMD_ZERO_OF_ALL, GCODE_ZERO_OF_ALL },
{MSG_2_GCODE_CMD_LEVEL_DATA, GCODE_LEVELING_DATA },
{MSG_2_GCODE_CMD_START_PRINT, GCODE_START_PRINT }
};
//GCode转发线程
void StartGCodeForWardTask(void *arg)
{
(void) arg;
k_err_t err;
char *GCode;
void *MsgRecv;
struct Msg_t Msg;
for (;;)
{
//阻塞等待消息
err = tos_msg_q_pend(&GCodeMsg, &MsgRecv, TOS_TIME_FOREVER);
if (K_ERR_NONE == err)
{
//将接收到的数据转换为消息类型结构体
memcpy(&Msg, MsgRecv, sizeof(struct Msg_t));
//判断消息类型是否合法
if (Msg.Type > MSG_2_GCODE_CMD_START_PRINT)
printf("Msg.Type is Unknow!\n");
else
{
//如果是设置风扇速度,则进行特殊处理
if (MSG_2_GCODE_CMD_FAN_SETTING == Msg.Type)
GCodeForward(Msg.Data, GCode_Send);
//否则直接调用表中的GCode命令将其发送给3D打印机串口
else
{
GCode = Msg2GCodeTab[Msg.Type].GcodeCmd;
GCodeForward(GCode, GCode_Send);
}
}
}
osDelay(5);
}
}
//以下是GCode转发线程调用的接口
//GCode命令转发
char *GCodeForward(char *Gcode, void(*GCodeToSend)(char *))
{
``` ```
if (NULL == Gcode || NULL == GCodeToSend)
return NULL;
GCodeToSend(Gcode);
return "OK";
}
// Отправка строки в последовательный порт
void GCode_Send(char *str) {
osSchedLock();
// Закрываем приём прерываний перед отправкой
USART_ITConfig(UART7, USART_IT_RXNE, DISABLE);
while (*str != '\0') {
USART_SendData(UART7, *str++);
while (USART_GetFlagStatus(UART7, USART_FLAG_TC) == RESET);
}
/* Очистка флага отправки */
USART_ClearFlag(UART7,USART_FLAG_TC);
USART_ITConfig(UART7, USART_IT_RXNE, ENABLE);
// Включаем приём прерываний после отправки
osSchedUnLock();
}```
**4. Платформа IoT Explorer от Tencent и интеграция с мини-программой Tencent**
Весь проект разрабатывается на основе программного обеспечения Tencent. Программное обеспечение Tencent поддерживает широкий спектр AT-команд, которые позволяют реализовать такие функции, как подключение к сети Wi-Fi, MQTT-подключение, подписка и публикация. Однако перед разработкой необходимо записать прошивку на плату разработки.
#### 4.1. Запись прошивки Tencent Cloud ESP8266
##### 4.1.1. Знакомство с принципиальной схемой и платой разработки
**(1) Принципиальная схема и расположение выводов платы разработки**
*Рисунок 4-1: Принципиальные схемы последовательного порта и сети Wi-Fi*
**(2) Соответствие между принципиальной схемой и фактическими выводами на плате разработки**
*Рисунок 4-2: Схема последовательного порта соответствует фактическому расположению выводов на плате*
*Рисунок 4-3: Схема сети Wi-Fi соответствует фактическому расположению выводов на плате*
**(3) Подключение платы разработки к компьютеру**
*Рисунок 4-4: Подключение платы разработки к USB-порту компьютера*
##### 4.1.2. Запись прошивки ESP8266 Tencent Cloud
**(1) Запуск программы записи прошивки ESP8266**
*Рисунок 4-5: Программа записи прошивки ESP8266*
**(2) Настройка параметров записи прошивки ESP8266 и запуск процесса записи**
*Рисунок 4-6: Настройка параметров и запуск записи прошивки*
Запись прошла успешно. После успешной записи необходимо подключить H5 к источнику питания 3,3 В, как показано на рисунке 4-7, чтобы перевести ESP8266 в нормальный режим работы:
*Рисунок 4-7: Переключение в нормальный режим*
##### 4.1.3. Проверка успешности записи прошивки Tencent Cloud на ESP8266
Откройте руководство по AT-командам для Wi-Fi-прошивки Tencent Cloud IoT Training Camp в папке «TencentOS Tiny RISC-V IoT».
*Рисунок 4-8: Руководство по AT-командам*
Запустите программу последовательной отладки и отправьте команду AT+TCMODULE. Я использую программное обеспечение SSCOM 5.13 для тестирования:
*Рисунок 4-9: Ответ на команду AT+TCMODULE*
Если ответ содержит информацию о модуле, это означает, что прошивка Tencent Cloud успешно записана в модуль Wi-Fi ESP8266. Если вам нужно протестировать модуль Wi-Fi через компьютер, подключите его, как показано на рисунке 4-10. По умолчанию при подключении будет выводиться информация о журнале модуля Wi-Fi:
*Рисунок 4-10: Режим взаимодействия AT с ESP8266 через ПК*
Для подключения к модулю Wi-Fi с помощью MCU выполните соединение, как показано на рисунке 4-11. По умолчанию при подключении будет отображаться информация журнала MCU:
*Рисунок 4-11: Соединение ESP8266 с MCU через последовательный порт*
*Рисунок 4-12: Соединение MCU с последовательным портом ESP8266*
Обычно после успешной записи прошивки Wi-Fi и проверки её работоспособности можно приступать к разработке основной программы. На этом этапе необходимо соединить последовательные порты Wi-Fi модуля и MCU.
Таким образом, запись прошивки ESP8266 завершена. Теперь можно приступить к написанию программы и взаимодействию с платформой IoT Explorer и мини-приложением Tencent.
#### 4.2. Конфигурация платформы IoT Explorer и мини-программы Tencent
Процесс создания продукта на платформе IoT Explorer можно найти в статье официального аккаунта TencentOS в WeChat:
```c
https://mp.weixin.qq.com/s/t8iVaypA1BtZwt7EEkAWyw
В этом конкурсе проект основан на стандартном шаблоне, но с некоторыми изменениями. Данные шаблона следующие:
{
"version": "1.0",
"properties": [
{
"id": "power_switch",
"name": "Свет",
"desc": "Управление светом",
"mode": "rw",
"required": true,
"define": {
"type": "bool",
"mapping": {
"0": "Выключить свет",
"1": "Включить свет"
}
}
},
{
"id": "printing_control",
"name": "Управление 3D-принтером",
"desc": "Управление 3D-принтером",
"mode": "rw",
"define": {
"type": "enum",
"mapping": {
"0": "Ответ на команду",
"1": "Предварительный нагрев PLA",
"2": "Предварительный нагрев ABS",
"3": "Охлаждение",
"4": "Перемещение X-оси вправо на 10 единиц",
"5": "Перемещение X-оси влево на 10 единиц",
"6": "Перемещение Y-оси вправо на 10 единиц",
"7": "Перемещение Y-оси влево на 10 единиц",
"8": "Перемещение Z-оси вправо на 10 единиц",
"9": "Перемещение Z-оси влево на 10 единиц",
"10": "Обнуление X-оси",
"11": "Обнуление Y-оси",
"12": "Обнуление Z-оси",
"13": "Полное обнуление",
"14": "Калибровка",
"15": "Начать печать"
}
},
"required": false
},
{
"id": "axis_text",
"name": "Отображение информации о местоположении",
"desc": "Положение",
"mode": "r",
"define": {
"type": "string",
"min": "0",
"max": "2048"
},
"required": false
},
{
"id": "nozzle_temp",
"name": "Температура сопла",
"desc": "По Цельсию",
"mode": "r",
"define": {
"type": "string"
}
}
]
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )