Python人工智慧圖控 - 研習交流廳 造訪社團 » ABS

原文網址 石小川
2020-02-18 20:45:06

繼昨天貼文 ' Python 呼叫 DLL 的方法 '後, 但能夠做甚麼呢? 下面給出Source code實例是Python模組PyCNC程式庫,我將C++運動控制驅動程式封裝給Python呼叫的範例,控制動作很流暢, 因為程式長所以就節錄部份程式碼給對控制硬體有興趣的朋友參考一下。

圖1. Python + PyQt5控制機台程式 影片 2. Python控制機台程式執行實例 影片 3. 程式控制機台實例 影片 4. TCP/IP遠距通信監控機台程式執行實例
使用Python語言做開發平台的三大動機 [語法簡單明瞭] Python語法簡單易學,最重要的是還有大量功能強大的免費模組可下載,其強大的應用層面已經發展到令人不可忽視的重要地位,甚至NASA也拿來當作航太人機介面的控制語言。早期接的專案我都是用Assembly、C、C++、C#等設計自動控制系統,這幾年我很多是改用Python來撰寫,好處是取得系統傳回的資料後,可很容易且快速的結合各種海量模組演算法發展出很專業的人工智慧機器。 [Python是跨平台語言] Python本身沒有支援特定硬體控制的功能,也正因為如此它才能夠跨平台,但這不是原罪,相反的卻是它的優點,換句話說,在x86、Arm、Arduino、PC、手機或平板等不同的作業系統環境下,相同的程式皆可以很容易互相移植過去正常執行,這 print('免費資源 + 免費的模組 + 簡單易學') 根本是一場世界革命,能不紅嗎! 綜合以上講了一大堆,無非就是要說服工程師們是該改變自已接受世界脈動的時候了,我也不例外,以此共勉之! [軟體IC] 接下來進入主題談論如何用 Python 開發一個多軸的 CNC 平台,會舉這個 CNC 專題當作例子是因為在我眼裡,CNC 其實就是一個機器人,我的經驗是 - 只要搞懂 CNC 軟硬體知識後,無論是自駕車、四軸無人機或是工具機皆是囊中物,至於想要用它做些甚麼,端看你無限的想像力而定! 因為 Python 沒有直接存取硬體的介面,我的方法是用 Python 當作主程式,將底層存取硬體的 API 程式(動態連結程式庫 DLL)封裝成Python 可調用的格式即可,如此一來多年使用 C、C++、C# 寫的程式庫都可調用了。將來使用者只要將封裝的軟體看成是黑箱直接呼叫就對了,而不須知道內部的演算法,事實上 Python 模組就是軟體IC的概念。

