眾所周知,對(duì)3D打印機(jī)感興趣的小伙伴來(lái)說(shuō),都清楚Cura是3D打印機(jī)的切片軟件,它的UI部分是基于QT來(lái)開(kāi)發(fā)的。而Cura中很多功能其實(shí)是基于插件的形式來(lái)開(kāi)發(fā),其中,用于實(shí)現(xiàn)Cura的USB轉(zhuǎn)串口聯(lián)機(jī)打印的邏輯就是一個(gè)插件,它是使用Python語(yǔ)言來(lái)實(shí)現(xiàn)的,具體代碼位于:
https://github.com/Ultimaker/Cura/tree/main/plugins/USBPrinting
之前我也做了一些3D打印機(jī)的聯(lián)機(jī)打印的開(kāi)源項(xiàng)目:
Anycubic Vyper 3D打印機(jī)串口屏改造開(kāi)源項(xiàng)目之串口屏項(xiàng)目啟動(dòng)篇(一)
Anycubic Vyper 3D打印機(jī)串口屏改造開(kāi)源項(xiàng)目之QT溫度曲線顯示(二)
而我前陣子參加開(kāi)放原子基金會(huì)組織的開(kāi)發(fā)者成長(zhǎng)激勵(lì)活動(dòng)的作品其實(shí)也算是聯(lián)機(jī)打印的一種,只是實(shí)現(xiàn)的方式不同而已罷了:
開(kāi)發(fā)者成長(zhǎng)激勵(lì)計(jì)劃-基于TencentOS Tiny FDM 3D打印機(jī)云控制系統(tǒng)方案
說(shuō)到Cura中的USB轉(zhuǎn)串口聯(lián)機(jī)打印,核心邏輯可以梳理下為以下幾點(diǎn):
(1)查找串口設(shè)備列表并獲取對(duì)應(yīng)的打印機(jī)設(shè)備端口號(hào),這部分的代碼是在USBPrinterOutputDeviceManager.py這個(gè)文件里實(shí)現(xiàn)的。
(2)設(shè)置串口設(shè)備參數(shù)并連接設(shè)備、啟動(dòng)更新線程來(lái)處理串口數(shù)據(jù)接收
具體的代碼實(shí)現(xiàn)如下:
defconnect(self): self._firmware_name=None#aftereachconnectionensurethatthefirmwarenameisremoved ifself._baud_rateisNone: ifself._use_auto_detect: auto_detect_job=AutoDetectBaudJob(self._serial_port) auto_detect_job.start() auto_detect_job.finished.connect(self._autoDetectFinished) return ifself._serialisNone: try: #設(shè)置串口參數(shù) self._serial=Serial(str(self._serial_port),self._baud_rate,timeout=self._timeout,writeTimeout=self._timeout) exceptSerialException: Logger.warning("Anexceptionoccurredwhiletryingtocreateserialconnection.") return exceptOSErrorase: Logger.warning("Theserialdeviceissuddenlyunavailablewhiletryingtocreateaserialconnection:{err}".format(err=str(e))) return CuraApplication.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() self.setConnectionState(ConnectionState.Connected) #啟動(dòng)更新線程 self._update_thread.start()
(3)啟動(dòng)更新任務(wù)線程,更新任務(wù)線程的作用是處理以下幾件事情:
以readline()的方式去接收打印機(jī)回復(fù)的數(shù)據(jù),然后處理數(shù)據(jù),例如接收到了ok或者溫度信息等。
處理接收的數(shù)據(jù),并接著發(fā)下一條Gcode指令,直到?jīng)]有得發(fā)為止。
處理打印過(guò)程中發(fā)生的異常事件
發(fā)送M105獲取溫度命令,這里Cura是做了一些處理的,發(fā)送該條命令的前提是打印機(jī)不處于忙狀態(tài)并且溫度到了設(shè)定的固件超時(shí)時(shí)間才會(huì)進(jìn)行發(fā)送。Cura的超時(shí)設(shè)置為3s。
Gcode重發(fā)機(jī)制的實(shí)現(xiàn)
具體的代碼實(shí)現(xiàn)如下:
#線程_update_thread->更新任務(wù)函數(shù)的實(shí)現(xiàn) def_update(self): whileself._connection_state==ConnectionState.Connectedandself._serialisnotNone: try: line=self._serial.readline() except: continue #獲取固件信息 #如果是Marlin,則會(huì)輸出類似如下所示的信息 #FIRMWARE_NAME:Marlin1.1.0.... ifnotself._firmware_name_requested: self._firmware_name_requested=True self.sendCommand("M115") #獲取FIRMWARE_NAME并保存起來(lái) ifb"FIRMWARE_NAME:"inline: self._setFirmwareName(line) # time()是獲取時(shí)間戳,以秒作為時(shí)間間隔,這里的timeout是3,也就意味著,Cura發(fā)送獲取溫度的條件是: #1、當(dāng)前的打印機(jī)不處于忙狀態(tài) #2、超時(shí),這里設(shè)置的時(shí)間是大于3s #以上兩個(gè)條件需要同時(shí)滿足 ifself._last_temperature_requestisNoneortime()>self._last_temperature_request+self._timeout: self.sendCommand("M105") self._last_temperature_request=time() #使用正則表達(dá)式獲取由打印機(jī)端上報(bào)的溫度事件,其中T:開(kāi)頭的數(shù)據(jù)代表噴頭溫度,B:開(kāi)頭的數(shù)據(jù)代表熱床溫度 ifre.search(b"[B|Td*]:?d+.?d*",line):#Temperaturemessage.'T:'forextruderand'B:'forbed extruder_temperature_matches=re.findall(b"T(d*):?(d+.?d*)s*/?(d+.?d*)?",line) #Updatealltemperaturevalues #獲取噴頭當(dāng)前/目標(biāo)溫度值并更新到前端顯示 matched_extruder_nrs=[] formatchinextruder_temperature_matches: extruder_nr=0 ifmatch[0]!=b"": extruder_nr=int(match[0]) ifextruder_nrinmatched_extruder_nrs: continue matched_extruder_nrs.append(extruder_nr) ifextruder_nr>=len(self._printers[0].extruders): Logger.log("w","Printerreportsmoretemperaturesthanthenumberofconfiguredextruders") continue extruder=self._printers[0].extruders[extruder_nr] ifmatch[1]: extruder.updateHotendTemperature(float(match[1])) ifmatch[2]: extruder.updateTargetHotendTemperature(float(match[2])) #獲取熱床當(dāng)前/目標(biāo)溫度值并更新到前端顯示 bed_temperature_matches=re.findall(b"B:?(d+.?d*)s*/?(d+.?d*)?",line) ifbed_temperature_matches: match=bed_temperature_matches[0] ifmatch[0]: self._printers[0].updateBedTemperature(float(match[0])) ifmatch[1]: self._printers[0].updateTargetBedTemperature(float(match[1])) #空行表示固件空閑 #多個(gè)空行可能意味著固件和Cura正在等待 #因?yàn)殄e(cuò)過(guò)了“ok”,所以我們跟蹤空行 #因?yàn)閛k可能丟掉了,所以我們需要將空行記錄下來(lái) ifline==b"": #Anemptylinemeansthatthefirmwareisidle #MultipleemptylinesprobablymeansthatthefirmwareandCuraarewaiting #foreachotherduetoamissed"ok",sowekeeptrackofemptylines self._firmware_idle_count+=1 else: self._firmware_idle_count=0 #檢查到ok字串或者_(dá)firmware_idle_count>1 ifline.startswith(b"ok")orself._firmware_idle_count>1: #此時(shí)打印機(jī)忙狀態(tài)解除 self._printer_busy=False #設(shè)置接收事件為True self._command_received.set() #如果當(dāng)前命令隊(duì)列不為空,則從隊(duì)列取出一條命令往打印機(jī)串口繼續(xù)發(fā)送 ifnotself._command_queue.empty(): self._sendCommand(self._command_queue.get()) #如果處于正在打印中,則繼續(xù)發(fā)送下一條Gcode命令 #如果此時(shí)暫停標(biāo)志生效,則什么事情都不干 elifself._is_printing: ifself._paused: pass#Nothingtodo! else: self._sendNextGcodeLine() #如果匹配到Marlin回復(fù)了"echo:busy"子串時(shí),則設(shè)置打印機(jī)為忙狀態(tài) ifline.startswith(b"echo"): self._printer_busy=True #如果在打印中接收到'!!',則表示打印機(jī)發(fā)出致命錯(cuò)誤,這個(gè)時(shí)候需要直接取消打印 ifself._is_printing: ifline.startswith(b'!!'): Logger.log('e',"Printersignalsfatalerror.Cancellingprint.{}".format(line)) self.cancelPrint() #如果在打印中接收到"resend"或者"rs"這樣的字符串,則可以通過(guò) Resend、resend 或 rs 請(qǐng)求重新發(fā)送。 elifline.lower().startswith(b"resend")orline.startswith(b"rs"): #AresendcanberequestedeitherbyResend,resendorrs. try: self._gcode_position=int(line.replace(b"N:",b"").replace(b"N",b"").replace(b":",b"").split()[-1]) except: ifline.startswith(b"rs"): #InsomecasesoftheRScommanditneedstobehandleddifferently. self._gcode_position=int(line.split()[1])
在USB轉(zhuǎn)串口聯(lián)機(jī)打印中,也實(shí)現(xiàn)了一些打印的基本業(yè)務(wù),待后續(xù)分析和開(kāi)源作品分享。
-
usb
+關(guān)注
關(guān)注
60文章
7963瀏覽量
265257 -
打印機(jī)
+關(guān)注
關(guān)注
10文章
775瀏覽量
45804 -
3D打印機(jī)
+關(guān)注
關(guān)注
9文章
527瀏覽量
44206 -
Cura
+關(guān)注
關(guān)注
0文章
5瀏覽量
2659
原文標(biāo)題:3D打印機(jī)USB聯(lián)機(jī)打印是如何實(shí)現(xiàn)的?(以Cura插件USBPrinting為例)
文章出處:【微信號(hào):嵌入式應(yīng)用研究院,微信公眾號(hào):嵌入式應(yīng)用研究院】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論