commands.py
1 import linuxcnc 2 import os,sys 3 # path to the configuration the user requested 4 # used to see if the is local handler files to use 5 try: 6 CONFIGPATH = os.environ['CONFIG_DIR'] 7 CONFIGDIR = os.path.join(CONFIGPATH, 'panelui_handler.py') 8 except: 9 print '**** PANEL COMMAND: no panelui_handlers.py file in config directory' 10 CONFIGPATH = os.path.expanduser("~") 11 CONFIGDIR = os.path.join(CONFIGPATH, 'panelui_handler.py') 12 13 # constants 14 JOGJOINT = 1 15 JOGTELEOP = 0 16 17 inifile = linuxcnc.ini(os.environ['INI_FILE_NAME']) 18 trajcoordinates = inifile.find("TRAJ", "COORDINATES").lower().replace(" ","") 19 jointcount = int(inifile.find("KINS","JOINTS")) 20 21 DBG_state = 0 22 def DBG(str): 23 if DBG_state > 0: 24 print str 25 26 # Loads user commands from a file named 'panelui_handler.py' from the config 27 def load_handlers(usermod,halcomp,builder,commands,master): 28 hdl_func = 'get_handlers' 29 mod = object = None 30 def add_handler(method, f): 31 if method in handlers: 32 handlers[method].append(f) 33 else: 34 handlers[method] = [f] 35 handlers = {} 36 for u in usermod: 37 (directory,filename) = os.path.split(u) 38 (basename,extension) = os.path.splitext(filename) 39 if directory == '': 40 directory = '.' 41 if directory not in sys.path: 42 sys.path.insert(0,directory) 43 DBG( 'panelui: adding import dir %s' % directory) 44 try: 45 mod = __import__(basename) 46 except ImportError,msg: 47 print ("panelui: module '%s' skipped - import error: %s" %(basename,msg)) 48 continue 49 DBG( "panelui: module '%s' imported OK" % mod.__name__) 50 try: 51 # look for 'get_handlers' function 52 h = getattr(mod,hdl_func,None) 53 if h and callable(h): 54 DBG("panelui: module '%s' : '%s' function found" % (mod.__name__,hdl_func)) 55 objlist = h(halcomp,builder,commands,master) 56 else: 57 # the module has no get_handlers() callable. 58 # in this case we permit any callable except class Objects in the module to register as handler 59 DBG("panelui: module '%s': no '%s' function - registering only functions as callbacks" % (mod.__name__,hdl_func)) 60 objlist = [mod] 61 # extract callback candidates 62 for object in objlist: 63 #DBG("Registering handlers in module %s object %s" % (mod.__name__, object)) 64 if isinstance(object, dict): 65 methods = dict.items() 66 else: 67 methods = map(lambda n: (n, getattr(object, n, None)), dir(object)) 68 for method,f in methods: 69 if method.startswith('_'): 70 continue 71 if callable(f): 72 DBG("panelui: Register callback '%s' in %s" % (method, basename)) 73 add_handler(method, f) 74 except Exception, e: 75 print ("**** PANELUI ERROR: trouble looking for handlers in '%s': %s" %(basename, e)) 76 77 # Wrap lists in Trampoline, unwrap single functions 78 for n,v in list(handlers.items()): 79 if len(v) == 1: 80 handlers[n] = v[0] 81 else: 82 handlers[n] = Trampoline(v) 83 84 return handlers,mod,object 85 86 # trampoline and load_handlers are used for custom keyboard commands 87 class Trampoline(object): 88 def __init__(self,methods): 89 self.methods = methods 90 91 def __call__(self, *a, **kw): 92 for m in self.methods: 93 m(*a, **kw) 94 95 # linuxcnc commands 96 class CNC_COMMANDS(): 97 def __init__(self, master): 98 global DBG_state 99 DBG_state = master._dbg 100 self.emc = linuxcnc 101 self.emcstat = linuxcnc.stat() 102 self.emccommand = linuxcnc.command() 103 self.return_to_mode = -1 # if not -1 return to the mode specified 104 self.sb = 0; 105 self.jog_velocity = 100.0/60.0 106 self.angular_jog_velocity = 3600/60 107 self._mdi = 0 108 self.isjogging = [0,0,0,0,0,0,0,0,0] 109 self.restart_line_number = self.restart_reset_line = 0 110 try: 111 handlers,self.handler_module,self.handler_instance = \ 112 load_handlers([CONFIGDIR], self.emcstat, self.emccommand,self, master) 113 except Exception, e: 114 print e 115 116 def mdi_active(self, wname, m): 117 self._mdi = m 118 119 def mist_on(self, wname, b): 120 self.emccommand.mist(1) 121 122 def mist_off(self, wname, b): 123 self.emccommand.mist(0) 124 125 def flood_on(self, wname, b): 126 self.emccommand.flood(1) 127 128 def flood_off(self, wname, b): 129 self.emccommand.flood(0) 130 131 def estop(self, wname, b): 132 self.emccommand.state(self.emc.STATE_ESTOP) 133 134 def estop_reset(self, wname, b): 135 self.emccommand.state(self.emc.STATE_ESTOP_RESET) 136 137 def machine_off(self, wname, b): 138 self.emccommand.state(self.emc.STATE_OFF) 139 140 def machine_on(self, wname, b): 141 self.emccommand.state(self.emc.STATE_ON) 142 143 def home_all(self, wname, b): 144 self.emccommand.mode(self.emc.MODE_MANUAL) 145 self.emccommand.home(-1) 146 147 def unhome_all(self, wname, b): 148 self.emccommand.mode(self.emc.MODE_MANUAL) 149 self.emccommand.unhome(-1) 150 151 def home_selected(self, wname, joint): 152 self.emccommand.mode(self.emc.MODE_MANUAL) 153 self.emccommand.home(int(joint)) 154 155 def unhome_selected(self, wname, joint): 156 self.emccommand.mode(self.emc.MODE_MANUAL) 157 self.emccommand.unhome(int(joint)) 158 159 def jogging(self, wname, b): 160 self.emccommand.mode(self.emc.MODE_MANUAL) 161 162 def override_limits(self, wname, b): 163 self.emccommand.mode(self.emc.MODE_MANUAL) 164 self.emccommand.override_limits() 165 166 def spindle_forward_adjust(self, wname, rpm=100): 167 if self.get_mode() == self.emc.MODE_MDI: 168 self.emccommand.mode(self.emc.MODE_MANUAL) 169 speed = self.is_spindle_running() 170 if speed == 0: 171 self.emccommand.spindle(1,float(rpm)); 172 elif speed > 0: 173 self.emccommand.spindle(self.emc.SPINDLE_INCREASE) 174 else: 175 self.emccommand.spindle(self.emc.SPINDLE_DECREASE) 176 177 def spindle_forward(self, wname, rpm=100): 178 self.emccommand.mode(self.emc.MODE_MANUAL) 179 speed = self.is_spindle_running() 180 if speed == 0: 181 self.emccommand.spindle(1,float(rpm)); 182 183 def spindle_stop(self, wname, b): 184 self.emccommand.mode(self.emc.MODE_MANUAL) 185 self.emccommand.spindle(0); 186 187 def spindle_reverse(self, wname, rpm=100): 188 self.emccommand.mode(self.emc.MODE_MANUAL) 189 speed = self.is_spindle_running() 190 if speed == 0: 191 self.emccommand.spindle(-1,float(rpm)); 192 193 def spindle_reverse_adjust(self, wname, rpm=100): 194 if self.get_mode() == self.emc.MODE_MDI: 195 self.emccommand.mode(self.emc.MODE_MANUAL) 196 speed = self.is_spindle_running() 197 if speed == 0: 198 self.emccommand.spindle(-1,float(rpm)); 199 elif speed < 0: 200 self.emccommand.spindle(self.emc.SPINDLE_INCREASE) 201 else: 202 self.emccommand.spindle(self.emc.SPINDLE_DECREASE) 203 204 def spindle_faster(self, wname, b): 205 self.emccommand.mode(self.emc.MODE_MANUAL) 206 self.emccommand.spindle(0,self.emc.SPINDLE_INCREASE) 207 208 def spindle_slower(self, wname, b): 209 self.emccommand.mode(self.emc.MODE_MANUAL) 210 self.emccommand.spindle(0,self.emc.SPINDLE_DECREASE) 211 212 def set_linear_jog_velocity(self, wname, cmd): 213 velocity = float(cmd) 214 if velocity is not None: 215 rate = self.jog_velocity = velocity / 60.0 216 for axisnum in (0,1,2,6,7,8): 217 if self.isjogging[axisnum]: 218 jjogmode,j_or_a = self.get_jog_info(axisnum) 219 self.emccommand.jog(self.emc.JOG_CONTINUOUS, jjogmode, j_or_a, self.isjogging[i] * rate) 220 221 def set_angular_jog_velocity(self, wname, cmd): 222 angular = float(cmd) 223 if velocity is not None: 224 rate = self.angular_jog_velocity = angular / 60.0 225 for axisnum in (3,4,5): 226 if self.isjogging[axisnum]: 227 jjogmode,j_or_a = self.get_jog_info(axisnum) 228 self.emccommand.jog(self.emc.JOG_CONTINUOUS, jjogmode, j_or_a, self.isjogging[i] * rate) 229 230 def continuous_jog(self, wname, cmd): 231 axisnum = int(cmd[0]) 232 jjogmode,j_or_a = self.get_jog_info(axisnum) 233 direction = int(cmd[1]) 234 if direction == 0: 235 self.isjogging[axisnum] = 0 236 self.emccommand.jog(self.emc.JOG_STOP, jjogmode, j_or_a) 237 else: 238 if axisnum in (3,4,5): 239 rate = self.angular_jog_velocity 240 else: 241 rate = self.jog_velocity 242 self.isjogging[axisnum] = direction 243 self.emccommand.jog(self.emc.JOG_CONTINUOUS, jjogmode, j_or_a, direction * rate) 244 245 def incremental_jog(self, wname, cmd): 246 axisnum = int(cmd[0]) 247 jjogmode,j_or_a = self.get_jog_info(axisnum) 248 direction = int(cmd[1]) 249 distance = float(cmd[2]) 250 self.isjogging[axisnum] = direction 251 if axisnum in (3,4,5): 252 rate = self.angular_jog_velocity 253 else: 254 rate = self.jog_velocity 255 self.emccommand.jog(self.emc.JOG_INCREMENT, jjogmode, axisnum, direction * rate, distance) 256 self.isjogging[axisnum] = 0 257 258 def quill_up(self, wname, cmd): 259 self.emccommand.mode(self.emc.MODE_MANUAL) 260 self.emccommand.wait_complete() 261 self.mdi('G53 G0 Z %f'% float(cmd)) 262 263 def feed_hold(self, wname, cmd): 264 self.emccommand.set_feed_hold(int(cmd)) 265 266 def feed_override(self, wname, f): 267 self.emccommand.feedrate(f) 268 269 def rapid_override(self, wname, f): 270 self.emccommand.rapidrate(f) 271 272 def spindle_override(self, wname, s): 273 self.emccommand.spindleoverride(0,s) 274 275 def max_velocity(self, wname, m): 276 self.emccommand.maxvel(m) 277 278 def reload_tooltable(self, wname, b): 279 self.emccommand.load_tool_table() 280 281 def optional_stop(self, wname, cmd): 282 self.emccommand.set_optional_stop(int(cmd)) 283 284 def block_delete(self, wname, cmd): 285 self.emccommand.set_block_delete(int(cmd)) 286 287 def abort(self, wname, cmd=None): 288 self.emccommand.abort() 289 290 def pause(self, wname, cmd=None): 291 self.emccommand.auto(self.emc.AUTO_PAUSE) 292 293 def resume(self, wname, cmd=None): 294 self.emccommand.auto(self.emc.AUTO_RESUME) 295 296 def single_block(self, wname, s): 297 self.sb = s 298 self.emcstat.poll() 299 if self.emcstat.queue > 0 or self.emcstat.paused: 300 # program or mdi is running 301 if s: 302 self.emccommand.auto(self.emc.AUTO_PAUSE) 303 else: 304 self.emccommand.auto(self.emc.AUTO_RESUME) 305 306 # make sure linuxcnc is in AUTO mode 307 # if Linuxcnc is paused then pushing cycle start will step the program 308 # else the program starts from restart_line_number 309 # after restarting it resets the restart_line_number to 0. 310 # You must explicitily set a different restart line each time 311 def smart_cycle_start(self, wname, cmd=None): 312 self.emcstat.poll() 313 if self.emcstat.task_mode != self.emc.MODE_AUTO: 314 self.emccommand.mode(self.emc.MODE_AUTO) 315 self.emccommand.wait_complete() 316 self.emcstat.poll() 317 if self.emcstat.paused: 318 self.emccommand.auto(self.emc.AUTO_STEP) 319 return 320 if self.emcstat.interp_state == self.emc.INTERP_IDLE: 321 print self.restart_line_number 322 self.emccommand.auto(self.emc.AUTO_RUN, self.restart_line_number) 323 self.restart_line_number = self.restart_reset_line 324 325 # This restarts the program at the line specified directly (without cyscle start push) 326 def re_start(self, wname, line): 327 self.emccommand.mode(self.emc.MODE_AUTO) 328 self.emccommand.wait_complete() 329 self.emccommand.auto(self.emc.AUTO_RUN, line) 330 self.restart_line_number = self.restart_reset_line 331 332 # checks if ready for commands 333 # calls MDI commands and when idle, periodic() will return to the mode it was in 334 def mdi_and_return(self, wname, cmd): 335 if self.ok_for_mdi(): 336 self.return_to_mode = self.get_mode() # for periodic() 337 self.set_mdi_mode() 338 if isinstance(cmd,list): 339 for i in cmd: 340 print str(i) 341 self.emccommand.mdi(str(i)) 342 else: 343 self.emccommand.mdi(str(cmd)) 344 345 # call MDI commands, set mode if needed 346 def mdi(self, wname, cmd): 347 self.set_mdi_mode() 348 if isinstance(cmd,list): 349 for i in cmd: 350 print str(i) 351 self.emccommand.mdi(str(i)) 352 else: 353 self.emccommand.mdi(str(cmd)) 354 355 # set the restart line, you can the either restart directly 356 # or restart on the cycle start button push 357 # see above. 358 # reset option allows one to change the default restart after it next restarts 359 # eg while a restart dialog is open, always restart at the line it says 360 # when the dialog close change the line and reset both to zero 361 def set_restart_line (self, wname, line,reset=0): 362 self.restart_line_number = line 363 self.restart_reset_line = reset 364 365 def set_manual_mode(self): 366 self.emcstat.poll() 367 if self.emcstat.task_mode != self.emc.MODE_MANUAL: 368 self.emccommand.mode(self.emc.MODE_MANUAL) 369 self.emccommand.wait_complete() 370 371 def set_mdi_mode(self): 372 self.emcstat.poll() 373 if self.emcstat.task_mode != self.emc.MODE_MDI: 374 self.emccommand.mode(self.emc.MODE_MDI) 375 self.emccommand.wait_complete() 376 377 def set_auto_mode(self): 378 self.emcstat.poll() 379 if self.emcstat.task_mode != self.emc.MODE_AUTO: 380 self.emccommand.mode(self.emc.MODE_AUTO) 381 self.emccommand.wait_complete() 382 383 def get_mode(self): 384 self.emcstat.poll() 385 return self.emcstat.task_mode 386 387 def ok_for_mdi(self): 388 self.emcstat.poll() 389 s = self.emcstat 390 return not s.estop and s.enabled and s.homed and \ 391 (s.interp_state == self.emc.INTERP_IDLE) 392 393 def is_spindle_running(self): 394 self.emcstat.poll() 395 s = self.emcstat 396 if s.spindle[0]['enabled']: 397 return s.spindle[0]['speed'] 398 else: 399 return 0 400 401 def periodic(self): 402 # return mode back to preset variable, when idle 403 if self.return_to_mode > -1: 404 self.emcstat.poll() 405 if self.emcstat.interp_state == self.emc.INTERP_IDLE: 406 self.emccommand.mode(self.return_to_mode) 407 self.return_to_mode = -1 408 409 def __getitem__(self, item): 410 return getattr(self, item) 411 def __setitem__(self, item, value): 412 return setattr(self, item, value) 413 414 def get_jjogmode(self): 415 self.emcstat.poll() 416 if self.emcstat.motion_mode == linuxcnc.TRAJ_MODE_FREE: 417 return JOGJOINT 418 if self.emcstat.motion_mode == linuxcnc.TRAJ_MODE_TELEOP: 419 return JOGTELEOP 420 print "commands.py: unexpected motion_mode",self.emcstat.motion_mode 421 return JOGTELEOP 422 423 def jnum_for_axisnum(self,axisnum): 424 if self.emcstat.kinematics_type != linuxcnc.KINEMATICS_IDENTITY: 425 print ("\n%s:\n Joint jogging not supported for" 426 "non-identity kinematics"%__file__) 427 return -1 # emcJogCont() et al reject neg joint/axis no.s 428 jnum = trajcoordinates.index( "xyzabcuvw"[axisnum] ) 429 if jnum > jointcount: 430 print ("\n%s:\n Computed joint number=%d for axisnum=%d " 431 "exceeds jointcount=%d with trajcoordinates=%s" 432 %(__file__,jnum,axisnum,jointcount,trajcoordinates)) 433 # Note: primary gui should protect for this misconfiguration 434 # decline to jog 435 return -1 # emcJogCont() et al reject neg joint/axis no.s 436 return jnum 437 438 def get_jog_info (self,axisnum): 439 jjogmode = self.get_jjogmode() 440 j_or_a = axisnum 441 if jjogmode == JOGJOINT: j_or_a = self.jnum_for_axisnum(axisnum) 442 return jjogmode,j_or_a 443