# -*- coding: utf-8 -*- ''' 石小川 / Michael Shih 光騰高科技工作室 / Quantum Tek. ''' import ctypes import ctypes.wintypes #------------------------------------------------------------------------------ class __IMC_EventType(): IMC_Allways = 0 #"無條件執行" IMC_Edge_Zero = 1 #"邊沿型條件執行——變為0時" IMC_Edge_NotZero = 2 #"邊沿型條件執行——變為非0時" IMC_Edge_Great = 3 #"邊沿型條件執行——變為大於時" IMC_Edge_GreatEqu = 4 #"邊沿型條件執行——變為大於等於時" IMC_Edge_Little = 5 #"邊沿型條件執行——變為小於時" IMC_Edge_Carry = 6 #"邊沿型條件執行——變為溢出時" IMC_Edge_NotCarry = 7 #"邊沿型條件執行——變為無溢出時" IMC_IF_Zero = 8 #"電位型條件執行——若為0" IMC_IF_NotZero = 9 #"電位型條件執行——若為非0" IMC_IF_Great = 10 #"電位型條件執行——若大於" IMC_IF_GreatEqu = 11 #"電位型條件執行——若大於等於" IMC_IF_Little = 12 #"電位型條件執行——若小於" IMC_IF_Carry = 13 #"電位型條件執行——若溢出" IMC_IF_NotCarry = 14 #"電位型條件執行——若無溢出" IMC_EventType = __IMC_EventType() #------------------------------------------------------------------------------ #define WR_MUL_DES, *pWR_MUL_DES class __WR_MUL_DES(ctypes.Structure): _fields_ = [ ("addr", ctypes.c_int16), ("axis", ctypes.c_uint16), ("len", ctypes.c_uint16), ("data_0", ctypes.c_uint16), ("data_1", ctypes.c_int16), ("data_2", ctypes.c_int16), ("data_3", ctypes.c_int16) ] #------------------------------------------------------------------------------ class __EventInfo(ctypes.Structure): _fields_ = [ ("EventCMD", ctypes.c_short), ("EventType", ctypes.c_short), ("Src1_loc", ctypes.c_short), ("Src1_axis", ctypes.c_short), ("Src2_loc", ctypes.c_short), ("Src2_axis", ctypes.c_short), ("reserve1", ctypes.c_int), ("dest_loc", ctypes.c_short), ("dest_axis", ctypes.c_short), ("reserve2", ctypes.c_int) ] #------------------------------------------------------------------------------ def CharArrayToList(array, num): btext = False text = "" List = [] if(num == 0): return List for i in range(len(array)): if(text != ""): btext = True if(array[i] == b'\x00'): array[i] = b'\n' text += str(array[i].decode('utf-8')) if(i%255 == 0 and btext == True): text = text.strip() text = str(text) if(len(text) > 0): List.append(text) text = "" btext = False return List #------------------------------------------------------------------------------ class __IMC_Pkg(): def __init__(self): self.ptr = ctypes.WinDLL('IMC_Pkg.dll') #_stdcall #--------------------------------------------------------------------------- def FindNetCard(self): charArray = ctypes.c_char * 4096 #16 x 2156 = 4096 array = charArray() num = ctypes.c_int() #ptr = ctypes.WinDLL('IMC_Pkg.dll') #_stdcall self.ptr.PKG_IMC_FindNetCard.argtypes = (ctypes.POINTER(charArray), ctypes.POINTER (ctypes.c_int)) self.ptr.PKG_IMC_FindNetCard.restype = ctypes.c_int status = self.ptr.PKG_IMC_FindNetCard(ctypes.byref(array), ctypes.byref(num)) return status, CharArrayToList(array, num) #--------------------------------------------------------------------------- def Open(self, netcardId, imcId): self.ptr.PKG_IMC_Open.argtypes = (ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_Open.restype = ctypes.POINTER(ctypes.c_voidp) return self.ptr.PKG_IMC_Open(netcardId, imcId) #--------------------------------------------------------------------------- def OpenX(self, netcardId, imcId, timeout, openMode): self.ptr.PKG_IMC_OpenX.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_OpenX.restype = ctypes.POINTER(ctypes.c_voidp) return self.ptr.PKG_IMC_OpenX(netcardId, imcId) #--------------------------------------------------------------------------- def OpenUsePassword(self, netcardId, imcId, password): self.ptr.PKG_IMC_OpenUsePassword.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes. c_char_p)) self.ptr.PKG_IMC_OpenUsePassword.restype = ctypes.POINTER(ctypes.c_voidp) return self.ptr.PKG_IMC_OpenUsePassword(netcardId, imcId, password) #--------------------------------------------------------------------------- def Close(self, handle): self.ptr.PKG_IMC_Close.argtypes = (ctypes.POINTER(ctypes.c_voidp), ) #單獨也必須加上括弧 self.ptr.PKG_IMC_Close.restype = ctypes.c_int return self.ptr.PKG_IMC_Close(handle) #--------------------------------------------------------------------------- def InitCfg(self, handle): self.ptr.PKG_IMC_InitCfg.argtypes = (ctypes.POINTER(ctypes.c_voidp), ) #單獨也必須加上括弧 self.ptr.PKG_IMC_InitCfg.restype = ctypes.c_int return self.ptr.PKG_IMC_InitCfg(handle) #--------------------------------------------------------------------------- def ClearIMC(self, handle): self.ptr.PKG_IMC_ClearIMC.argtypes = (ctypes.POINTER(ctypes.c_voidp), ) #單獨也必須加上括弧 self.ptr.PKG_IMC_ClearIMC.restype = ctypes.c_int return self.ptr.PKG_IMC_ClearIMC(handle) #--------------------------------------------------------------------------- def ClearAxis(self, handle, axis): self.ptr.PKG_IMC_ClearAxis.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int) self.ptr.PKG_IMC_ClearAxis.restype = ctypes.c_int return self.ptr.PKG_IMC_ClearAxis(handle, axis) #--------------------------------------------------------------------------- def SetPulWidth(self, handle, ns, axis): self.ptr.PKG_IMC_SetPulWidth.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_uint, ctypes.c_int) self.ptr.PKG_IMC_SetPulWidth.restype = ctypes.c_int return self.ptr.PKG_IMC_SetPulWidth(handle, ns, axis) #--------------------------------------------------------------------------- def SetPulPolar(self, handle, pul, dir, axis): self.ptr.PKG_IMC_SetPulPolar.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetPulPolar.restype = ctypes.c_int return self.ptr.PKG_IMC_SetPulPolar(handle, pul, dir, axis) #--------------------------------------------------------------------------- def SetEncpEna(self, handle, ena, axis): self.ptr.PKG_IMC_SetEncpEna.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetEncpEna.restype = ctypes.c_int return self.ptr.PKG_IMC_SetEncpEna(handle, ena, axis) #--------------------------------------------------------------------------- def SetEncpMode(self, handle, mode, dir, axis): self.ptr.PKG_IMC_SetEncpModer.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetEncpModer.restype = ctypes.c_int return self.ptr.PKG_IMC_SetEncpModer(handle, mode, dir, axis) #--------------------------------------------------------------------------- def SetEncpRate(self, handle, rate, axis): self.ptr.PKG_IMC_SetEncpRate.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_double, ctypes.c_int) self.ptr.PKG_IMC_SetEncpRate.restype = ctypes.c_int return self.ptr.PKG_IMC_SetEncpRate(handle, rate, axis) #--------------------------------------------------------------------------- def SetVelAccLim(self, handle, vellim, acclim, axis): self.ptr.PKG_IMC_SetVelAccLim.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_double, ctypes.c_double, ctypes.c_int) self.ptr.PKG_IMC_SetVelAccLim.restype = ctypes.c_int return self.ptr.PKG_IMC_SetVelAccLim(handle, vellim, acclim, axis) #--------------------------------------------------------------------------- def SetEna(self, handle, ena, axis): self.ptr.PKG_IMC_SetEna.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetEna.restype = ctypes.c_int return self.ptr.PKG_IMC_SetEna(handle, ena, axis) #--------------------------------------------------------------------------- def Setlimit(self, handle, plimEna, plimPolar, nlimEna, nlimPolar, axis): self.ptr.ptr.PKG_IMC_Setlimit.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int) self.ptr.ptr.PKG_IMC_Setlimit.restype = ctypes.c_int return self.ptr.PKG_IMC_Setlimit(handle, plimEna, plimPolar, nlimEna, nlimPolar, axis) #--------------------------------------------------------------------------- def SetAlm(self, handle, ena, polar, axis): self.ptr.ptr.PKG_IMC_SetAlm.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int, ctypes.c_int) self.ptr.ptr.PKG_IMC_SetAlm.restype = ctypes.c_int return self.ptr.PKG_IMC_SetAlm(handle, ena, polar, axis) #--------------------------------------------------------------------------- def SetINP(self, handle, ena, polar, axis): self.ptr.ptr.PKG_IMC_SetINP.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int, ctypes.c_int) self.ptr.ptr.PKG_IMC_SetINP.restype = ctypes.c_int return self.ptr.PKG_IMC_SetINP(handle, ena, polar, axis) #--------------------------------------------------------------------------- def SetEmstopPolar(self, handle, polar, axis): self.ptr.PKG_IMC_SetEmstopPolar.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetEmstopPolar.restype = ctypes.c_int return self.ptr.PKG_IMC_SetEmstopPolar(handle, polar, axis) #--------------------------------------------------------------------------- def SetInPolar(self, handle, polar, inPort): self.ptr.PKG_IMC_SetInPolar.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetInPolar.restype = ctypes.c_int return self.ptr.PKG_IMC_SetInPolar(handle, polar, inPort) #--------------------------------------------------------------------------- def SetStopfilt(self, handle, stop, axis): self.ptr.PKG_IMC_SetStopfilt.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetStopfilt.restype = ctypes.c_int return self.ptr.PKG_IMC_SetStopfilt(handle, stop, axis) #--------------------------------------------------------------------------- def SetExitfilt(self, handle, exit, axis): self.ptr.PKG_IMC_SetExitfilt.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetExitfilt.restype = ctypes.c_int return self.ptr.PKG_IMC_SetExitfilt(handle, exit, axis) #--------------------------------------------------------------------------- def SetRecoupRange(self, handle, range, axis): self.ptr.PKG_IMC_SetRecoupRange.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_SetRecoupRange.restype = ctypes.c_int return self.ptr.PKG_IMC_SetRecoupRange(handle, range, axis) #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- def MoveAbs(self, handle, pos, startvel, tgvel, wait, axis): self.ptr.PKG_IMC_MoveAbs.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_double, ctypes.c_double, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_MoveAbs.restype = ctypes.c_int return self.ptr.PKG_IMC_MoveAbs(handle, pos, startvel, tgvel, wait, axis) #--------------------------------------------------------------------------- def MoveAbs_P(self, handle, pos, startvel, tgvel, wait, axis): #P 輔助座標 self.ptr.PKG_IMC_MoveAbs_P.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_double, ctypes.c_double, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_MoveAbs_P.restype = ctypes.c_int return self.ptr.PKG_IMC_MoveAbs_P(handle, pos, startvel, tgvel, wait, axis) #--------------------------------------------------------------------------- def MoveDist(self, handle, dist, startvel, tgvel, wait, axis): self.ptr.PKG_IMC_MoveDist.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_double, ctypes.c_double, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_MoveDist.restype = ctypes.c_int return self.ptr.PKG_IMC_MoveDist(handle, dist, startvel, tgvel, wait, axis)

