stdglue.py
1 # stdglue - canned prolog and epilog functions for the remappable builtin codes (T,M6,M61,S,F) 2 # 3 # we dont use argspec to avoid the generic error message of the argspec prolog and give more 4 # concise ones here 5 6 # cycle_prolog,cycle_epilog: generic code-independent support glue for oword sub cycles 7 # 8 # these are provided as starting point - for more concise error message you would better 9 # write a prolog specific for the code 10 # 11 # Usage: 12 #REMAP=G84.3 modalgroup=1 argspec=xyzqp prolog=cycle_prolog ngc=g843 epilog=cycle_epilog 13 14 import emccanon 15 from interpreter import * 16 throw_exceptions = 1 17 18 # REMAP=S prolog=setspeed_prolog ngc=setspeed epilog=setspeed_epilog 19 # exposed parameter: #<speed> 20 21 def setspeed_prolog(self,**words): 22 try: 23 c = self.blocks[self.remap_level] 24 if not c.s_flag: 25 self.set_errormsg("S requires a value") 26 return INTERP_ERROR 27 self.params["speed"] = c.s_number 28 except Exception,e: 29 self.set_errormsg("S/setspeed_prolog: %s)" % (e)) 30 return INTERP_ERROR 31 return INTERP_OK 32 33 def setspeed_epilog(self,**words): 34 try: 35 if not self.value_returned: 36 r = self.blocks[self.remap_level].executing_remap 37 self.set_errormsg("the %s remap procedure %s did not return a value" 38 % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) 39 return INTERP_ERROR 40 if self.return_value < -TOLERANCE_EQUAL: # 'less than 0 within interp's precision' 41 self.set_errormsg("S: remap procedure returned %f" % (self.return_value)) 42 return INTERP_ERROR 43 if self.blocks[self.remap_level].builtin_used: 44 pass 45 #print "---------- S builtin recursion, nothing to do" 46 else: 47 self.speed = self.params["speed"] 48 emccanon.enqueue_SET_SPINDLE_SPEED(self.speed) 49 return INTERP_OK 50 except Exception,e: 51 self.set_errormsg("S/setspeed_epilog: %s)" % (e)) 52 return INTERP_ERROR 53 return INTERP_OK 54 55 # REMAP=F prolog=setfeed_prolog ngc=setfeed epilog=setfeed_epilog 56 # exposed parameter: #<feed> 57 58 def setfeed_prolog(self,**words): 59 try: 60 c = self.blocks[self.remap_level] 61 if not c.f_flag: 62 self.set_errormsg("F requires a value") 63 return INTERP_ERROR 64 self.params["feed"] = c.f_number 65 except Exception,e: 66 self.set_errormsg("F/setfeed_prolog: %s)" % (e)) 67 return INTERP_ERROR 68 return INTERP_OK 69 70 def setfeed_epilog(self,**words): 71 try: 72 if not self.value_returned: 73 r = self.blocks[self.remap_level].executing_remap 74 self.set_errormsg("the %s remap procedure %s did not return a value" 75 % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) 76 return INTERP_ERROR 77 if self.blocks[self.remap_level].builtin_used: 78 pass 79 #print "---------- F builtin recursion, nothing to do" 80 else: 81 self.feed_rate = self.params["feed"] 82 emccanon.enqueue_SET_FEED_RATE(self.feed_rate) 83 return INTERP_OK 84 except Exception,e: 85 self.set_errormsg("F/setfeed_epilog: %s)" % (e)) 86 return INTERP_ERROR 87 return INTERP_OK 88 89 # REMAP=T prolog=prepare_prolog ngc=prepare epilog=prepare_epilog 90 # exposed parameters: #<tool> #<pocket> 91 92 def prepare_prolog(self,**words): 93 try: 94 cblock = self.blocks[self.remap_level] 95 if not cblock.t_flag: 96 self.set_errormsg("T requires a tool number") 97 return INTERP_ERROR 98 tool = cblock.t_number 99 if tool: 100 (status, pocket) = self.find_tool_pocket(tool) 101 if status != INTERP_OK: 102 self.set_errormsg("T%d: pocket not found" % (tool)) 103 return status 104 else: 105 pocket = -1 # this is a T0 - tool unload 106 self.params["tool"] = tool 107 self.params["pocket"] = pocket 108 return INTERP_OK 109 except Exception, e: 110 self.set_errormsg("T%d/prepare_prolog: %s" % (int(words['t']), e)) 111 return INTERP_ERROR 112 113 def prepare_epilog(self, **words): 114 try: 115 if not self.value_returned: 116 r = self.blocks[self.remap_level].executing_remap 117 self.set_errormsg("the %s remap procedure %s did not return a value" 118 % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) 119 return INTERP_ERROR 120 if self.blocks[self.remap_level].builtin_used: 121 #print "---------- T builtin recursion, nothing to do" 122 return INTERP_OK 123 else: 124 if self.return_value > 0: 125 self.selected_tool = int(self.params["tool"]) 126 self.selected_pocket = int(self.params["pocket"]) 127 emccanon.SELECT_POCKET(self.selected_pocket, self.selected_tool) 128 return INTERP_OK 129 else: 130 self.set_errormsg("T%d: aborted (return code %.1f)" % (int(self.params["tool"]),self.return_value)) 131 return INTERP_ERROR 132 except Exception, e: 133 self.set_errormsg("T%d/prepare_epilog: %s" % (tool,e)) 134 return INTERP_ERROR 135 136 # REMAP=M6 modalgroup=6 prolog=change_prolog ngc=change epilog=change_epilog 137 # exposed parameters: 138 # #<tool_in_spindle> 139 # #<selected_tool> 140 # #<current_pocket> 141 # #<selected_pocket> 142 143 def change_prolog(self, **words): 144 try: 145 # this is relevant only when using iocontrol-v2. 146 if self.params[5600] > 0.0: 147 if self.params[5601] < 0.0: 148 self.set_errormsg("Toolchanger hard fault %d" % (int(self.params[5601]))) 149 return INTERP_ERROR 150 print "change_prolog: Toolchanger soft fault %d" % int(self.params[5601]) 151 152 if self.selected_pocket < 0: 153 self.set_errormsg("M6: no tool prepared") 154 return INTERP_ERROR 155 if self.cutter_comp_side: 156 self.set_errormsg("Cannot change tools with cutter radius compensation on") 157 return INTERP_ERROR 158 self.params["tool_in_spindle"] = self.current_tool 159 self.params["selected_tool"] = self.selected_tool 160 self.params["current_pocket"] = self.current_pocket # this is probably nonsense 161 self.params["selected_pocket"] = self.selected_pocket 162 return INTERP_OK 163 except Exception, e: 164 self.set_errormsg("M6/change_prolog: %s" % (e)) 165 return INTERP_ERROR 166 167 def change_epilog(self, **words): 168 try: 169 if not self.value_returned: 170 r = self.blocks[self.remap_level].executing_remap 171 self.set_errormsg("the %s remap procedure %s did not return a value" 172 % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) 173 yield INTERP_ERROR 174 # this is relevant only when using iocontrol-v2. 175 if self.params[5600] > 0.0: 176 if self.params[5601] < 0.0: 177 self.set_errormsg("Toolchanger hard fault %d" % (int(self.params[5601]))) 178 yield INTERP_ERROR 179 print "change_epilog: Toolchanger soft fault %d" % int(self.params[5601]) 180 181 if self.blocks[self.remap_level].builtin_used: 182 #print "---------- M6 builtin recursion, nothing to do" 183 yield INTERP_OK 184 else: 185 if self.return_value > 0.0: 186 # commit change 187 self.selected_pocket = int(self.params["selected_pocket"]) 188 emccanon.CHANGE_TOOL(self.selected_pocket) 189 self.current_pocket = self.selected_pocket 190 self.selected_pocket = -1 191 self.selected_tool = -1 192 # cause a sync() 193 self.set_tool_parameters() 194 self.toolchange_flag = True 195 yield INTERP_EXECUTE_FINISH 196 else: 197 self.set_errormsg("M6 aborted (return code %.1f)" % (self.return_value)) 198 yield INTERP_ERROR 199 except Exception, e: 200 self.set_errormsg("M6/change_epilog: %s" % (e)) 201 yield INTERP_ERROR 202 203 # REMAP=M61 modalgroup=6 prolog=settool_prolog ngc=settool epilog=settool_epilog 204 # exposed parameters: #<tool> #<pocket> 205 206 def settool_prolog(self,**words): 207 try: 208 c = self.blocks[self.remap_level] 209 if not c.q_flag: 210 self.set_errormsg("M61 requires a Q parameter") 211 return INTERP_ERROR 212 tool = int(c.q_number) 213 if tool < -TOLERANCE_EQUAL: # 'less than 0 within interp's precision' 214 self.set_errormsg("M61: Q value < 0") 215 return INTERP_ERROR 216 (status,pocket) = self.find_tool_pocket(tool) 217 if status != INTERP_OK: 218 self.set_errormsg("M61 failed: requested tool %d not in table" % (tool)) 219 return status 220 self.params["tool"] = tool 221 self.params["pocket"] = pocket 222 return INTERP_OK 223 except Exception,e: 224 self.set_errormsg("M61/settool_prolog: %s)" % (e)) 225 return INTERP_ERROR 226 227 def settool_epilog(self,**words): 228 try: 229 if not self.value_returned: 230 r = self.blocks[self.remap_level].executing_remap 231 self.set_errormsg("the %s remap procedure %s did not return a value" 232 % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) 233 return INTERP_ERROR 234 235 if self.blocks[self.remap_level].builtin_used: 236 #print "---------- M61 builtin recursion, nothing to do" 237 return INTERP_OK 238 else: 239 if self.return_value > 0.0: 240 self.current_tool = int(self.params["tool"]) 241 self.current_pocket = int(self.params["pocket"]) 242 emccanon.CHANGE_TOOL_NUMBER(self.current_pocket) 243 # cause a sync() 244 self.tool_change_flag = True 245 self.set_tool_parameters() 246 else: 247 self.set_errormsg("M61 aborted (return code %.1f)" % (self.return_value)) 248 return INTERP_ERROR 249 except Exception,e: 250 self.set_errormsg("M61/settool_epilog: %s)" % (e)) 251 return INTERP_ERROR 252 253 # educational alternative: M61 remapped to an all-Python handler 254 # demo - this really does the same thing as the builtin (non-remapped) M61 255 # 256 # REMAP=M61 modalgroup=6 python=set_tool_number 257 258 def set_tool_number(self, **words): 259 try: 260 c = self.blocks[self.remap_level] 261 if c.q_flag: 262 toolno = int(c.q_number) 263 else: 264 self.set_errormsg("M61 requires a Q parameter") 265 return status 266 (status,pocket) = self.find_tool_pocket(toolno) 267 if status != INTERP_OK: 268 self.set_errormsg("M61 failed: requested tool %d not in table" % (toolno)) 269 return status 270 if words['q'] > -TOLERANCE_EQUAL: # 'greater equal 0 within interp's precision' 271 self.current_pocket = pocket 272 self.current_tool = toolno 273 emccanon.CHANGE_TOOL_NUMBER(pocket) 274 # cause a sync() 275 self.tool_change_flag = True 276 self.set_tool_parameters() 277 return INTERP_OK 278 else: 279 self.set_errormsg("M61 failed: Q=%4" % (toolno)) 280 return INTERP_ERROR 281 except Exception, e: 282 self.set_errormsg("M61/set_tool_number: %s" % (e)) 283 return INTERP_ERROR 284 285 _uvw = ("u","v","w","a","b","c") 286 _xyz = ("x","y","z","a","b","c") 287 # given a plane, return sticky words, incompatible axis words and plane name 288 # sticky[0] is also the movement axis 289 _compat = { 290 emccanon.CANON_PLANE_XY : (("z","r"),_uvw,"XY"), 291 emccanon.CANON_PLANE_YZ : (("x","r"),_uvw,"YZ"), 292 emccanon.CANON_PLANE_XZ : (("y","r"),_uvw,"XZ"), 293 emccanon.CANON_PLANE_UV : (("w","r"),_xyz,"UV"), 294 emccanon.CANON_PLANE_VW : (("u","r"),_xyz,"VW"), 295 emccanon.CANON_PLANE_UW : (("v","r"),_xyz,"UW")} 296 297 # extract and pass parameters from current block, merged with extra parameters on a continuation line 298 # keep tjose parameters across invocations 299 # export the parameters into the oword procedure 300 def cycle_prolog(self,**words): 301 # self.sticky_params is assumed to have been initialized by the 302 # init_stgdlue() method below 303 global _compat 304 try: 305 # determine whether this is the first or a subsequent call 306 c = self.blocks[self.remap_level] 307 r = c.executing_remap 308 if c.g_modes[1] == r.motion_code: 309 # first call - clear the sticky dict 310 self.sticky_params[r.name] = dict() 311 312 self.params["motion_code"] = c.g_modes[1] 313 314 (sw,incompat,plane_name) =_compat[self.plane] 315 for (word,value) in words.items(): 316 # inject current parameters 317 self.params[word] = value 318 # record sticky words 319 if word in sw: 320 if self.debugmask & 0x00080000: print "%s: record sticky %s = %.4f" % (r.name,word,value) 321 self.sticky_params[r.name][word] = value 322 if word in incompat: 323 return "%s: Cannot put a %s in a canned cycle in the %s plane" % (r.name, word.upper(), plane_name) 324 325 # inject sticky parameters which were not in words: 326 for (key,value) in self.sticky_params[r.name].items(): 327 if not key in words: 328 if self.debugmask & 0x00080000: print "%s: inject sticky %s = %.4f" % (r.name,key,value) 329 self.params[key] = value 330 331 if not "r" in self.sticky_params[r.name]: 332 return "%s: cycle requires R word" % (r.name) 333 else: 334 if self.sticky_params[r.name] <= 0.0: 335 return "%s: R word must be > 0 if used (%.4f)" % (r.name, words["r"]) 336 337 if "l" in words: 338 # checked in interpreter during block parsing 339 # if l <= 0 or l not near an int 340 self.params["l"] = words["l"] 341 342 if "p" in words: 343 p = words["p"] 344 if p < 0.0: 345 return "%s: P word must be >= 0 if used (%.4f)" % (r.name, p) 346 self.params["p"] = p 347 348 if self.feed_rate == 0.0: 349 return "%s: feed rate must be > 0" % (r.name) 350 if self.feed_mode == INVERSE_TIME: 351 return "%s: Cannot use inverse time feed with canned cycles" % (r.name) 352 if self.cutter_comp_side: 353 return "%s: Cannot use canned cycles with cutter compensation on" % (r.name) 354 return INTERP_OK 355 356 except Exception, e: 357 raise 358 return "cycle_prolog failed: %s" % (e) 359 360 # make sure the next line has the same motion code, unless overriden by a 361 # new G code 362 def cycle_epilog(self,**words): 363 try: 364 c = self.blocks[self.remap_level] 365 self.motion_mode = c.executing_remap.motion_code # retain the current motion mode 366 return INTERP_OK 367 except Exception, e: 368 return "cycle_epilog failed: %s" % (e) 369 370 # this should be called from TOPLEVEL __init__() 371 def init_stdglue(self): 372 self.sticky_params = dict()