Один из принтеров, который в работе, - creality K1C оборудован камерой для наблюдения за процессом печати. Удобно, но не более. Наблюдать часами как печатается деталь быстро надоедает. Вдвойне печально, когда результаты печати неудачны по тем или иным причинам, и печать не была вовремя остановлена. Как раз о ранней остановке печати при наличии брака на столе и пойдет речь.
Creality работали в направлении ранней остановки печати, и где-то на глаза даже попадался алгоритм, но все это было сделано для другой модели принтера. Здесь же хотелось бы сделать то же самое, но для данной модели: аварийный останов печати, когда модель оторвалась от стола, появился наплыв (blob) или же принтер просто стал печатать "макароны" ни с того, ни с сего. В принципе, данный алгоритм подойдет для любого принтера, камера к которому выводит видеопоток в сеть.
Как выяснилось, интегрированная в принтер камера, "отдает" видеопоток по http (например - http://192.168.1.114:8080/?action=stream) и это уже само по себе облегчает задачу. Не нужно пытаться перехватывать картинки, улетающие в родное мобильное приложение creality. По умолчанию картинки идут туда.
Все что нужно - "читать" кадры с камеры и, при наличии аномалий, отправлять email или какое-либо уведомление. Останавливать печать программой моментально вряд ли стоит - бывает и на "старуху проруха" - аномалия может быть ложно определена.
Как же без нейросети.
Чтобы все аномалии детектировались понадобится нейросеть. yolov8 подойдет, но можно и что-то более свежее взять из семейства yolo.
Датасет (приложен к статье), на котором будет обучена нейросеть взят в открытом доступе на roboflow. В нем представлено достаточное количество картинок с аномалиями:

Обучение на датасете "стандартное" для yolo-detect моделей:
yolo task=detect mode=train model=yolov8s.pt imgsz=640 data=spagetti\data.yaml epochs=10 batch=8 name=yolov8n_custom
Здесь обучается "s" модель 8й yolo на протяжении 10 эпох. Если результат не будет удовлетворять потребностям, "s" меняем на "l" и/или увеличиваем количество эпох обучения. Как все упростилось с обучением моделей, красота!
На выходе получаем модель, которая будет использоваться в коде далее и определять аномалии. Для "лиги лени" модель также будет приложена к статье.
Программа для борьбы со "спагетти" и не только.
Рассмотрим код:
import cv2,time,os
from ultralytics import YOLO
model_yolov8 = YOLO('best3d.pt', task='detect')
#ffmpeg -i 3d_print_fail.mp4 -c:v libx264 -preset ultrafast -crf 22 output.mp4
counter=0
def yolov8_work(img,conf):
results = model_yolov8.predict(img, conf=conf, imgsz=640,verbose=False)
boxes = results[0].boxes.xyxy.tolist()
if boxes:
boxes = results[0].boxes.xyxy.tolist()
for i, box in enumerate(boxes):
x1, y1, x2, y2 = box
crop = img[int(y1):int(y2), int(x1):int(x2)]
crop = cv2.cvtColor(crop, cv2.COLOR_BGR2RGB)
cv2.imwrite(f'out/{counter}.jpg', crop)
counter+=1
url = cv2.VideoCapture('output.mp4')
#url = cv2.VideoCapture('http://192.168.1.114:8080/?action=stream')
conf=0.3
process_this_frame = True
while True:
ret, frame=url.read()
if process_this_frame:
st=time.time()
yolov8_work(frame,conf)
print(time.time()-st)
process_this_frame = not process_this_frame
В данном примере для наглядности обрабатывается ранее сохраненный timelapse сеанса 3d печати, при котором произошел сбой. При выявлении аномалии - сохраняется снимок на диск. Либо же возможно вызывать какое-либо иное событие.
Записи сеансов от creality требуют конвертации для нормальной обработки:
ffmpeg -i 3d_print_fail.mp4 -c:v libx264 -preset ultrafast -crf 22 output.mp4
Отправка уведомления на email.
Чтобы уведомить об аномалии, отправим email. Допустим на email yandex:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
now = datetime.now()
# Connect to the SMTP server
smtp_server = 'smtp.yandex.ru'
port = 587
server = smtplib.SMTP(smtp_server, port)
server.starttls()
# Login to the server
server.login('___@yandex.ru', 'password')
with open ('alarm.txt') as f:
alarm_text=f.readline().strip()
date_time = now.strftime("%d/%m/%Y, %H:%M:%S")
# Create the email message
sender_email = '______@yandex.ru'
receiver_email = '_____@yandex.ru'
message = MIMEMultipart()
message['From'] = sender_email
message['To'] = receiver_email
message['Subject'] = f'{alarm_text}'
body = f'{date_time}'
message.attach(MIMEText(body, 'plain'))
# Send the email
server.sendmail(sender_email, receiver_email, message.as_string())
# Close the connection to the SMTP server
server.quit()
На почтовый ящик будет отправляться текст cо временем выявления аномалии, с темой письма - alarm_text. Чтобы соединение с почтовым сервером yandex работало, необходимо предварительно создать пароль для приложений и поместить его в строку server.login('___@yandex.ru', 'password')
. Как это сделать, написано здесь - yandex.ru/support/id/ru/authorization/app-passwords.
Таким образом, общий код примет вид:
import cv2,time,os
from ultralytics import YOLO
model_yolov8 = YOLO('best3d.pt', task='detect')
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
now = datetime.now()
def send_alarm():
# Connect to the SMTP server
smtp_server = 'smtp.yandex.ru'
port = 587
server = smtplib.SMTP(smtp_server, port)
server.starttls()
# Login to the server
server.login('___@yandex.ru', 'password')
with open ('alarm.txt') as f:
alarm_text=f.readline().strip()
date_time = now.strftime("%d/%m/%Y, %H:%M:%S")
# Create the email message
sender_email = '______@yandex.ru'
receiver_email = '_____@yandex.ru'
message = MIMEMultipart()
message['From'] = sender_email
message['To'] = receiver_email
message['Subject'] = f'{alarm_text}'
body = f'{date_time}'
message.attach(MIMEText(body, 'plain'))
# Send the email
server.sendmail(sender_email, receiver_email, message.as_string())
# Close the connection to the SMTP server
server.quit()
counter=0
def yolov8_work(img,conf):
global counter
results = model_yolov8.predict(img, conf=conf, imgsz=640,verbose=False)
boxes = results[0].boxes.xyxy.tolist()
if boxes:
boxes = results[0].boxes.xyxy.tolist()
for i, box in enumerate(boxes):
x1, y1, x2, y2 = box
crop = img[int(y1):int(y2), int(x1):int(x2)]
crop = cv2.cvtColor(crop, cv2.COLOR_BGR2RGB)
cv2.imwrite(f'out/{counter}.jpg', crop)
send_alarm()
counter+=1
url = cv2.VideoCapture('output.mp4')
conf=0.3
process_this_frame = True
while True:
ret, frame=url.read()
if process_this_frame:
st=time.time()
yolov8_work(frame,conf)
print(time.time()-st)
process_this_frame = not process_this_frame
Одна проблема в коде - при выявлении аномалии он начнет "бомбардировку письмами" и чтобы этого не происходило, можно добавить задержку по времени при отправке или придумать что-то иное.
Спасибо за внимание. Удачной печати!
Архив программы, сеть, видео - здесь.