Wilson Kao
2020-02-26 15:59:35

有人有紡織業瑕疵檢測紡織的經驗嗎? 謝謝


原文網址 石小川
2020-02-14 08:43:41

使用Python語言做自動控制的方法 - I I I通信篇
網路發達後要做到機器設備遠端監控已非遙不可及了,網路通信在無人工廠的監控設備上會越來越重要。 圖中展示的系統是TCP/IP通訊協定的主從(Server-Client)式架構,TServer伺服端程式負責現場機器設備運作及回傳Sensor數據和即時影像給TClient用戶端處理。 為了方便教學緣故,已將網路封包加密演算法及帳號管理拿掉,通信程式精簡許多,比較容易理解,伺服端是以C#實作,用戶端會以C#及Python各實作一個版本。建議伺服端以C++或C#為主,而用戶端可用Python設計遠端控制APP,將來回傳的遙測大數據可很容易的用Python模組分析。
熟悉遠端操控軟硬體對將來有志設計無人工廠機器設備的朋友幫助很大,習得一技之長絕對增加競爭力。2月分我將開此TCP/IP主從式通信實作課程,因為現在病毒肆虐,採遠距教學方式較適合,沒有機器設備的同學我會提供兩台三軸機台做遠距連線操控練習,可在家寫Python程式做遠端連線操控,詳細辦法及日期我再擇期公布,歡迎有興趣的朋友來報名上課。
第五章 實作C#、Python軸控遠端機台 Python很適合做數據擷取及分析,有幾萬個套件模組讓你發揮,全世界的網路根本就是一個取之不竭,用之不盡的海量資料庫。Python 只要引入模組,要寫個爬蟲程式沒幾行代碼,就可抓你關注的網頁資料做數據分析,真的只是小菜一碟而已,這是筆者會喜歡它的原因之一 。 Python既然在人工智慧、深度學習領域都有它的蹤跡,那麼自動控制的機台也必定不會缺席的,自動化工廠的機器設備和感測器交握信號彙整起來可能有上萬種數據需要及時處理並回傳,此時Python會是一個不錯的選擇。 本章通訊系統中的伺服端仍然採用第四章的C#版本 : TServer,用戶端則是Python版本 : PyClient,理由無他,伺服端需要具備同時快速處理許多用戶及機器設備,負擔較重,建議伺服端實作還是以C++或C#為主,處理速度會快很多。 Python標準庫支援的TCP/IP稍微陽春些,筆者這裡是採用PyQt5 QtNetwork通訊模組,函式庫支援豐富,因已封裝底層API,通訊程式也比較好寫,故推薦用此方式,學習道路可少走一些遠路。 伺服端程式命名為 :TServer(C#),用戶端程式命名 : PyClient(Python)。 TServer 第四章已介紹過,在此略過, 請讀者再複習一下內文。
下列程式碼是Python版本用戶端TCP/IP通訊模組部分原始碼,有興趣的朋友歡迎報名參加遠距指導教學課程(開課日期 : 2020/02/19, 下星期三)。
# -*- coding: utf-8 -*- ''' 石小川 / Michael Shih 光騰高科技工作室 / Quantum Tek. ''' import time #OpenCV模組 import cv2 from PyQt5.QtNetwork import QTcpSocket, QHostAddress, QAbstractSocket, QNetworkInterface,\ QNetworkAddressEntry, QHostInfo,QNetworkConfiguration,\ QNetworkConfigurationManager from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtCore import Qt, QByteArray, QDataStream, QIODevice from TStream import TStream #------------------------------------------------------------------------------ #Client通信處裡類別 #------------------------------------------------------------------------------ class TcpClient(QTcpSocket): #signal define def __init__(self, parent=None): super(TcpClient, self).__init__(parent) self.__serverIP = QHostAddress() self.__serverPort = 8000 #int self.__userName = "" self.__clientSocket = None self.__pImage = None self.__chunkMode = False #切換接收mode是 command 或 chunkBytes self.__chunkCount = 0 self.__chunkLength = 0 self.__chunkBytes = QByteArray() self.__Dro = [] #------------------------------------------------------------------------ def Open(self, ip, port, userName): if not self.__serverIP.setAddress(ip): return False self.__serverPort = port self.__userName = userName if(self.__userName == ''): return False self.__clientSocket = QTcpSocket(self) self.__clientSocket.abort(); self.__clientSocket.connected.connect(self.Connected) self.__clientSocket.disconnected.connect(self.Disconnected) self.__clientSocket.readyRead.connect(self.dataReceived) self.__clientSocket.connectToHost(self.__serverIP, self.__serverPort) self.SendCommand_Connect(self.__userName) #------------------------------------------------------------------------ def Close(self): try: self.SendCommand_Disconnect(self.__userName) self.__clientSocket.disconnectFromHost() except Exception as e: print(e) #------------------------------------------------------------------------ def ListenServer(self, byteArray): stream = TStream() #byteArray Data structure : command(4) + datalength(4) + data(dataLength) if(self.__chunkMode == False): command = stream.GetPackCommand(byteArray) bData = stream.GetPackBytes(byteArray) #bData是純資料存 , 扣掉command(4)和扣掉datalength(4) length = len(bData) #接收到資料的長度 if(command == 9999): #新用戶者上線通知 data = stream.BytesToString(bData) #not used self.SendCommand_JogMode(0) elif(command == 1): #user要求對所有 Client廣播 data = stream.BytesToString(bData) #not used elif(command == 2): #//user 私密Client data = stream.BytesToString(bData) #not used elif(command == 3): #//image 需分多次接收 self.__chunkMode = True #接下來開始接收大塊資料 (>65536 都是大塊資料) self.__chunkCount = 0 self.__chunkBytes.clear() self.__isImage = False; nCols, nRows, nChannels = stream.ImageSize(bData) #一張影像大小 4(nCols) + 4(nRows) + 4(nChannels) + 320x 240 x3 = 230412 #減去已接收到的資料 (65536-4 = 65528) self.__chunkLength = nCols*nRows*nChannels + 12 self.__chunkCount = length self.__chunkBytes.append(bData) elif(command == 4): #//接收Server送來三軸位置資料 data = stream.BytesToString(bData) codes = data.split('|') #print (codes) self.__Dro.clear() for code in codes: #字串轉浮點 self.__Dro.append(float(code)) else: #chunkMode length = len(byteArray) self.__chunkCount += length self.__chunkBytes.append(byteArray) if(self.__chunkCount >= self.__chunkLength): self.__pImage = stream.ByteArrayToMat(self.__chunkBytes) self.SendCommand_Position(self.__userName) self.__chunkMode = False #切換回command模式

