Загрузка данных


ПАСПОРТ ПРОЕКТА: Графический интерфейс ЧПУ (Python / PyQt6)

Привет! Нам нужно разработать профессиональное управляющее приложение на Python (PyQt6 + pyqtgraph) в стиле промышленного интерфейса LinuxCNC AXIS. Приложение будет управлять кастомным 4-метровым фрезерным станком по Wi-Fi.

КОНТЕКСТ И АРХИТЕКТУРА СИСТЕМЫ:
1. Железо станка: 4-метровая ферма. Ось X — зубчатая рейка (100 шагов/мм), Y и Z — ласточкин хвост + винты ШВП (400 шагов/мм). 
2. Топология шкафа: Вся электроника, драйверы и контроллер ESP32 (38-pin) установлены в экранированном щите прямо на подвижной чугунной каретке. Длина проводов к моторам <1 метра, наводок нет.
3. Прошивка ESP32: Написана на C++ (PlatformIO). Core 1 генерирует импульсы STEP/DIR на частоте 100 кГц. Core 0 управляет TCP-сервером (IP: 192.168.4.1, Порт: 8888). Станок является Wi-Fi точкой доступа.
4. Бинарная предзагрузка G-кода: Чтобы избежать пауз при Wi-Fi передаче, программа целиком упаковывается в Питон-приложении и пачкой заливается в кучу (RAM) ESP32 (буфер на 10 000 команд, по 15 байт на кадр). Станок пилит автономно из памяти.
5. Энергонезависимость: Координаты WCS (G54), матрица наклона детали и номер текущей выполняемой строки автоматически фиксируются в EEPROM станка. При сбое питания станок помнит, где упал.

ПРОТОКОЛ ОБМЕНА ДАННЫМИ ПО TCP (Все команды заканчиваются на \n):
- От станка в ПК (Телеметрия каждую секунду): 
  "<Status:ИМЯ_СТАТУСА|Pos:X=0.00,Y=0.00,Z=0.00|Line=НОМЕР_СТРОКИ>"
- От станка в ПК (При покадровом режиме): "SINGLE_BLOCK_WAIT" (сигнал, что кадр сделан и станок замер).
- Базовые команды к станку: "ESTOP" (Авария), "RESET_ALARM" (Сброс), "HOME" (Хоуминг), "SET_ZERO:ALL" (Обнуление WCS).
- Запрос точки останова: "GET_LAST_ABORTED_LINE" (Станок ответит: "LAST_LINE:Номер"). Запуск со строки: "START_FROM_LINE:Номер".
- Ручной режим (JOG): "JOG:G0 X10 F1200", "JOG:G0 Y-5 F600".
- Удаленная настройка EEPROM: "GET_CONFIG" (выдает строку всех шагов/ускорений) и "SET_CONFIG:accel=180.0".
- Пошаговый дебаг: "SINGLE_BLOCK_ON" / "SINGLE_BLOCK_OFF" / "NEXT_BLOCK" (выполнить следующий кадр).
- Разворот заготовки (Наклон): "SET_ALIGN_A" (задать точку старта), "SET_ALIGN_B" (задать финиш), "ACTIVATE_ALIGN" / "DEACTIVATE_ALIGN".
- Измерительные сканеры: 
  * "START_CALIBRATION" (запуск лазерного сканирования провиса фермы).
  * "EXPORT_MAP" (выгрузка карты из станка) / "MAP_LOAD_START" -> "MAP_LOAD:IDX=..;Y=..;Z=.." -> "MAP_LOAD_END" (заливка карты в станок).
  * "SCAN_GEOMETRY:START;END;STEP;SPEED" (запуск комплексного сканирования фермы часовым индикатором и лазером одновременно). Станок начнет выдавать в сокет поток CSV-данных: "X_POS;DIAL_INDICATOR;LASER_Y;LASER_Z". Модули съемные (Hot-Plug), если физически отключены, станок выдает вместо цифр маркер "DISCONNECTED".

НАША ЗАДАЧА В ЭТОМ ЧАТЕ:
Разработать GUI-приложение на Python (PyQt6 + pyqtgraph.opengl). Интерфейс должен содержать:
1. Окно DRO (Координаты X, Y, Z, статус станка, текущая и последняя сбойная строка из EEPROM).
2. Панель JOG-управления (Стрелки, выбор шага, слайдер скорости) и MDI-консоль ввода команд.
3. Интерактивное 3D-окно (pyqtgraph): сетка станины 4000х500 мм, маркер положения фрезы, синяя линия траектории из загруженного файла .nc.
4. Визуализацию лазерной карты отклонений (в виде 3D-сетки/поверхности) и вывод графиков геометрического сканера (сравнение данных часового индикатора и лазера).
5. Конвертер-паковщик: модуль, который открывает файл G-кода, очищает от комментариев, берет реальный номер строки файла, формирует бинарные пакеты "B:TYPE;LINE_NUM;X;Y;Z;F" и пачкой шлет в TCP-сокет.

Давай начнем со структуры классов PyQt6, настройки сетевого потока QThread и построения 3D OpenGL сцены станка.