Guest User

Untitled

a guest
May 6th, 2020
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.10 KB | None | 0 0
  1. # V0.002 pass2 for plasmac - slowdown for holes and other small (<= minDiameter) profiles
  2. # long non-recursive version with queue to fake look ahead (no rewinding input with tell/seek due to exising file mode)
  3. # Notes: Python queue library qsize() returns incorrect queue size. LNct is used at some point to determine remaining queue entries.
  4. import re, queue, math
  5.  
  6. LINESTRING = '{0}'
  7. HOLESTRING = '{0} ({1})'
  8. PROFILEQUEUESIZE = 1024 #probably excessive (DRAM?)
  9. ZCOMMENTS = True # add or append removed Z move to line's comment
  10.  
  11. #precision at which traverse around profile closes to be considered "closed" profile (bad CAM or intended undercut)
  12. #overcut coasting must continue along current/last segment and (if necessary) onto (the first) next segment
  13. KP_PROFILEPRECISION = 0.001 #get from plasmac or LinuxCNC?
  14.  
  15. #remove
  16. KP_KEEPEMPTYLINES = False #don't supress empty lines
  17. KP_ADDEMPTYLINES = True #empty line after every STOPCUT
  18. KP_PIERCE1 = 1 # CIP pierce
  19. KP_PIERCE0 = 0 # normal pierce
  20. #remove
  21.  
  22. # gcodes
  23. STARTCUT = 'm3'
  24. STOPCUT = 'm5'
  25. ENDJOB1 = 'm30'
  26. ENDJOB2 = 'm2'
  27. ENDJOB3 = '%'
  28. METRICUNITS = 'g21'
  29. IMPERIALUNITS = 'g20'
  30. G00MOVE = 'g0'
  31. G01MOVE = 'g1'
  32. G02MOVE = 'g2'
  33. G03MOVE = 'g3'
  34. TEMPHOLESTART ='M67 E3 Q60'
  35. HOLEEND = 'M67 E3 Q0'
  36.  
  37. PC_IMPERIAL = 1
  38. PC_METRIC = 2
  39. PC_DEFAULTMATERIAL = 0
  40. PC_HOLES0 = 0 # plasmac hole - normal, as coded
  41. PC_HOLES1 = 1 # plasmac hole - auto slowdown
  42. PC_HOLES2 = 2 # plasmac hole - auto slowdown and overcut (coast)
  43. PC_HOLEMODE = '#<holes>'
  44. PC_OVERCUT = '#<oclength>'
  45. PC_MDIA = '#<m_diameter>'
  46. PC_IDIA = '#<i_diameter>'
  47. #remove
  48. KP_PIERCE = "#<pierce>"
  49. KP_POST = "#<post>" #direcly modify CONSTANTS for easier/faster testing
  50. #remove
  51. DEBUG = True #verbose debugging text (as comments)
  52.  
  53. measuremode = PC_IMPERIAL
  54. minDiameter = 1.25 #from plasmac
  55. precision = 6 #from plasmac - check this in original code
  56. scale = 0
  57. holeEnable = overCut = False
  58. ocLength = 0.157
  59. line = rawline = commenttext =''
  60. lastG = G00MOVE #fix this!!!! and ismove() - first line should be rapid, but maybe not - catch CAM modal errors
  61. lastXmove = lastYmove = 0
  62.  
  63. firstmaterial = PC_DEFAULTMATERIAL
  64. infile = 'input2.ngc' #exising RO file in plasmac
  65. fRead = open(infile, 'r') #open input RO
  66. line = fRead.readline() #read first line
  67. pierceonlyComments = False # comment lines unnecessary for piercing that normally don't appear
  68. Zcomments = False
  69. pierceonly = True
  70. pierceMode = KP_PIERCE0
  71.  
  72. def errorout(ErrorOut):
  73. return
  74.  
  75. def removeZword(line): #move Z axis motion to (a new) comment
  76. line = line.strip()
  77. if 'z' in line:
  78. try: zword = re.search(r'(([Zz]) *(-?\d+.?\d*))',line).group(1)
  79. except: return line
  80. line = re.sub(zword,'',line)
  81. if (ZCOMMENTS):
  82. if ((')' in line) and (' (' in line)):
  83. line = line[:line.index(')')] + ' *Z removed: ' + zword + '*' + line[line.index(')'):]
  84. else:
  85. line = line + ' (*Z removed ' + zword + '*)'
  86. line = line.strip()
  87. return line
  88.  
  89. def removeNword(line): #remove line number if present
  90. line = line.strip()
  91. if (line[0:1] == 'n'):
  92. nword = re.search(r'(^([Nn]\d+) *)',line).group(1)
  93. line = re.sub(nword,'',line).strip()
  94. return line
  95.  
  96. def cleanupGandMwords(line): #remove leading zeros in G and M
  97. if ('g0' in line):
  98. line = re.sub(r'([g]0?[4])','g4',line) #fix this!!!! general regex for all Gx Mx etc.
  99. line = re.sub(r'([g]0?[3])','g3',line)
  100. line = re.sub(r'([g]0?[2])','g2',line)
  101. line = re.sub(r'([g]0?[1])','g1',line)
  102. line = re.sub(r'([g]0?[0])','g0',line)
  103. if ('m0' in line):
  104. line = re.sub(r'([m]0?[2])','m2',line)
  105. line = re.sub(r'([m]0?[3])','m3',line)
  106. line = re.sub(r'([m]0?[5])','m5',line)
  107. return line
  108.  
  109. def iscomment(line): #find comment - assumes it begins the line #fix this!!!!
  110. line = line.strip()
  111. try:
  112. if (line.index('(') < 2): #weird python error suddenly appeared with valid commented gcode line...
  113. return True
  114. except:
  115. return False
  116. return False
  117.  
  118. def apxSize(minX,maxX,minY,maxY): #pick or add method for profile vs. minDiameter
  119. #return math.sqrt((maxX - minX)**2 + (maxY - minY)**2) #diagonal line across extents of 'hole' profile
  120. return (max(maxX-minX,maxY-minY)) #longest side of 'hole' profile
  121.  
  122. def ismove(lastG): # if modal motion append it to the last G0x
  123. global line
  124. if (('x' in line) or ('y' in line)) and (not iscomment(line) and (not '#<' in line)): # fix a modal line first (global result)
  125. if (len(lastG) > 0):
  126. if((not G00MOVE in line) and (not G01MOVE in line) and (not G02MOVE in line) and (not G03MOVE in line)):
  127. line = lastG + line
  128. else:
  129. return False #fix this!!!! should result in plasmac error
  130. if((G00MOVE in line) or (G01MOVE in line) or (G02MOVE in line) or (G03MOVE in line)): # then test for motion
  131. return True
  132. return False
  133.  
  134. def getminmaxXY(minX, maxX, minY, maxY, firstX, firstY):
  135. global line, lastG
  136. x, y, lastG = getXY(line)
  137. if ((x != 0) and (y != 0)):
  138. maxX = max(x,maxX); maxY = max(y,maxY)
  139. minX = min(x,minX); minY = min(y,minY)
  140. if (firstX == 9999): firstX = x
  141. if (firstY == 9999): firstY = y
  142. return minX, maxX, minY, maxY, firstX, firstY
  143.  
  144. def getXY(line): #get G0x, X, and Y from motion line
  145. global lastG
  146.  
  147. def getXYval(selection, line): #eliminate a couple of individual fuctions with similar standalone regex
  148. if ((selection == 'x') and (selection in line)):
  149. try: x = float(re.search(r'(x) *(-?\d+.?\d*)',line).group(2))
  150. except: return 0
  151. return x
  152. if ((selection == 'y') and (selection in line)):
  153. try: y = float(re.search(r'(y) *(-?\d+.?\d*)',line).group(2))
  154. except: return 0
  155. return y
  156. return 0
  157.  
  158. x = y = 0
  159. if ismove(lastG):
  160. x = getXYval('x',line)
  161. y = getXYval('y',line)
  162. if ('g' in line):
  163. try: lastG = re.search(r'([Gg]0?[01]?)',line).group(1) # return any form of the Gxx motion command
  164. except: x = y = 0
  165. if ((x+y) == 0): #fix this - add error/null checks
  166. return x,y,''
  167. return x, y, lastG
  168.  
  169. #def getXYZIJval(selection, line):
  170. # if (selection in line):
  171. # return float(re.search(r"(' + selection + ') *(-?\d+.?\d*)",line).group(2))
  172.  
  173. def getI(line):
  174. if (('i') in line):
  175. I = float(re.search(r'(i) *(-?\d+.?\d*)',line).group(2))
  176. return I
  177.  
  178. def getJ(line):
  179. if (('j') in line):
  180. J = float(re.search(r'(j) *(-?\d+.?\d*)',line).group(2))
  181. return J
  182.  
  183. def getX(line):
  184. x , y, lastG = getXY(line)
  185. return x
  186.  
  187. def getY(line):
  188. x , y, lastG = getXY(line)
  189. return y
  190.  
  191. def identifyProfiles(G0ct,G1ct,G2ct,G3ct,LNct): #tests and exceptions for profile pre/post processing will go here
  192. global commenttext
  193. commenttext = 'Start Profile Process'
  194. if ((G0ct < 1) and (G1ct+G2ct+G3ct+LNct > 0)): #success if legal cut motion was counted
  195. return True
  196. return False
  197.  
  198. def doPierce(x,y,pierceMode):
  199. if pierceMode == (KP_PIERCE0): #fixed pierce (normal)
  200. if (DEBUG): print('( pierce only at X{0} Y{1} )'.format(x,y))
  201. print('m3 $0 s1')
  202. print('g91')
  203. print('g1 X.000001')
  204. print('g90')
  205. print('m5')
  206. if (KP_ADDEMPTYLINES):
  207. print('')
  208. #remove
  209. elif pierceMode == (KP_PIERCE1): #CIP pierce
  210. return
  211. #remove
  212. return
  213.  
  214. def commentoutline(line): #make line a comment
  215. if (('(' in line) and (')' in line) and len(line.strip()) > 2 ):
  216. line = line.replace('(','') #fix this!!!! - regex
  217. line = line.replace(')','')
  218. if (len(line.strip()) > 0):
  219. line = '( ' + line.strip() + ' )'
  220. return line
  221. else: # empty line
  222. return ''
  223.  
  224. def processProfile(lastXmove, lastYmove):
  225. global lastG, line, rawline, pierceonly, pierceonlyComments, pierceMode
  226. linequeue = queue.Queue(PROFILEQUEUESIZE) #FIFO
  227. G0ct = G1ct = G2ct = G3ct = 0
  228. LNct = 1
  229. LNclose = 0
  230. ishole = closedprofile = False
  231. maxX = maxY = -9999
  232. minX = minY = firstX = firstY = 9999
  233. firstLNct = 0
  234. dummy1 = '' #nothing
  235. firstline = secondline = lastline = closingline= ''
  236.  
  237. while ((line) and (not ENDJOB1 in line) and (not ENDJOB2 in line) and (not ENDJOB3 in line)):
  238. if ismove(lastG): #also inserts lastG before modal move
  239. minX, maxX, minY, maxY, firstX, firstY = getminmaxXY(minX, maxX, minY, maxY, firstX, firstY) # update position from current move
  240. if (STOPCUT in line):
  241. linequeue.put(line) #push last (M05) line
  242. if (pierceonly):
  243. doPierce(lastXmove, lastYmove, pierceMode) #pierce routine
  244. while(not linequeue.empty()): #empty the queue
  245. line = linequeue.get(0)
  246. if (pierceonlyComments): print(LINESTRING.format(commentoutline(line)))
  247. else: # Normal cut mode
  248. #if inside profle processing
  249. #remove
  250. if (KP_ADDEMPTYLINES):
  251. print('')
  252. #remove
  253. ishole = identifyProfiles(G0ct,G1ct,G2ct,G3ct,LNct) #doesn do anything yet except check for some cutting action
  254. if ((ishole and (apxSize(minX,maxX,minY,maxY) <= minDiameter)) and holeEnable and closedprofile): #start inside profile processing
  255. print(HOLESTRING.format(TEMPHOLESTART,commenttext))
  256. else:
  257. ishole = False
  258. firstLNct = LNct
  259. while(not linequeue.empty()): #sequentially pop all saved lines
  260. line = linequeue.get(0); LNct -= 1
  261. if (LNct == (firstLNct -1)): # profile's first move after M03 - add tests and processing here
  262. firstline = line
  263. if (LNct == (firstLNct -2)): # profile's second move after M03 - in event first was a lead
  264. secondline = line
  265. if ((LNct == 1) and ishole and holeEnable): # profile's last move before M05 - add tests and processing here
  266. lastline = line
  267. print(LINESTRING.format(line))
  268. if (overCut and holeEnable and closedprofile and (ocLength > 0)): # do overcut along first line
  269. line = line
  270. if (ishole and holeEnable and closedprofile): #end inside profile processing
  271. print(HOLESTRING.format(HOLEEND,'End Profile Process'))
  272. #remove
  273. if (KP_ADDEMPTYLINES):
  274. print('')
  275. #remove
  276. if (LNct > 2): #check for closed profile - based on destination of all moves - which won't detect a profile (loop)/CAM errors
  277. testX, testY, dummy1 = getXY(line)
  278. if ((abs(float(testX-firstX)) <= KP_PROFILEPRECISION) and (abs(float(testY - firstY)) <= KP_PROFILEPRECISION)):
  279. closedprofile = True #above tests every line for profile closure, which won't detect CAM error (profile/lead-out)
  280. closingline = line # move that closed profile (should be first line, excluding lead)
  281. LNclose = LNct #move detected to have closed profile
  282.  
  283. # check for funky gcode here - fix before queue to enable queuing fixes in sequence
  284. if (False): # 360 degree G02 and G03 arcs and split for dequeue processing
  285. line = line # fix this!!!!
  286.  
  287. linequeue.put(line) #push current line
  288. #count moves in lines to guess profile type latter - save last move type to address modal lines
  289. if (G00MOVE in line): G0ct += 1; lastG = G00MOVE #detect any G00 move(s) in cut
  290. if (G01MOVE in line): G1ct += 1; lastG = G01MOVE
  291. if (G02MOVE in line): G2ct += 1; lastG = G02MOVE
  292. if (G03MOVE in line): G3ct += 1; lastG = G03MOVE
  293. LNct += 1
  294. line = fRead.readline() #get next line
  295. line = preprocessline(line)
  296.  
  297. def ProcessOtherLines(line): #deal with anything that will not appear in cut, while tracking any g00/G01 motion
  298. global lastG, lastXmove, lastYmove, measuremode, holeEnable #function modifies lines (adds comments)
  299. global overCut, ocLength, firstmaterial, pierceMode, pierceonly
  300. global ZCOMMENTS, KP_ADDEMPTYLINES, KP_KEEPEMPTYLINES
  301. if ('g91' in line):
  302. errorout('G91')
  303. if ('g90.1' in line):
  304. errorout('g91.1')
  305. if ('m190' in line): # material
  306. try: material = re.match(r'm190 *p *(\d*)',line).group(1)
  307. except: material = PC_DEFAULTMATERIAL
  308. if (firstmaterial < 1):
  309. firstmaterial = material
  310. line = line + '( ' + 'get material name from plasmac and put here' + ' )'
  311. #Popen('halcmd setp plasmac_run.first-material {}'.format(material), stdout = PIPE, shell = True)
  312. if (IMPERIALUNITS in line): #process cut-time directives - plasmac's must begin on first line column
  313. measuremode = PC_IMPERIAL #freedom units mode
  314. if (METRICUNITS in line):
  315. measuremode = PC_METRIC #metric units mode
  316. if (PC_HOLEMODE in line): #<holes> = n
  317. try: holeval = int(re.search(r'^\#\< *holes *\> *\= *(\d*)',line).group(1))
  318. except: holeval = PC_HOLES0
  319. if (holeval == PC_HOLES0):
  320. line = line + ' (disable hole sensing)'
  321. holeEnable = overCut = False
  322. if (holeval == PC_HOLES1):
  323. line = line + ' (hole sensing - velocity reduction)'
  324. holeEnable = True ; overCut = False
  325. if (holeval == PC_HOLES2):
  326. if (ocLength > 0):
  327. holeEnable = overCut = True
  328. line = line + ' (hole sensing - velocity reduction - overcut)'
  329. else:
  330. holeEnable = True ; overCut = False
  331. line = line + ' (hole sensing - velocity reduction - overcut length = 0)'
  332. if (holeval > PC_HOLES2):
  333. line = line + ' (no hole sensing - unknown hole mode: ' + str(holeval) + ')'
  334. holeEnable = overCut = False
  335. if (PC_OVERCUT in line): #fix this!!!! scale
  336. try: ocLength = float(re.search(r'^\#\< *oclength *\> *\= *(\d*\.\d*)',line).group(1))
  337. except: ocLength = 0
  338. if (ocLength <= 0):
  339. line = line + ' (overcut value for hole mode 2 must be larger than zero)'
  340. ocLength = 0 ; overCut = False
  341. else: line = line + ' (overcut value - active with hole mode 2 only)'
  342. if (PC_MDIA in line): #fix this!!!! scale
  343. try: minDiameter = float(re.search(r'^\#\< *m_diameter *\> *\= *(\d*\.\d*)',line).group(1))
  344. except: minDiameter = 0
  345. if (minDiameter <= 0):
  346. line = line + ' (metric diameter = 0 - no hole sensing)'
  347. minDiameter = 0 ; holeEnable = overCut = False
  348. else: line = line + ' (metric diameter set for hole sensing)'
  349. if (PC_IDIA in line): #fix this!!!! scale
  350. try: minDiameter = float(re.search(r'^\#\< *i_diameter *\> *\= *(\d*\.\d*)',line).group(1))
  351. except: minDiameter = 0
  352. if (minDiameter <= 0):
  353. line = line + ' (imperial diameter = 0 - no hole sensing)'
  354. minDiameter = 0 ; holeEnable = overCut = False
  355. else: line = line + ' (imperial diameter set for hole sensing)'
  356.  
  357. #remove
  358. if (KP_PIERCE in line): #<pierce> = n
  359. try: pierceMode = int(re.search(r'^\#\< *pierce *\> *\= *(\d*)',line).group(1))
  360. except: pierceMode = KP_PIERCE0
  361. if (pierceMode == KP_PIERCE0): line = line + ' (standard pierce)'
  362. if (pierceMode == KP_PIERCE1): line = line + ' (dynamic cip pierce)'
  363.  
  364. if (KP_POST in line): #proecess post directives - modify constants
  365. if ('zcomments off' in line): ZCOMMENTS = False
  366. if ('zcomments on' in line): ZCOMMENTS = True
  367.  
  368. if ('keepemptylines off' in line): KP_KEEPEMPTYLINES = False
  369. if ('keepemptylines on' in line): KP_KEEPEMPTYLINES = True
  370.  
  371. if ('addemptylines off' in line): KP_ADDEMPTYLINES = False
  372. if ('addemptylines on' in line): KP_ADDEMPTYLINES = True
  373.  
  374. if ('pierce only off' in line): pierceonly = False
  375. if ('pierce only on' in line): pierceonly = True
  376. #remove
  377.  
  378. if ismove(lastG): lastXmove, lastYmove, lastG = getXY(line) #track position (ie: rapid moves)
  379. return line
  380.  
  381. def preprocessline(line):
  382. global rawline
  383. rawline = line #keep original available JIC
  384. line = line.lower().strip()
  385. line = removeNword(line)
  386. line = removeZword(line)
  387. line = cleanupGandMwords(line)
  388. return line
  389.  
  390. while line:
  391. line = preprocessline(line) #modifies line (moves Z, removes n-word, etc.)
  392. if (STARTCUT in line): #process M03 to M05
  393. #select the default material here if no material so kerf value is available before processing (first) profile
  394. processProfile(lastXmove, lastYmove)
  395. else: #process everything else
  396. line = ProcessOtherLines(line) #modifies line (adds comments)
  397. #remove
  398. if ((len(line) > 0) or (KP_KEEPEMPTYLINES)):
  399. #remove
  400. print(LINESTRING.format(line)) #output all non-cut lines
  401. line = fRead.readline() #get next line
  402. fRead.close()
Add Comment
Please, Sign In to add comment