王登程
2020-02-14 20:16:43

如果待加工料可以自动化输送到加工台,那技术上真的可以远程加工了。


原文網址 石小川
2019-11-27 11:09:22

窮忙一陣子後今天終於可偷閒寫一下文章跟大家分享一下上回談的G-Code產生器了. 我用最簡單的CNC圓形切割來圖文解釋一下, 相信應該可以很快了解其中運作原理.

先解釋一下Entity名詞, Entity在CAD工程上是實體的意思, AutoCAD出圖後的元件我們稱為Entity, 如圓弧, 直線, 雲行線等皆是實體. 上回提過由DWG/DXF檔案 經過程式剖析分解後產生一連串Entity的資料, 如圖一, 是圓的Entity, 將它送入GCodeCircle(Entity) 函式就可很快地產生切圓的G-Code, 下面是GCodeCircle(Entity) C#版程式範例:

//-------------------------------------------------------------------------
public string GCodeCircle(EntityRecord entityrecord)
{
string gCode = "";
Point3D center = new Point3D(entityrecord.Circle.Center.X, entityrecord.Circle.Center.Y, entityrecord.Circle.Center.Z);
double radius = entityrecord.Circle.Radius;
Point3D point = new Point3D(0, 0, 0);
point.X = center.X + radius;
point.Y = center.Y;
gCode += "G00 X" + (point.X - center.X).ToString("#0.0000") + " " + "Y"+ (point.Y - center.Y).ToString("#0.0000") + " " + "Z5.0000"+ "\n";
//此段是為了說明已經簡化許多參數
gCode += "G01" + " " + "Z-1.0000"+ " " + "F200"+ "\n";
gCode += "G02" + " " + "I-"+ radius.ToString("#0.0000");
return gCode;
}

圖二是產生的G-Code, 可直接送去機器做切割一個100mm的正圓.

另外之前有位朋友問我5軸聯動切向跟隨實作問題, 我列出部分程式碼給您參考一下, 基本上我大部分實作都是圓弧直線插補ArcLine()就可完成.

//---------------------------------------------------------------------------
//圓弧直線跟隨插補
//pos : Z軸直線運動位置
//axisNum = 3, 圓弧+直線運動軸數 X Y Z
public boolArcLine(int startx, intstarty, int endx, intendy, int cx, intcy, int[] pos, int[] axis, int dir = 0, intaxisNum = 3, double acc = 10, doubletgvel = 100, double endvel = 0, doublefeedRate = 1.0, int wait = 1, intfifo = (int)FIFO_SEL.SEL_PFIFO1, boolbAbs = true)
{
int st;
if(axisNum < 2 || axisNum > MAX_NAXIS)
return false;
//清空PFIFO
st = IMC_Pkg.PKG_IMC_PFIFOclear(gHandle, fifo);
if(st == 0)
return false;
//設置加速度和進給率
if(SetPFIFO(acc, feedRate, fifo) == false)
return false;
//映射軸
st = IMC_Pkg.PKG_IMC_AxisMap(gHandle, axis, axisNum, fifo);
if(st == 0)
return false;
double dx,dy;
dx = startx - cx;
dy = starty - cy;
double r1 = Math.Sqrt(dx * dx + dy * dy);
dx = endx - cx;
dy = endy - cy;
double r2 = Math.Sqrt(dx * dx + dy * dy);
//判斷, 如果起點到圓心距離r1 != 終點到圓心距離r2 表示圓弧軌跡不正確, 跳出不執行
if(r1 != r2)
return false;
//由當前位置移動到指定位置
if(bAbs) //絕對位置
st = IMC_Pkg.PKG_IMC_ArcLine_Pos(gHandle, endx, endy, cx, cy, dir, pos, axisNum - 2, tgvel, endvel, wait, fifo); //絕對位置
else
st = IMC_Pkg.PKG_IMC_ArcLine_Dist(gHandle, endx, endy, cx, cy, dir, pos, axisNum - 2, tgvel, endvel, wait, fifo); //相對位置
if(st == 0)
return false;
return true;
}

圖三是我執行雷射切割的機台, 雷射頭是5.5W藍光雷射, 下回再分享此G-Code雷射切割成果.

p.s. 在我的APP程式直接畫圖我是直接呼叫運動卡驅動CNC, 沒有經過G-Code產生器這道手續, 加快CNC處理速度, 除非是匯入DWG/DXF檔案才會呼叫G-Code 產生器。

鍾小生
2019-11-27 12:24:32

小聲問,那套App有試用版嗎?


原文網址 石小川
2019-11-26 12:36:22

[語法簡單明瞭]
Python語法簡單易學,最重要的是還有大量功能強大的免費模組可下載,其強大的應用層面已經發展到令人不可忽視的重要地位,甚至NASA也拿來當作航太人機介面的控制語言。早期接的專案我都是用Assembly、C、C++、C#等設計自動控制系統,這幾年我很多是改用Python來撰寫,好處是取得系統傳回的資料後,可很容易且快速的結合各種海量模組演算法發展出很專業的人工智慧機器。 [Python是跨平台語言]
Python本身沒有支援特定硬體控制的功能,也正因為如此它才能夠跨平台,但這不是原罪,相反的卻是它的優點,換句話說,在x86、Arm、Arduino、PC、手機或平板等不同的作業系統環境下,相同的程式皆可以很容易互相移植過去正常執行,這 print('免費資源 + 免費的模組 + 簡單易學') 根本是一場世界革命,能不紅嗎! 綜合以上講了一大堆,無非就是要說服工程師們是該改變自已接受世界脈動的時候了,我也不例外,以此共勉之! [軟體開發]
接下來進入主題談論如何用Python開發一個多軸的CNC平台,會舉這個CNC專題當作例子是因為在我眼裡,CNC其實就是一個機器人,我的經驗是~只要搞懂CNC軟硬體知識後,無論是自駕車、四軸無人機或是工具機皆是囊中物,至於想要用它做些甚麼,端看你無限的想像力而定! 因為Python沒有直接存取硬體的介面,我的方法是用Python當作主程式,將底層存取硬體的API程式(動態連結程式庫 DLL)封裝成Python可調用的格式即可,如此一來多年使用C++/C#寫的程式庫都可引用了。因為程式很長, 為免洗板我簡略敘說過程如下: (A). 封裝DLL程式庫成PyCNC.py 模組,其中 class __IMC_Pkg()就是封裝成類別的名稱, 將來Python與機器溝通的介面就是依靠這項。 #---------------------------------------------------------------------------
#這是被呼叫的模組 : PyCNC.py
#---------------------------------------------------------------------------
#需引用ctypes
import ctypes
import ctypes.wintypes
#------------------------------------------------------------------------------
class __IMC_Pkg():
def __init__(self):
self.ptr = ctypes.WinDLL('IMC_Pkg.dll') #_stdcall
#---------------------------------------------------------------------------
def Open(self, netcardId, imcId):
self.ptr.PKG_IMC_Open.argtypes = (ctypes.c_int, ctypes.c_int)
self.ptr.PKG_IMC_Open.restype = ctypes.POINTER(ctypes.c_voidp)
return self.ptr.PKG_IMC_Open(netcardId, imcId)
#---------------------------------------------------------------------------
def Close(self, handle):
self.ptr.PKG_IMC_Close.argtypes = (ctypes.POINTER(ctypes.c_voidp), )
self.ptr.PKG_IMC_Close.restype = ctypes.c_int
return self.ptr.PKG_IMC_Close(handle)
#---------------------------------------------------------------------------
def MoveAbs(self, handle, pos, startvel, tgvel, wait, axis):
self.ptr.PKG_IMC_MoveAbs.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_double, ctypes.c_double, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_MoveAbs.restype = ctypes.c_int
return self.ptr.PKG_IMC_MoveAbs(handle, pos, startvel, tgvel, wait, axis)
#---------------------------------------------------------------------------
def MoveAbs_P(self, handle, pos, startvel, tgvel, wait, axis): #P 輔助座標
self.ptr.PKG_IMC_MoveAbs_P.argtypes = (ctypes.POINTER(ctypes.c_voidp), ctypes.c_int, ctypes.c_double, ctypes.c_double, ctypes.c_int, ctypes.c_int) self.ptr.PKG_IMC_MoveAbs_P.restype = ctypes.c_int
return self.ptr.PKG_IMC_MoveAbs_P(handle, pos, startvel, tgvel, wait, axis)
.
.
(B). 主程式motion.py 要引用也很簡單, 只要加上PyCNC.py模組,就可以調用IMC_Pkg所有的功能
#---------------------------------------------------------------------------
#這是主程式 : motion.py
#---------------------------------------------------------------------------
from CNC import PyCNC
IMC_Pkg = PyCNC.__IMC_Pkg()
#---------------------------------------------------------------------------
if(self.gHandle != None):
IMC_Pkg.Close(self.gHandle)
self.gHandle = IMC_Pkg.Open(netcardId, imcId)
if(self.gHandle != None): #//if(IsOpen())
if(IMC_Pkg.InitCfg(self.gHandle) != 0):
self.nAxis = IMC_Pkg.GetNaxis(self.gHandle) #取得設備支援軸數
p, self.Position = self.GetPosition(3) (C). 建議開發環境安裝Anaconda開發包, 在設計Python程式時可少走很多冤枉路,為了相容以前DLL程式庫,我是下載Anaconda3 - 32bit - Python3.7.3版本。 p.s. (1). IMC3xx/IMC4xx系列運動控制卡所有函數(IMC_Pkg.dll)我都有封裝成PyCNC.py以方便Python呼叫,有興趣的朋友可加入我臉書討論。 (2). 圖-1. 八軸運動+I/O+AD/DA控制卡應用圖例 圖-2. motion.py 主程式的視窗介面 影片-1. 使用motion.py 展示CNC軸控,也順便Demo飛行搖桿控制3軸及發射雷射 影片-2. 電腦執行motion.py情形 影片-3. 使用motion.py 執行G-Code,用雷射雕刻一個正圓
(3). 下回有機會再補上 : "使用Python語言做自動控制的方法 - I I 硬體篇"及 "使用Python語言做自動控制的方法 - I I I 通信篇" (UART、USB、TCP/IP)兩篇才算完整,並且教導大家如何組裝一台三軸運動控制平台的知識(機械結構及控制電路的接法),對於想創業設計自已機器的朋友不要錯過了。在臉書不適合長篇大論所以只能簡單敘述,總感覺見樹不見林,當然我也有開相關的指導課程,有興趣的朋友可上我臉書或私訊我。

Grass Lin
2019-11-26 13:12:09

感謝

Pizfinfin Albert
2019-11-26 18:32:35

我也深深有感;程式語言是積木;是工具;怎麼用工具變出創意及藝術那就是真的需要天份+努力.

林志強
2019-11-27 10:55:44

川哥
滿足我對知識的渴望


 

全不選 發文排行