diff --git a/my-3d/3d_print_filter.py b/my-3d/3d_print_filter.py new file mode 100644 index 0000000..9a26233 --- /dev/null +++ b/my-3d/3d_print_filter.py @@ -0,0 +1,58 @@ +#! /usr/bin/python3 +"""changes all words for controlling filament advancment 'E' to +more appropriet LinuxCNC join 'U' words +also changes argument names for the user defined M-codes""" +import sys + +def main(argv): + + openfile = open(argv, 'r') + file_in = openfile.readlines() + openfile.close() + + file_out = [] + for l in file_in: + line = l.rstrip('\n') + #print(line) + #if line[0] == ';': + # print('hej') + if line.find('E') != -1: + words = line.split(' ') + + newArray = [] + for i in words: + if i != '': + if i[0] == 'E': + i = i.replace('E', 'U', 1) + + if len(i) > 0: + newArray.append(i) + + line = ' '.join(newArray) + + elif line.find('M104 S') != -1: + line = line.replace('M104 S', 'M104 P', 1) + + elif line.find('M106 S') != -1: + line = line.replace('M106 S', 'M106 P', 1) + + elif line.find('M109 S') != -1: + line = line.replace('M109 S', 'M109 P', 1) + + elif line.find('M140 S') != -1: + line = line.replace('M140 S', 'M140 P', 1) + + # Cura seems to forget to divide the wait-value (Pxyz) with 1000 + # giving really long dwell-times + elif line.find('G4') != -1: + words = line.split('P') + words[1] = str(float(words[1])/1000) + line = 'P'.join(words) + + file_out.append(line) + + for item in file_out: + print(item) + +if __name__ == '__main__': + main(sys.argv[1]) diff --git a/my-3d/comms.py b/my-3d/comms.py new file mode 100644 index 0000000..5dd93d3 --- /dev/null +++ b/my-3d/comms.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 +# list available ports with 'python -m serial.tools.list_ports' +import serial +import watchdog + +## Default values ## +BAUDRATE = 38400 +"""Default value for the baudrate in Baud (int).""" + +PARITY = 'N' #serial.PARITY_NONE +"""Default value for the parity. See the pySerial module for documentation. Defaults to serial.PARITY_NONE""" + +BYTESIZE = 8 +"""Default value for the bytesize (int).""" + +STOPBITS = 1 +"""Default value for the number of stopbits (int).""" + +TIMEOUT = 0.05 +"""Default value for the timeout value in seconds (float).""" + +CLOSE_PORT_AFTER_EACH_CALL = False +"""Default value for port closure setting.""" + + +class Message: + """'container for messages. keeps two strings and """ + def __init__(self, name = '', data = ''): + self.name = name + self.data = data + + def __repr__(self): + return 'msg: ' + self.name + ' val: ' + self.data + + def copy(self, msg): + self.name = msg.name + self.data = msg.data + +class instrument: + """rs232 port""" + + def __init__(self, + port, + msg_handler, + watchdog_enabled = False, + watchdog_timeout = 2, + watchdog_periodicity = 0.5): + self.serial = serial.Serial() + self.serial.port = port + self.serial.baudrate = BAUDRATE + self.serial.parity = PARITY + self.serial.bytesize = BYTESIZE + self.serial.stopbits = STOPBITS + self.serial.xonxoff = False # disable software flow control + self.serial.timeout = TIMEOUT + self.portOpened = False + self.msg_hdlr = msg_handler + + self.watchdog_daemon = watchdog.WatchDogDaemon(watchdog_timeout, + watchdog_timeout, + watchdog_enabled) + self.watchdog_daemon.reset = self._watchdogClose #register watchdog reset function + self.closed_by_watchdog = False + + self.open() + + def open(self): + try: + self.serial.open() + self.portOpened = True + print('comms::opening port') + except serial.SerialException: + self.portOpened = False + print('unable to open port...') + + def close(self): + self.serial.close() + self.portOpened = False + print('comms::closeing port') + + def dataReady(self): + if self.portOpened: + return self.serial.in_waiting + else: + return False + + def readMessages(self): + """reads serial port. creates an array of events + output: array of events: + """ + if self.closed_by_watchdog: + self.closed_by_watchdog = False + self.open() + + while self.dataReady(): + msg_str = self._read().split('_', 1) + + if msg_str[0] != '': + self.msg_hdlr(Message(*msg_str)) + self.watchdog_daemon.ping() + + def generateEvent(self, name, data = ''): + self.writeMessage(Message(name, data)) + + def writeMessage(self, m): + self._write(m.name) + if m.data != '': + #self._write(m.data) + self._write('_' + str(m.data)) + + self._write('\n') + + def enableWatchdog(self, enable): + self.watchdog_daemon.setEnabled(enable) + + def _write(self, str): + if self.portOpened == True: + #serial expects a byte-array and not a string + self.serial.write(''.join(str).encode('utf-8', 'ignore')) + + def _read(self): + """ returns string read from serial port """ + b = '' + if self.portOpened == True: + b = self.serial.read_until() #blocks until '\n' received or timeout + + return b.decode('utf-8', 'ignore') #convert byte array to string + + def _watchdogClose(self): + self.closed_by_watchdog = True + self.close() + + def _is_number(self, s): + """ helper function to evaluate if input text represents an integer or not """ + try: + int(s) + return True + except ValueError: + return False + \ No newline at end of file diff --git a/my-3d/custom-m-codes/M102 b/my-3d/custom-m-codes/M102 new file mode 100644 index 0000000..7cc6bca --- /dev/null +++ b/my-3d/custom-m-codes/M102 @@ -0,0 +1,4 @@ +#!/bin/bash +# file to turn on parport pin XX to close the IO break out bord relay +halcmd setp and2.0.in1 1 +exit 0 diff --git a/my-3d/custom-m-codes/M103 b/my-3d/custom-m-codes/M103 new file mode 100644 index 0000000..7358070 --- /dev/null +++ b/my-3d/custom-m-codes/M103 @@ -0,0 +1,4 @@ +#!/bin/bash +# file to turn on parport pin XX to close the IO break out bord relay +halcmd setp and2.0.in1 0 +exit 0 diff --git a/my-3d/custom-m-codes/M104 b/my-3d/custom-m-codes/M104 new file mode 100644 index 0000000..2c6393e --- /dev/null +++ b/my-3d/custom-m-codes/M104 @@ -0,0 +1,12 @@ +#!/usr/bin/python3 +# M104: Set Extruder Temperature +import sys +import hal + +_dummy = hal.component("dummy") + +P = sys.argv[1] +setVal = str(int(float(P))) #convert from float-in-a-string to int-in-a-string +hal.set_p("my-temp-ctrl.ref-temp", setVal) + +print("M104 P" + setVal) diff --git a/my-3d/custom-m-codes/M105 b/my-3d/custom-m-codes/M105 new file mode 100644 index 0000000..35b4020 --- /dev/null +++ b/my-3d/custom-m-codes/M105 @@ -0,0 +1,3 @@ +#!/bin/bash +#do nothing +exit 0 diff --git a/my-3d/custom-m-codes/M106 b/my-3d/custom-m-codes/M106 new file mode 100644 index 0000000..c706178 --- /dev/null +++ b/my-3d/custom-m-codes/M106 @@ -0,0 +1,6 @@ +#!/bin/bash +# M106: Set Extruder fan PWM +temp=$1 +echo fan-pwm $temp +halcmd sets fan-pwm-value $temp +exit 0 diff --git a/my-3d/custom-m-codes/M107 b/my-3d/custom-m-codes/M107 new file mode 100644 index 0000000..137261b --- /dev/null +++ b/my-3d/custom-m-codes/M107 @@ -0,0 +1,4 @@ +#!/bin/bash +# M107: Fan Off +halcmd sets fan-pwm-value 0.0 +exit 0 diff --git a/my-3d/custom-m-codes/M109 b/my-3d/custom-m-codes/M109 new file mode 100644 index 0000000..0b4252f --- /dev/null +++ b/my-3d/custom-m-codes/M109 @@ -0,0 +1,28 @@ +#!/bin/bash +# M109: Set Extruder Temperature and Wait +float_ref=$1 +printf -v int_ref %.0f "$float_ref" +curr=$(halcmd getp my-temp-ctrl.curr-temp) + +halcmd setp my-temp-ctrl.ref-temp $int_ref +echo curr $curr +echo ref $int_ref + +CNT=0 +let ref=int_ref-2 +# do until reference temp is greater or equal to current temp +echo curr $curr, ref $ref +until [ $curr -ge $ref ] +do + sleep 1 + curr=$(halcmd getp my-temp-ctrl.curr-temp) + echo curr $curr, ref $ref + echo cnt $CNT + let CNT=CNT+1 + if [ "$CNT" = 60 ]; then + echo timeout + exit 0 + fi +done +echo M109 P$int_ref +exit 0 diff --git a/my-3d/custom-m-codes/M140 b/my-3d/custom-m-codes/M140 new file mode 100644 index 0000000..2437348 --- /dev/null +++ b/my-3d/custom-m-codes/M140 @@ -0,0 +1,6 @@ +#!/bin/bash +# M140: Set Bed Temperature (Fast) +v=$1 +echo bed-pwm $v +halcmd sets bed-pwm-value $v +exit 0 diff --git a/my-3d/custom-m-codes/M190 b/my-3d/custom-m-codes/M190 new file mode 100644 index 0000000..35b4020 --- /dev/null +++ b/my-3d/custom-m-codes/M190 @@ -0,0 +1,3 @@ +#!/bin/bash +#do nothing +exit 0 diff --git a/my-3d/custom-m-codes/M84 b/my-3d/custom-m-codes/M84 new file mode 100644 index 0000000..7358070 --- /dev/null +++ b/my-3d/custom-m-codes/M84 @@ -0,0 +1,4 @@ +#!/bin/bash +# file to turn on parport pin XX to close the IO break out bord relay +halcmd setp and2.0.in1 0 +exit 0 diff --git a/my-3d/custom-m-codes/disable_steppers.ngc b/my-3d/custom-m-codes/disable_steppers.ngc new file mode 100644 index 0000000..3e0df53 --- /dev/null +++ b/my-3d/custom-m-codes/disable_steppers.ngc @@ -0,0 +1,4 @@ +o sub +M103 +o endsub +M2 diff --git a/my-3d/custom-m-codes/do_nothing.ngc b/my-3d/custom-m-codes/do_nothing.ngc new file mode 100644 index 0000000..41f6847 --- /dev/null +++ b/my-3d/custom-m-codes/do_nothing.ngc @@ -0,0 +1,3 @@ +o sub +o endsub +M2 diff --git a/my-3d/custom-m-codes/enable_steppers.ngc b/my-3d/custom-m-codes/enable_steppers.ngc new file mode 100644 index 0000000..2dc1016 --- /dev/null +++ b/my-3d/custom-m-codes/enable_steppers.ngc @@ -0,0 +1,4 @@ +o sub +M102 +o endsub +M2 diff --git a/my-3d/custom-m-codes/stop_idle_hold.ngc b/my-3d/custom-m-codes/stop_idle_hold.ngc new file mode 100644 index 0000000..3e0df53 --- /dev/null +++ b/my-3d/custom-m-codes/stop_idle_hold.ngc @@ -0,0 +1,4 @@ +o sub +M103 +o endsub +M2 diff --git a/my-3d/custom.hal b/my-3d/custom.hal new file mode 100644 index 0000000..e834c7e --- /dev/null +++ b/my-3d/custom.hal @@ -0,0 +1,40 @@ +loadusr -Wn my-temp-ctrl python3 hal_extruder_temp_ctrl.py --port=/dev/ttyACM0 -c my-temp-ctrl +loadrt pwmgen output_type=0,0 +loadrt conv_float_u32 count=2 +loadrt and2 count=2 #enabling steppers, enabling extruder + +addf conv-float-u32.0 servo-thread +addf conv-float-u32.1 servo-thread +addf pwmgen.make-pulses base-thread +addf pwmgen.update servo-thread +addf and2.0 servo-thread +addf and2.1 servo-thread + +sets spindle-at-speed true + +### PWM for hot bed +# pwmgen.0.value connected and controlled in M140 +net bed-pwm-value => conv-float-u32.0.in +net bed-pwm-value => pwmgen.0.value +setp pwmgen.0.pwm-freq 100.0 +setp pwmgen.0.scale 512 #duty_cycle = (value/scale) + offset, with 1.0 meaning 100%, now with scale 1020 max duty is 25% +setp pwmgen.0.offset 0 +setp pwmgen.0.enable 1 +setp pwmgen.0.dither-pwm true +net bed-pwm-out pwmgen.0.pwm => parport.0.pin-14-out + +### PWM for extruder fan +# pwmgen.1.value connected and controlled in M106, M107 +net fan-pwm-value conv-float-u32.1.in +net fan-pwm-value pwmgen.1.value +setp pwmgen.1.pwm-freq 100.0 +setp pwmgen.1.scale 255 #duty_cycle = (value/scale) + offset, with 1.0 meaning 100% +setp pwmgen.1.offset 0 +setp pwmgen.1.enable 1 +setp pwmgen.1.dither-pwm true +net fan-pwm-out pwmgen.1.pwm => parport.0.pin-16-out + +### enable steppers +net machine-is-on halui.machine.is-on => and2.0.in0 +net and-out and2.0.out => parport.0.pin-17-out +setp and2.0.in1 1 # start enabled, in1 is written by M102(enable) and M103(disable) diff --git a/my-3d/custom_postgui.hal b/my-3d/custom_postgui.hal new file mode 100644 index 0000000..367deff --- /dev/null +++ b/my-3d/custom_postgui.hal @@ -0,0 +1,13 @@ +# Include your customized HAL commands here +# The commands in this file are run after the AXIS GUI (including PyVCP panel) starts +### enable extruder +net machine-is-on => and2.1.in0 +net enable-chkbtn and2.1.in1 <= pyvcp.enable-chkbtn +net temp-ctrl-enable and2.1.out => my-temp-ctrl.enable + +net temp-ctrl-ref my-temp-ctrl.ref-temp-out => pyvcp.ref-temp +net temp-ctrl-curr my-temp-ctrl.curr-temp => pyvcp.curr-temp + +net bed-pwm-u32value conv-float-u32.0.out => pyvcp.bed-pwm +net fan-pwm-u32value conv-float-u32.1.out => pyvcp.fan-pwm + diff --git a/my-3d/custompanel.xml b/my-3d/custompanel.xml new file mode 100644 index 0000000..58b6a75 --- /dev/null +++ b/my-3d/custompanel.xml @@ -0,0 +1,126 @@ + + + + ("Helvetica",12) + + + RIDGE + 2 + + "enable-chkbtn" + " Enable Extruder Temp Ctrl" + ("Helvetica",10) + 1 + + + + + RIDGE + 2 + + + "ref-temp" + ("Helvetica",10) + "6d" + 6 + + + + + RIDGE + 2 + + + "curr-temp" + ("Helvetica",10) + "6d" + 6 + + + + RIDGE + 2 + + + "fan-pwm" + ("Helvetica",10) + "6d" + 6 + + + + + ("Helvetica",12) + + RIDGE + 2 + + + "bed-pwm" + ("Helvetica",10) + "6d" + 6 + + + + + ("Helvetica",12) + RIDGE + 2 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hal_extruder_temp_ctrl.py b/my-3d/hal_extruder_temp_ctrl.py similarity index 100% rename from hal_extruder_temp_ctrl.py rename to my-3d/hal_extruder_temp_ctrl.py diff --git a/my-3d/linuxcnc.var b/my-3d/linuxcnc.var new file mode 100644 index 0000000..e19eb6b --- /dev/null +++ b/my-3d/linuxcnc.var @@ -0,0 +1,119 @@ +5161 0.000000 +5162 0.000000 +5163 0.000000 +5164 0.000000 +5165 0.000000 +5166 0.000000 +5167 0.000000 +5168 0.000000 +5169 0.000000 +5181 0.000000 +5182 0.000000 +5183 0.000000 +5184 0.000000 +5185 0.000000 +5186 0.000000 +5187 0.000000 +5188 0.000000 +5189 0.000000 +5210 1.000000 +5211 0.000000 +5212 0.000000 +5213 0.000000 +5214 0.000000 +5215 0.000000 +5216 0.000000 +5217 270.164780 +5218 0.000000 +5219 0.000000 +5220 1.000000 +5221 7.154117 +5222 -1.718917 +5223 0.627583 +5224 0.000000 +5225 0.000000 +5226 0.000000 +5227 0.000000 +5228 0.000000 +5229 0.000000 +5230 0.000000 +5241 0.000000 +5242 0.000000 +5243 0.000000 +5244 0.000000 +5245 0.000000 +5246 0.000000 +5247 0.000000 +5248 0.000000 +5249 0.000000 +5250 0.000000 +5261 0.000000 +5262 0.000000 +5263 0.000000 +5264 0.000000 +5265 0.000000 +5266 0.000000 +5267 0.000000 +5268 0.000000 +5269 0.000000 +5270 0.000000 +5281 0.000000 +5282 0.000000 +5283 0.000000 +5284 0.000000 +5285 0.000000 +5286 0.000000 +5287 0.000000 +5288 0.000000 +5289 0.000000 +5290 0.000000 +5301 0.000000 +5302 0.000000 +5303 0.000000 +5304 0.000000 +5305 0.000000 +5306 0.000000 +5307 0.000000 +5308 0.000000 +5309 0.000000 +5310 0.000000 +5321 0.000000 +5322 0.000000 +5323 0.000000 +5324 0.000000 +5325 0.000000 +5326 0.000000 +5327 0.000000 +5328 0.000000 +5329 0.000000 +5330 0.000000 +5341 0.000000 +5342 0.000000 +5343 0.000000 +5344 0.000000 +5345 0.000000 +5346 0.000000 +5347 0.000000 +5348 0.000000 +5349 0.000000 +5350 0.000000 +5361 0.000000 +5362 0.000000 +5363 0.000000 +5364 0.000000 +5365 0.000000 +5366 0.000000 +5367 0.000000 +5368 0.000000 +5369 0.000000 +5370 0.000000 +5381 0.000000 +5382 0.000000 +5383 0.000000 +5384 0.000000 +5385 0.000000 +5386 0.000000 +5387 0.000000 +5388 0.000000 +5389 0.000000 +5390 0.000000 diff --git a/my-3d/my-3d.hal b/my-3d/my-3d.hal new file mode 100644 index 0000000..1e9080b --- /dev/null +++ b/my-3d/my-3d.hal @@ -0,0 +1,121 @@ +# Generated by stepconf 1.1 at Fri May 1 19:07:04 2020 +# If you make changes to this file, they will be +# overwritten when you run stepconf again +loadrt [KINS]KINEMATICS +#autoconverted trivkins +loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS +loadrt hal_parport cfg="0 out" +setp parport.0.reset-time 5000 +loadrt stepgen step_type=0,0,0,0 +#loadrt pwmgen output_type=0 + +addf parport.0.read base-thread +addf stepgen.make-pulses base-thread +#addf pwmgen.make-pulses base-thread +addf parport.0.write base-thread +addf parport.0.reset base-thread + +addf stepgen.capture-position servo-thread +addf motion-command-handler servo-thread +addf motion-controller servo-thread +addf stepgen.update-freq servo-thread +#addf pwmgen.update servo-thread + +#net spindle-cmd-rpm => pwmgen.0.value +#net spindle-on <= spindle.0.on => pwmgen.0.enable +#net spindle-pwm <= pwmgen.0.pwm +#setp pwmgen.0.pwm-freq 100.0 +#setp pwmgen.0.scale 9333.33333333 +#setp pwmgen.0.offset 0.0928571428571 +#setp pwmgen.0.dither-pwm true +#net spindle-cmd-rpm <= spindle.0.speed-out +#net spindle-cmd-rpm-abs <= spindle.0.speed-out-abs +#net spindle-cmd-rps <= spindle.0.speed-out-rps +#net spindle-cmd-rps-abs <= spindle.0.speed-out-rps-abs +net spindle-at-speed => spindle.0.at-speed +#net spindle-cw <= spindle.0.forward + +net xdir => parport.0.pin-02-out +net xstep => parport.0.pin-03-out +setp parport.0.pin-03-out-reset 1 +net ydir => parport.0.pin-04-out +net ystep => parport.0.pin-05-out +setp parport.0.pin-05-out-reset 1 +setp parport.0.pin-06-out-invert 1 +net zdir => parport.0.pin-06-out +net zstep => parport.0.pin-07-out +setp parport.0.pin-07-out-reset 1 +setp parport.0.pin-08-out-invert 1 +net udir => parport.0.pin-08-out +net ustep => parport.0.pin-09-out +setp parport.0.pin-09-out-reset 1 + + +#net spindle-pwm => parport.0.pin-08-out +#net spindle-cw => parport.0.pin-17-out +net min-home-x <= parport.0.pin-11-in +net max-home-y <= parport.0.pin-10-in +net max-home-z <= parport.0.pin-12-in + +setp stepgen.0.position-scale [JOINT_0]SCALE +setp stepgen.0.steplen 1 +setp stepgen.0.stepspace 0 +setp stepgen.0.dirhold 35000 +setp stepgen.0.dirsetup 35000 +setp stepgen.0.maxaccel [JOINT_0]STEPGEN_MAXACCEL +net xpos-cmd joint.0.motor-pos-cmd => stepgen.0.position-cmd +net xpos-fb stepgen.0.position-fb => joint.0.motor-pos-fb +net xstep <= stepgen.0.step +net xdir <= stepgen.0.dir +net xenable joint.0.amp-enable-out => stepgen.0.enable +net min-home-x => joint.0.home-sw-in +net min-home-x => joint.0.neg-lim-sw-in + +setp stepgen.1.position-scale [JOINT_1]SCALE +setp stepgen.1.steplen 1 +setp stepgen.1.stepspace 0 +setp stepgen.1.dirhold 35000 +setp stepgen.1.dirsetup 35000 +setp stepgen.1.maxaccel [JOINT_1]STEPGEN_MAXACCEL +net ypos-cmd joint.1.motor-pos-cmd => stepgen.1.position-cmd +net ypos-fb stepgen.1.position-fb => joint.1.motor-pos-fb +net ystep <= stepgen.1.step +net ydir <= stepgen.1.dir +net yenable joint.1.amp-enable-out => stepgen.1.enable +net max-home-y => joint.1.home-sw-in +net max-home-y => joint.1.pos-lim-sw-in + +setp stepgen.2.position-scale [JOINT_2]SCALE +setp stepgen.2.steplen 1 +setp stepgen.2.stepspace 0 +setp stepgen.2.dirhold 35000 +setp stepgen.2.dirsetup 35000 +setp stepgen.2.maxaccel [JOINT_2]STEPGEN_MAXACCEL +net zpos-cmd joint.2.motor-pos-cmd => stepgen.2.position-cmd +net zpos-fb stepgen.2.position-fb => joint.2.motor-pos-fb +net zstep <= stepgen.2.step +net zdir <= stepgen.2.dir +net zenable joint.2.amp-enable-out => stepgen.2.enable +net max-home-z => joint.2.home-sw-in +net max-home-z => joint.2.pos-lim-sw-in + +setp stepgen.3.position-scale [JOINT_3]SCALE +setp stepgen.3.steplen 1 +setp stepgen.3.stepspace 0 +setp stepgen.3.dirhold 35000 +setp stepgen.3.dirsetup 35000 +setp stepgen.3.maxaccel [JOINT_3]STEPGEN_MAXACCEL +net upos-cmd joint.3.motor-pos-cmd => stepgen.3.position-cmd +net upos-fb stepgen.3.position-fb => joint.3.motor-pos-fb +net ustep <= stepgen.3.step +net udir <= stepgen.3.dir +net uenable joint.3.amp-enable-out => stepgen.3.enable + +net estop-out <= iocontrol.0.user-enable-out +net estop-out => iocontrol.0.emc-enable-in + +loadusr -W hal_manualtoolchange +net tool-change iocontrol.0.tool-change => hal_manualtoolchange.change +net tool-changed iocontrol.0.tool-changed <= hal_manualtoolchange.changed +net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number +net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared diff --git a/my-3d/my-3d.ini b/my-3d/my-3d.ini new file mode 100644 index 0000000..22d5321 --- /dev/null +++ b/my-3d/my-3d.ini @@ -0,0 +1,204 @@ +# This config file was created 2021-02-04 16:39:45.407451 by the update_ini script +# The original config files may be found in the /home/johan/linuxcnc/configs/test/test.old directory + +# Generated by stepconf 1.1 at Fri May 1 19:07:04 2020 +# If you make changes to this file, they will be +# overwritten when you run stepconf again + +[EMC] +# The version string for this INI file. +VERSION = 1.1 + +MACHINE = my-3d +DEBUG = 0 + +[DISPLAY] +DISPLAY = axis +EDITOR = gedit +POSITION_OFFSET = RELATIVE +POSITION_FEEDBACK = ACTUAL +ARCDIVISION = 64 +GRIDS = 10mm 20mm 50mm 100mm 1in 2in 5in 10in +MAX_FEED_OVERRIDE = 1.2 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 +DEFAULT_LINEAR_VELOCITY = 2.50 +MIN_LINEAR_VELOCITY = 0 +MAX_LINEAR_VELOCITY = 25.00 +DEFAULT_ANGULAR_VELOCITY = 36.00 +MIN_ANGULAR_VELOCITY = 0 +MAX_ANGULAR_VELOCITY = 360.00 +INTRO_GRAPHIC = linuxcnc.gif +INTRO_TIME = 5 +PROGRAM_PREFIX = /home/johan/linuxcnc/nc_files +INCREMENTS = 5mm 1mm .5mm .1mm .05mm .01mm .005mm +PYVCP = custompanel.xml +GEOMETRY = XYZ + +[FILTER] +PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image +PROGRAM_EXTENSION = .py Python Script +PROGRAM_EXTENSION = .gcode 3D Printer + +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python +gcode = python /home/johan/linuxcnc/configs/my-3d/3d_print_filter.py + +[RS274NGC] +PARAMETER_FILE = linuxcnc.var +SUBROUTINE_PATH=/home/johan/linuxcnc/configs/my-3d/custom-m-codes +USER_M_PATH=/home/johan/linuxcnc/configs/my-3d/custom-m-codes +REMAP=M17 modalgroup=10 ngc=enable_steppers +REMAP=M18 modalgroup=10 ngc=disable_steppers +REMAP=M84 modalgroup=10 ngc=stop_idle_hold +REMAP=M82 modalgroup=10 ngc=do_nothing + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 1.0 +BASE_PERIOD = 100000 +SERVO_PERIOD = 1000000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.010 + +[HAL] +HALUI = halui +HALFILE = my-3d.hal +HALFILE = custom.hal +POSTGUI_HALFILE = custom_postgui.hal + +[HALUI] + +[TRAJ] +COORDINATES = XYZU +JOINTS = 3 +HOME = 0 0 0 0 +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 25.0 +MAX_LINEAR_VELOCITY = 25.0 +DEFAULT_LINEAR_ACCELERATION = 50.0 +MAX_LINEAR_ACCELERATION = 50.0 + +[EMCIO] +EMCIO = io +CYCLE_TIME = 0.100 +TOOL_TABLE = tool.tbl + + +[KINS] +KINEMATICS = trivkins coordinates=XYZU +#This is a best-guess at the number of joints, it should be checked +JOINTS = 4 + +# X axis +#prescale = 2, steps/rev = 200, 2 mm/rev +#scale = 200*2/2 steps/mm +[AXIS_X] +MIN_LIMIT = -90.0 +MAX_LIMIT = 90.0 +MAX_VELOCITY = 25.0 +MAX_ACCELERATION = 50.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 25.0 +MAX_ACCELERATION = 50.0 +STEPGEN_MAXACCEL = 62.5 +SCALE = 200.0 +FERROR = 1 +MIN_FERROR = .25 +MIN_LIMIT = -90.0 +MAX_LIMIT = 90.0 +HOME_OFFSET = -91.400000 +HOME_SEARCH_VEL = -10.0 +HOME_LATCH_VEL = -1.50 +HOME_IGNORE_LIMITS = YES +HOME_SEQUENCE = 0 + +# Y axis +#prescale = 2, steps/rev = 200, 2 mm/rev +#scale = 200*2/2 steps/mm +[AXIS_Y] +MIN_LIMIT = -90.0 +MAX_LIMIT = 90.0 +MAX_VELOCITY = 25.0 +MAX_ACCELERATION = 50.0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 25.0 +MAX_ACCELERATION = 50.0 +STEPGEN_MAXACCEL = 62.5 +SCALE = 200.0 +FERROR = 1 +MIN_FERROR = .25 +MIN_LIMIT = -90.0 +MAX_LIMIT = 90.0 +HOME_OFFSET = 66.00000 +HOME_SEARCH_VEL = 10.0 +HOME_LATCH_VEL = 2.5 +HOME_IGNORE_LIMITS = YES +HOME_SEQUENCE = 0 + +# Z axis +#prescale = 8, steps/rev = 200, 1 mm/rev +#scale = 200*8/1 = 1600 steps/mm +[AXIS_Z] +MIN_LIMIT = -10.0 +MAX_LIMIT = 51.7 +MAX_VELOCITY = 6.0 +MAX_ACCELERATION = 50.0 + +[JOINT_2] +TYPE = LINEAR +HOME = 48.0 +MAX_VELOCITY = 6.0 +MAX_ACCELERATION = 50.0 +STEPGEN_MAXACCEL = 62.5 +SCALE = 1600.0 +FERROR = 1 +MIN_FERROR = .25 +MIN_LIMIT = -10.0 +MAX_LIMIT = 51.7 +HOME_OFFSET = 51.7 +HOME_SEARCH_VEL = 7.500000 +HOME_LATCH_VEL = 0.312500 +HOME_IGNORE_LIMITS = YES +HOME_SEQUENCE = 0 + +# U axis +#prescale = 4, steps/rev = 200, 34.069 mm/rev (D=10.85, pi*10.85=34.069) +#scale = 200*4/34.069 steps/mm +[AXIS_U] +MIN_LIMIT = -1e99 +MAX_LIMIT = 1e99 +MAX_VELOCITY = 30 +MAX_ACCELERATION = 50.0 + +[JOINT_3] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 30 +MAX_ACCELERATION = 50.0 +STEPGEN_MAXACCEL = 62.5 +SCALE = 23.5 +BACKLASH = 0.000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -1e99 +MAX_LIMIT = 1e99 +FERROR = 1 +MIN_FERROR = .25 +HOME_OFFSET = 0.0 +HOME_SEARCH_VEL = 0 +HOME_LATCH_VEL = 0 +HOME_USE_INDEX = NO +HOME_IGNORE_LIMITS = YES +HOME_SEQUENCE = 0 +HOME_IS_SHARED = NO diff --git a/my-draw.hal b/my-3d/my-draw.hal similarity index 100% rename from my-draw.hal rename to my-3d/my-draw.hal diff --git a/my-draw.ini b/my-3d/my-draw.ini similarity index 100% rename from my-draw.ini rename to my-3d/my-draw.ini diff --git a/my-3d/tool.tbl b/my-3d/tool.tbl new file mode 100644 index 0000000..507e208 --- /dev/null +++ b/my-3d/tool.tbl @@ -0,0 +1,4 @@ +T1 P1 Z50 D12.0 ;12mm end mill +T2 P2 Z24.1 D8.0 ;8mm end mill +T3 P3 Z26 D4.2 ;m5 tap drill +T99999 P99999 Z0.1 ;big tool number diff --git a/my-3d/watchdog.py b/my-3d/watchdog.py new file mode 100644 index 0000000..d780c7d --- /dev/null +++ b/my-3d/watchdog.py @@ -0,0 +1,93 @@ +#! /usr/bin/python3 +import time +import threading +import sys + +class WatchDog(): + def __init__(self, timeout): + self.timeout = timeout + self.last_ping_time = time.time() + + def ping(self): + self.last_ping_time = time.time() + + def check(self): + if time.time() - self.last_ping_time > self.timeout: + self.last_ping_time = time.time() #reset tick time + return True + else: + return False + + def insideMargin(self): + if time.time() - self.last_ping_time <= self.timeout: + return True + else: + self.last_ping_time = time.time() #reset tick time + return False + + +class WatchDogDaemon(threading.Thread): + def __init__(self, timeout, periodicity, enable = True): + self.wd = WatchDog(timeout) + self.periodicity = periodicity + self.enabled = enable + self._start() + + def _start(self): + threading.Thread.__init__(self) + self.daemon = True + self.start() + + def ping(self): + self.wd.ping() + + def run(self): + print("Starting watchdog deamon...") + while(self.enabled): + time.sleep(self.periodicity) + + if not self.wd.insideMargin(): + self.reset() + + print("stopping watchdog deamon...") + + def setEnabled(self, enabled): + if self.enabled == False and enabled == True: + self.enabled = True + self.wd.ping() # reset tick time + self._start() + + if enabled == False: + self.enabled = False + + def reset(self): + """to be overriden by client""" + pass + + +def reset(): + print('reset') + +def main(): + i = 0 + wdd = WatchDogDaemon(2, 0.5, False) + wdd.reset = reset + try: + while 1: + time.sleep(1) + print('main_' + str(i)) + print(wdd.is_alive()) + i = i+1 + + if i == 5 or i == 15: + wdd.setEnabled(True) + if i == 10: + wdd.setEnabled(False) + + wdd.ping() + + except KeyboardInterrupt: + raise SystemExit + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/my-emco-compact-5/comms.py b/my-emco-compact-5/comms.py new file mode 100644 index 0000000..62775db --- /dev/null +++ b/my-emco-compact-5/comms.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# list available ports with 'python -m serial.tools.list_ports' +import serial +import watchdog + +## Default values ## +BAUDRATE = 38400 +"""Default value for the baudrate in Baud (int).""" + +PARITY = 'N' #serial.PARITY_NONE +"""Default value for the parity. See the pySerial module for documentation. Defaults to serial.PARITY_NONE""" + +BYTESIZE = 8 +"""Default value for the bytesize (int).""" + +STOPBITS = 1 +"""Default value for the number of stopbits (int).""" + +TIMEOUT = 0.05 +"""Default value for the timeout value in seconds (float).""" + +CLOSE_PORT_AFTER_EACH_CALL = False +"""Default value for port closure setting.""" + + +class Message: + """'container for messages. keeps two strings and """ + def __init__(self, name = '', data = ''): + self.name = name + self.data = data + + def __repr__(self): + return 'msg: ' + self.name + ' val: ' + self.data + + def copy(self, msg): + self.name = msg.name + self.data = msg.data + +class instrument: + """rs232 port""" + + def __init__(self, + port, + msg_handler, + watchdog_enabled = False, + watchdog_timeout = 2, + watchdog_periodicity = 0.5): + self.serial = serial.Serial() + self.serial.port = port + self.serial.baudrate = BAUDRATE + self.serial.parity = PARITY + self.serial.bytesize = BYTESIZE + self.serial.stopbits = STOPBITS + self.serial.xonxoff = False # disable software flow control + self.serial.timeout = TIMEOUT + self.portOpened = False + self.msg_hdlr = msg_handler + + self.watchdog_daemon = watchdog.WatchDogDaemon(watchdog_timeout, + watchdog_timeout, + watchdog_enabled) + self.watchdog_daemon.reset = self._watchdogClose #register watchdog reset function + self.closed_by_watchdog = False + + self.open() + + def open(self): + try: + self.serial.open() + self.portOpened = True + print('comms::opening port') + except serial.SerialException: + self.portOpened = False + print('unable to open port...') + + def close(self): + self.serial.close() + self.portOpened = False + print('comms::closeing port') + + def dataReady(self): + if self.portOpened: + return self.serial.in_waiting + else: + return False + + def readMessages(self): + """reads serial port. creates an array of events + output: array of events: + """ + if self.closed_by_watchdog: + self.closed_by_watchdog = False + self.open() + + while self.dataReady(): + msg_str = self._read().split('_', 1) + + if msg_str[0] != '': + self.msg_hdlr(Message(*msg_str)) + self.watchdog_daemon.ping() + + def generateEvent(self, name, data = ''): + self.writeMessage(Message(name, data)) + + def writeMessage(self, m): + self._write(m.name) + if m.data != '': + #self._write(m.data) + self._write('_' + str(m.data)) + + self._write('\n') + + def enableWatchdog(self, enable): + self.watchdog_daemon.setEnabled(enable) + + def _write(self, str): + if self.portOpened == True: + #serial expects a byte-array and not a string + self.serial.write(''.join(str).encode('utf-8', 'ignore')) + + def _read(self): + """ returns string read from serial port """ + b = '' + if self.portOpened == True: + b = self.serial.read_until() #blocks until '\n' received or timeout + + return b.decode('utf-8', 'ignore') #convert byte array to string + + def _watchdogClose(self): + self.closed_by_watchdog = True + self.close() + + def _is_number(self, s): + """ helper function to evaluate if input text represents an integer or not """ + try: + int(s) + return True + except ValueError: + return False + diff --git a/my-emco-compact-5/custom-m-codes/M103 b/my-emco-compact-5/custom-m-codes/M103 new file mode 100644 index 0000000..56dcc29 --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/M103 @@ -0,0 +1,4 @@ +#!/bin/bash +# axis reload after +axis-remote --reload +exit 0 diff --git a/my-emco-compact-5/custom-m-codes/M199 b/my-emco-compact-5/custom-m-codes/M199 new file mode 100644 index 0000000..5ed5ffc --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/M199 @@ -0,0 +1,5 @@ +#!/bin/bash +# set spindle speed gain corresponding to selected motor-spindle-belt-wheel +halcmd setp scale.1.gain $1 +halcmd setp scale.1.offset $2 +exit 0 \ No newline at end of file diff --git a/my-emco-compact-5/custom-m-codes/extend_m0.ngc b/my-emco-compact-5/custom-m-codes/extend_m0.ngc new file mode 100644 index 0000000..8aa33a6 --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/extend_m0.ngc @@ -0,0 +1,37 @@ +; extend M0 to: +; turn off spindle, flood, mist if optional stop = 1 and block delete is off +; +; on cycle restart: +; turn on spindle +; turn mist on if it was on before the m1 +; turn flood on if it was on before the m1 + +o sub + ;(debug, extend_m0:) + + ; record whether mist/flood were on + # = #<_mist> + # = #<_flood> + # = #<_spindle_on> + + M5 M9 ; stop spindle, mist+flood off + + m0 (refer to builtin m0) + + ; restore mist, flood setting + o100 if [#] + m7 + o100 endif + + o200 if [#] + m8 + o200 endif + + o300 if [#] + m3 ; spindle on + o300 endif + + ;(debug, extend_m0 done) + +o endsub +m2 diff --git a/my-emco-compact-5/custom-m-codes/extend_m1.ngc b/my-emco-compact-5/custom-m-codes/extend_m1.ngc new file mode 100644 index 0000000..4b1bee9 --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/extend_m1.ngc @@ -0,0 +1,34 @@ +; extend M1 to: +; turn off spindle, flood, mist if optional stop = 1 and block delete is off +; +; on cycle restart: +; turn on spindle +; turn mist on if it was on before the m1 +; turn flood on if it was on before the m1 + +o sub +(debug, extend_m1:) + +; record whether mist/flood were on +# = #<_mist> +# = #<_flood> + +/M5 M9 ; stop spindle, mist+flood off + +/m1 (refer to builtin m1) + +; restore mist, flood setting +/o100 if [#] +/ m7 +/o100 endif + +/o200 if [#] +/ m8 +/o200 endif + +/M3 ; spindle on + +(debug, extend_m1 done) + +o endsub +m2 diff --git a/my-emco-compact-5/custom-m-codes/mysetspeed.ngc b/my-emco-compact-5/custom-m-codes/mysetspeed.ngc new file mode 100644 index 0000000..434184a --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/mysetspeed.ngc @@ -0,0 +1,31 @@ +o sub + (DEBUG, S# setspeed) + o10 if [# LE 950] + o11 if [#4997 NE 1] + (MSG, Set spindle speed selection belt in AC1 position) + O call [0.48483] [20.16466] + #4997 = 1 + o11 endif + o10 else + o20 if [# LE 1500] + o21 if [#4997 NE 2] + (MSG, Set spindle speed selection belt in AC2 position) + O call [0.32571] [-8.05714] + #4997 = 2 + o21 endif + o20 else + o30 if [# LE 2400] + o31 if [#4997 NE 3] + (MSG, Set spindle speed selection belt in AC3 position) + O call [0.20098] [22.64117] + #4997 = 3 + o31 endif + o30 else + (MSG, Unsupported spindle speed. will continue anyway. Safest is probably to abort and regenerate program) + o30 endif + o20 endif + o10 endif + S# + M0 +o endsub [1] +M2 diff --git a/my-emco-compact-5/custom-m-codes/myspindlegain.ngc b/my-emco-compact-5/custom-m-codes/myspindlegain.ngc new file mode 100644 index 0000000..be08e27 --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/myspindlegain.ngc @@ -0,0 +1,6 @@ +o sub + M199 P#1 Q#2 + #4998 = #1 + #4999 = #2 +o endsub +M2 diff --git a/my-emco-compact-5/custom-m-codes/myspindlespeeddown.ngc b/my-emco-compact-5/custom-m-codes/myspindlespeeddown.ngc new file mode 100644 index 0000000..c3db13b --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/myspindlespeeddown.ngc @@ -0,0 +1,12 @@ +o sub + o10 if [#<_spindle_on> EQ 1] + O20 if [#<_rpm> GT 100] + # = [#<_rpm> - 100] + O20 else + # = 0 + M5 + O20 endif + S# + o10 endif +o endsub +M2 diff --git a/my-emco-compact-5/custom-m-codes/myspindlespeedup.ngc b/my-emco-compact-5/custom-m-codes/myspindlespeedup.ngc new file mode 100644 index 0000000..524a5f4 --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/myspindlespeedup.ngc @@ -0,0 +1,11 @@ +o sub + ;o10 if [#<_spindle_on> EQ 1] + # = [#<_rpm>+100] + O10 if [# GT 4500] + # = 4500 + O10 endif + S# + M3 + ;o10 endif +o endsub +M2 diff --git a/my-emco-compact-5/custom-m-codes/myspindlestart.ngc b/my-emco-compact-5/custom-m-codes/myspindlestart.ngc new file mode 100644 index 0000000..7efa9a8 --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/myspindlestart.ngc @@ -0,0 +1,10 @@ +o sub + o10 if [#<_spindle_on> EQ 1] + M5 + o10 else + S800 + M3 + o10 endif + ;M103 +o endsub +M2 \ No newline at end of file diff --git a/my-emco-compact-5/custom-m-codes/mytouch.ngc b/my-emco-compact-5/custom-m-codes/mytouch.ngc new file mode 100644 index 0000000..3f1f92c --- /dev/null +++ b/my-emco-compact-5/custom-m-codes/mytouch.ngc @@ -0,0 +1,23 @@ +o sub + o10 if [EXISTS[#<_hal[jog-axis-sel]>]] + # = #<_hal[jog-axis-sel]> + ;(DEBUG, my-mpg.axis-selector: #) + + (touch off) + o20 if [# EQ 0] + G10 L20 P0 X0 + M103 + (MSG, touch off x axis) + o20 endif + + (touch off z axis) + o30 if [# EQ 1] + G10 L20 P0 Z0 + M103 + (MSG, touch off z axis) + o30 endif + o10 else + (DEBUG, didn't exist) + o10 endif +o endsub +M2 diff --git a/my-emco-compact-5/custom.hal b/my-emco-compact-5/custom.hal new file mode 100644 index 0000000..5deafb3 --- /dev/null +++ b/my-emco-compact-5/custom.hal @@ -0,0 +1,127 @@ +# Include your custom HAL commands here +# This file will not be overwritten when you run stepconf again +loadrt near names=spindle-at-speed +loadrt siggen num_chan=1 #spincle speed control +loadrt and2 count=4 # 0 used in e-stop chain, + # 1,2,3 used för connecting spindle speed gain selection +loadrt classicladder_rt +loadrt timedelay count=1 + +addf spindle-at-speed servo-thread +addf scale.1 servo-thread +addf scale.2 servo-thread +addf scale.3 servo-thread +addf scale.4 servo-thread +addf siggen.0.update servo-thread +addf and2.0 servo-thread +addf and2.1 servo-thread +addf and2.2 servo-thread +addf and2.3 servo-thread +addf classicladder.0.refresh servo-thread +addf timedelay.0 servo-thread + +loadusr -Wn my-mpg python3 serialEventHandler.py --port=/dev/ttyUSB0 -c my-mpg mpg.xml +loadusr classicladder test_ladder.clp --nogui +#loadusr classicladder test_ladder.clp + +### spindle at speed monitoring ### +setp spindle-at-speed.scale 0.98 +setp spindle-at-speed.difference 10 +net spindle-cmd-rpm => spindle-at-speed.in1 +#net spindle-rpm-filtered-low-res => spindle-at-speed.in2 # moved to postgui + +### temp... until encoder works... +#net spindle-ready <= spindle-at-speed.out => spindle.0.at-speed +net spindle-ready => spindle.0.at-speed +sets spindle-ready 1 +### + +### spindle cw start/stop ### +net spindle-cw <= spindle.0.forward +net spindle-cw => parport.0.pin-14-out # turn on spindle +### spindle ccw start/stop ### +net spindle-ccw <= spindle.0.reverse +net spindle-ccw => parport.0.pin-17-out # turn on spindle ccw + +### spindle speed ctrl ### +# gain and offset is set via M199/O when homed +#setp scale.1.gain 0.473 +#setp scale.1.offset 26.5 +setp siggen.0.amplitude 1 +setp siggen.0.offset 0 + +net spindle-cmd-rpm-abs => scale.1.in +net scaled-spindle-cmd scale.1.out => siggen.0.frequency +net spindle-freq siggen.0.clock => parport.0.pin-16-out + + +### e-stop chain ### +net estop-internal <= iocontrol.0.user-enable-out +#estop-external connected to parport.0.pin-11-in-not + +net estop-internal => and2.0.in0 +net estop-external => and2.0.in1 +net estop-chain and2.0.out => iocontrol.0.emc-enable-in + + +### pendant ########################################## + +# mpg spindle speed control +net spindle-rpm-cmd-up classicladder.0.out-08 halui.mdi-command-00 +net spindle-rpm-cmd-down classicladder.0.out-09 halui.mdi-command-01 + +# axis selector connects to x, z axis enable +net jog-axis-sel my-mpg.axis-selector +net jog-axis-sel classicladder.0.s32in-00 + +net jog-x-enable classicladder.0.out-00 +net jog-z-enable classicladder.0.out-01 +net jog-x-enable halui.axis.x.select +net jog-z-enable halui.axis.z.select + +# jog scale selector/velocity mode +setp scale.2.gain 0.01 +setp scale.2.offset 0 +net jog-scale-sel my-mpg.scale-selector +net jog-scale-sel classicladder.0.s32in-01 +net jog-increment-100 classicladder.0.floatout-00 scale.2.in +net jog-increment halui.axis.selected.increment scale.2.out + +# jogging plus and minus +setp halui.axis.jog-speed 800 +net mpg-jog-plus-in my-mpg.jog-pos-btn => classicladder.0.in-00 +net mpg-jog-minus-in my-mpg.jog-neg-btn => classicladder.0.in-01 + +net mpg-jog-plus-inc classicladder.0.out-04 => halui.axis.selected.increment-plus +net mpg-jog-minus-inc classicladder.0.out-06 => halui.axis.selected.increment-minus +net mpg-jog-plus classicladder.0.out-05 => halui.axis.selected.plus +net mpg-jog-minus classicladder.0.out-07 => halui.axis.selected.minus + +# connect Func-button +net func-button my-mpg.func-btn halui.mdi-command-02 + +# connect E-Stop button +net estop-button halui.estop.activate <= my-mpg.estop-btn + +# joystic +setp scale.3.gain 0.01 +setp scale.3.offset 0 +setp scale.4.gain 0.01 +setp scale.4.offset 0 +net joystick-x my-mpg.joystick-x scale.3.in +net joystick-x-scaled scale.3.out halui.axis.x.analog + +net joystick-z my-mpg.joystick-z scale.4.in +net joystick-z-scaled scale.4.out halui.axis.z.analog + +### Misc ################################################# + +# all-homed used to enable some of the panels and trigger some other stuff +net all-homed motion.is-all-homed + +# set the saved spindle speed selection gain +#setp timedelay.0.on-delay 1 +net all-homed timedelay.0.in +net all-homed-delayed timedelay.0.out +net all-homed-delayed halui.mdi-command-06 + diff --git a/my-emco-compact-5/custom_postgui.hal b/my-emco-compact-5/custom_postgui.hal new file mode 100644 index 0000000..b4383ee --- /dev/null +++ b/my-emco-compact-5/custom_postgui.hal @@ -0,0 +1,18 @@ +# Include your custom_postgui HAL commands here +# This file will not be overwritten when you run stepconf again + +# Filtering and scaling... +setp encoder.1.counter-mode true +setp encoder.1.position-scale 1 +setp scale.0.gain 60 +setp lowpass.0.gain .07 +net spindle-index encoder.1.phase-A +net spindle-vel-rps-low-res encoder.1.velocity => lowpass.0.in + +net spindle-rps-filtered-low-res lowpass.0.out scale.0.in +net spindle-rpm-filtered-low-res scale.0.out +net spindle-rpm-filtered-low-res gmoccapy.spindle_feedback_bar + +net spindle-rpm-filtered-low-res => spindle-at-speed.in2 +net spindle-ready => gmoccapy.spindle_at_speed_led + diff --git a/my-emco-compact-5/emcopos.txt b/my-emco-compact-5/emcopos.txt new file mode 100644 index 0000000..705672d --- /dev/null +++ b/my-emco-compact-5/emcopos.txt @@ -0,0 +1,16 @@ +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 +0.00000000000000000 diff --git a/my-emco-compact-5/func-btn.xml b/my-emco-compact-5/func-btn.xml new file mode 100644 index 0000000..3977d1d --- /dev/null +++ b/my-emco-compact-5/func-btn.xml @@ -0,0 +1,5 @@ + + Touch off selected axisO<mytouch>call + Return to safe ZG53 G0 Z0 + Return to homeG53 G0 X0 Y0 Z0 + \ No newline at end of file diff --git a/my-emco-compact-5/gladevcp-handler.py b/my-emco-compact-5/gladevcp-handler.py new file mode 100644 index 0000000..2a148ea --- /dev/null +++ b/my-emco-compact-5/gladevcp-handler.py @@ -0,0 +1,141 @@ +#!/usr/bin/ python3 + +import gi +gi.require_version("Gtk", "3.0") + +from gi.repository import Gtk +import linuxcnc +import hal +import hal_glib +import xml.etree.ElementTree as ET + +debug = 0 + +"""class ToolTableParser: + def __init__(self, f): + self.f = open(f, 'r') + self.list = Gtk.ListStore(int, str, str) + self._parse_file() + self.f.close() + + def __repr__(self): + ret_str = '' + for l in self.list: + ret_str += str(l) + '\n' + return ret_str + + def get_parsed_data(self): + return self.list + + def _parse_file(self): + lines = self.f.readlines() + + i = 0 + for line in lines: + tool_nbr = line.split(' ')[0] + tool_descr = tool_nbr + ' ' + line.split(';')[1] + self.list.append([i, tool_descr, tool_nbr]) + i = i+1 +""" + +class XmlParser: + def __init__(self, f): + self.tree = [] + self.list = Gtk.ListStore(int, str, str) + + self._parse_file(f) + + def get_parsed_data(self): + return self.list + + def _parse_file(self, f): + self.tree = ET.parse(f) + root = self.tree.getroot() + + i = 0 + for func in root.iter('function'): + gcode = func.find('gcode') + + # create the LinuxCNC hal pin and create mapping dictionary binding incomming events with data and the hal pins + if gcode is not None: + self.list.append([i, func.text, gcode.text]) + i = i+1 + +class HandlerClass: + + def on_destroy(self,obj,data=None): + print("on_destroy, combobox active=%d" %(self.combo.get_active())) + self.halcomp.exit() # avoid lingering HAL component + Gtk.main_quit() + + """def on_changed(self, combobox, data=None): + if self.tool_combo_initiated: + model = combobox.get_model() + tool_change_cmd = 'M6' + ' ' + model[combobox.get_active()][2] + ' ' + 'G43' + self._send_mdi(tool_change_cmd) + print(tool_change_cmd)""" + + def __init__(self, halcomp, builder, useropts): + self.linuxcnc_status = linuxcnc.stat() + self.linuxcnc_cmd = linuxcnc.command() + self.halcomp = halcomp + self.builder = builder + self.useropts = useropts + + self.trigger1 = hal_glib.GPin(halcomp.newpin('trigger_pin', hal.HAL_BIT, hal.HAL_IN)) + self.trigger1.connect('value-changed', self._trigger_change) + + #self.trigger2 = hal_glib.GPin(halcomp.newpin('saved-tool-pin', hal.HAL_U32, hal.HAL_IN)) + #self.trigger2.connect('value-changed', self._init_tool_combo) + + func_list = XmlParser('func-btn.xml').get_parsed_data() + self.func_combo = self.builder.get_object('func-btn-combo') + self.func_combo.set_model(func_list) + self.func_combo.set_entry_text_column(1) + self.func_combo.set_active(0) + + #tool_list = ToolTableParser('tool.tbl').get_parsed_data() + #self.tool_combo = self.builder.get_object('tool-combo') + #self.tool_combo.set_model(tool_list) + #self.tool_combo.set_entry_text_column(2) + #self.tool_combo.set_active(0) + + renderer_text = Gtk.CellRendererText() + self.func_combo.pack_start(renderer_text, True) + #self.tool_combo.pack_start(renderer_text, True) + #self.tool_combo_initiated = False + + def _trigger_change(self, pin, userdata = None): + #setp gladevcp.trigger_pin 1 + #print "pin value changed to: " + str(pin.get()) + #print "pin name= " + pin.get_name() + #print "pin type= " + str(pin.get_type()) + #print "active " + str(self.combo.get_active()) + if pin.get() is True: + model = self.func_combo.get_model() + self._send_mdi(model[self.func_combo.get_active()][2]) + + #def _init_tool_combo(self, pin, userdata = None): + #setp gladevcp.saved_tool_pin 2 + # self.tool_combo.set_active(pin.get()) + # self.tool_combo_initiated = True + + + def _ok_for_mdi(self): + self.linuxcnc_status.poll() + return not self.linuxcnc_status.estop and self.linuxcnc_status.enabled and (self.linuxcnc_status.homed.count(1) == self.linuxcnc_status.joints) and (self.linuxcnc_status.interp_state == linuxcnc.INTERP_IDLE) + + def _send_mdi(self, mdi_cmd_str): + if self._ok_for_mdi(): + self.linuxcnc_cmd.mode(linuxcnc.MODE_MDI) + self.linuxcnc_cmd.wait_complete() # wait until mode switch executed + self.linuxcnc_cmd.mdi(mdi_cmd_str) + +def get_handlers(halcomp, builder, useropts): + + global debug + for cmd in useropts: + exec(cmd in globals()) + + return [HandlerClass(halcomp, builder, useropts)] + diff --git a/my-emco-compact-5/linuxcnc.var b/my-emco-compact-5/linuxcnc.var new file mode 100644 index 0000000..eb5e5bf --- /dev/null +++ b/my-emco-compact-5/linuxcnc.var @@ -0,0 +1,122 @@ +4997 1.000000 +4998 0.484830 +4999 20.164660 +5161 0.000000 +5162 0.000000 +5163 0.000000 +5164 0.000000 +5165 0.000000 +5166 0.000000 +5167 0.000000 +5168 0.000000 +5169 0.000000 +5181 0.000000 +5182 0.000000 +5183 0.000000 +5184 0.000000 +5185 0.000000 +5186 0.000000 +5187 0.000000 +5188 0.000000 +5189 0.000000 +5210 0.000000 +5211 0.000000 +5212 0.000000 +5213 0.000000 +5214 0.000000 +5215 0.000000 +5216 0.000000 +5217 0.000000 +5218 0.000000 +5219 0.000000 +5220 1.000000 +5221 -8.934820 +5222 0.000000 +5223 8.596005 +5224 0.000000 +5225 0.000000 +5226 0.000000 +5227 0.000000 +5228 0.000000 +5229 0.000000 +5230 0.000000 +5241 0.000000 +5242 0.000000 +5243 0.000000 +5244 0.000000 +5245 0.000000 +5246 0.000000 +5247 0.000000 +5248 0.000000 +5249 0.000000 +5250 0.000000 +5261 0.000000 +5262 0.000000 +5263 0.000000 +5264 0.000000 +5265 0.000000 +5266 0.000000 +5267 0.000000 +5268 0.000000 +5269 0.000000 +5270 0.000000 +5281 0.000000 +5282 0.000000 +5283 0.000000 +5284 0.000000 +5285 0.000000 +5286 0.000000 +5287 0.000000 +5288 0.000000 +5289 0.000000 +5290 0.000000 +5301 0.000000 +5302 0.000000 +5303 0.000000 +5304 0.000000 +5305 0.000000 +5306 0.000000 +5307 0.000000 +5308 0.000000 +5309 0.000000 +5310 0.000000 +5321 0.000000 +5322 0.000000 +5323 0.000000 +5324 0.000000 +5325 0.000000 +5326 0.000000 +5327 0.000000 +5328 0.000000 +5329 0.000000 +5330 0.000000 +5341 0.000000 +5342 0.000000 +5343 0.000000 +5344 0.000000 +5345 0.000000 +5346 0.000000 +5347 0.000000 +5348 0.000000 +5349 0.000000 +5350 0.000000 +5361 0.000000 +5362 0.000000 +5363 0.000000 +5364 0.000000 +5365 0.000000 +5366 0.000000 +5367 0.000000 +5368 0.000000 +5369 0.000000 +5370 0.000000 +5381 0.000000 +5382 0.000000 +5383 0.000000 +5384 0.000000 +5385 0.000000 +5386 0.000000 +5387 0.000000 +5388 0.000000 +5389 0.000000 +5390 0.000000 diff --git a/my-emco-compact-5/macros/LICENSE b/my-emco-compact-5/macros/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/my-emco-compact-5/macros/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/my-emco-compact-5/macros/LatheMacro.svg b/my-emco-compact-5/macros/LatheMacro.svg new file mode 100644 index 0000000..dc974c4 --- /dev/null +++ b/my-emco-compact-5/macros/LatheMacro.svg @@ -0,0 +1,3057 @@ + +image/svg+xml diff --git a/my-emco-compact-5/macros/README b/my-emco-compact-5/macros/README new file mode 100644 index 0000000..ea8b65e --- /dev/null +++ b/my-emco-compact-5/macros/README @@ -0,0 +1,77 @@ +This folder contains a number of simulated lathe configs. + +the "lathemacro" config offers a number of simple macros to perform +the most common lathe operations. + +The GUI that controls the macros can be viewed by clicking the "Cycles" +tab top left of the graphical preview window. + +There are two load-time options to control the tab behaviour: +1) norun will hide the action button, use this if you want to use only +a physical button (connected to gladevcp.cycle-start) to start the macros +(Strongly recommended, especially with Touchy) +2) notouch will allow keyboard editing of the spinboxes. Otherwise the +custom numeric keyboard will be shown. + +An example loadrt line, as used here in the Gmoccapy demo is: + +[DISPLAY] +EMBED_TAB_COMMAND = halcmd loadusr -Wn gladevcp gladevcp -c gladevcp -U notouch=1 -U norun=0 -u lathehandler.py -x {XID} lathemacro.ui + +The window will resize slowly if you grab the corner and move the mouse +inside the window. It's not as bad as it was, but still needs work. +You may need to click the unmaximise button in the toolbar to get a +window border to be able to use the resize handles. + +To relocate the files outside of the config directory (i.e. the direcrory containing the INI file) use, for example, +"macros/lathehandeler.py" and "macros/lathemacro.ui" in the EMBED_TAB_COMMAND above. The system will look for the +LatheMacro.svg file in the same path as the lathehandler.py file. If you need to relocate or rename this file then +use "-U svgfile=/full/path/to/svgfile.svg" in the embed command. + +Notes on the keyboard: +As well as the obvious functions and unit conversions, it can be used to +enter fractions. For example if you type 1.1/2 it will automatically +update to display 1.5000 and 16.17/64 will show 16.2656. +This can be used in a limited way to halve the onscreen value eg for +entering radius instead of diameter. +However it only works for whole numbers: 100/2 will become 50 but +3.14149/2 is interpreted as 3 and 14 thousand halves so won't work. + +Notes on adding your own cycles: +Create a new G-code subroutine in the same format as the existing ones. +In Glade add a new tab to the 'tabs1' notebook and give it a name matching +the new cycle. +Edit the action button (inside an eventbox) to call the new G-code sub. +Rename the action button to match the tab name and append '.action' eg +MyCycle.action + +Create new artwork. I used Fusion360, the models are here: +https://a360.co/3uFPZNv +and the drawings are here: +https://a360.co/3uFPZNv +Esport the drawing page as PDF and import into the lathemacro.svg file in +Inkscape. You will need to resize. Add your own arrows and annotations. + +Save the new layer in a layer named "layerN" (lower case) where N is the +tab number, starting at zero. You will need to invoke the XML editor for +this (Shift-Cmd-X on Mac) + +The entry boxes are positioned relative to a 1500 x 1000 image; the +original size of the SVG. So you can hover your mouse over the image in +Inkscape to determine the coordinates. +In the in the case of on-drawing controls the coordinates are entered as +an XML comment in the Tooltip for the control in x,y format (The surface speed, +tool and coolant do not need this, they are in a fixed table) + +An example: + +', c.get_tooltip_markup()) + if len(m) > 0: + x1 = int(m[0][0]); y1 = int(m[0][1]) + c.set_margin_left(max(0, w * x1/1500)) + c.set_margin_top(max(0, h * y1/1000)) + + + # decide if our window is active to mask the cycle-start hardware button + # FIXME: This is probably not as reliable as one might wish. + def event(self,w,event): + if w.is_active(): + if w.has_toplevel_focus() : + self.active = True + else: + self.active = False + + # Capture notify events + def on_map_event(self, widget, data=None): + top = widget.get_toplevel() + top.connect('notify', self.event) + + def on_destroy(self,obj,data=None): + self.ini.save_state(self) + + def on_restore_defaults(self,button,data=None): + ''' + example callback for 'Reset to defaults' button + currently unused + ''' + self.ini.create_default_ini() + self.ini.restore_state(self) + + def __init__(self, halcomp,builder,useropts): + self.halcomp = halcomp + self.builder = builder + self.ini_filename = 'savestate.sav' + self.defaults = { IniFile.vars: dict(), + IniFile.widgets : widget_defaults(select_widgets(self.builder.get_objects(), + hal_only=False,output_only = True)) + } + self.ini = IniFile(self.ini_filename,self.defaults,self.builder) + self.ini.restore_state(self) + + # A pin to use a physical switch to start the cycle + self.cycle_start = hal_glib.GPin(halcomp.newpin('cycle-start', hal.HAL_BIT, hal.HAL_IN)) + self.cycle_start.connect('value-changed', self.cycle_pin) + + # This catches the signal from Touchy to say that the tab is exposed + t = self.builder.get_object('macrobox') + t.connect('map-event',self.on_map_event) + t.add_events(Gdk.EventMask.STRUCTURE_MASK) + + self.cmd = linuxcnc.command() + + # This connects the expose event to re-draw and scale the SVG frames + t = self.builder.get_object('tabs1') + t.connect_after("draw", self.on_expose) + t.connect("destroy", Gtk.main_quit) + t.add_events(Gdk.EventMask.STRUCTURE_MASK) + print(svgfile) + self.svg = Rsvg.Handle().new_from_file(svgfile) + self.active = True + + # handle Useropts + if norun: + for c in range(0,6): + print(c) + print( f'tab{c}.action') + self.builder.get_object(f'tab{c}.action').set_visible(False) + + def show_keyb(self, obj, data=None): + if notouch: return False + self.active_ctrl = obj + self.keyb = self.builder.get_object('keyboard') + self.entry = self.builder.get_object('entry1') + self.entry.modify_font(Pango.FontDescription("courier 42")) + self.entry.set_text("") + resp = self.keyb.run() + return True + + def keyb_prev_click(self, obj, data=None): + self.entry.set_text(self.active_ctrl.get_text()) + + def keyb_number_click(self, obj, data=None): + data = self.entry.get_text() + data = data + obj.get_label() + if any( x in data for x in [ '/2', '/4', '/8', '/16', '/32', '/64', '/128']): + v = [0] + [float(x) for x in data.replace('/','.').split('.')] + data = f'{v[-3] + v[-2]/v[-1]:6.7}' + self.entry.set_text(data) + + def keyb_pm_click(self, obj, data=None): + data = self.entry.get_text() + if data[0] == '-': + data = data[1:] + else: + data = '-' + data + self.entry.set_text(data) + + def keyb_convert_click(self, obj, data=None): + v = float(self.entry.get_text()) + op = obj.get_label() + if op == 'in->mm': + self.entry.set_text(f'{v * 25.4:6.4}') + elif op == 'mm->in': + self.entry.set_text(f'{v / 25.4:6.4}') + elif op == 'tpi->pitch': + self.entry.set_text(f'{25.4 / v:6.4}') + elif op == 'pitch->tpi': + self.entry.set_text(f'{25.4 / v:6.4}') + + def keyb_del_click(self, obj, data=None): + data = self.entry.get_text() + data = data[:-1] + self.entry.set_text(data) + + def keyb_clear_click(self, obj, data=None): + self.entry.set_text('') + + def keyb_cancel_click(self, obj, data=None): + self.keyb.hide() + + def keyb_ok_click(self, obj, data=None): + if self.entry.get_text() != '': + self.active_ctrl.set_value(float(self.entry.get_text())) + self.keyb.hide() + + def set_alpha(self, obj, data = None): + cr = obj.get_property('window').cairo_create() + cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) + + def cycle_pin(self, pin, data = None): + if pin.get() == 0: + return + if self.active: + nb = self.builder.get_object('tabs1') + print('current tab', nb.get_current_page()) + c = self.builder.get_object(f"tab{nb.get_current_page()}.action") + if c is not None: + self.cmd.abort() + self.cmd.mode(linuxcnc.MODE_MDI) + self.cmd.wait_complete() + c.emit('clicked') + print(c.get_name(), "clicked") + + def testing(self, obj, data = None): + print('event', data) + +def get_handlers(halcomp,builder,useropts): + + global debug + for cmd in useropts: + print(cmd) + exec(cmd, globals()) + + set_debug(debug) + return [HandlerClass(halcomp,builder,useropts)] + + + diff --git a/my-emco-compact-5/macros/lathemacro.ui b/my-emco-compact-5/macros/lathemacro.ui new file mode 100644 index 0000000..f9261e8 --- /dev/null +++ b/my-emco-compact-5/macros/lathemacro.ui @@ -0,0 +1,2937 @@ + + + + + + + -89 + 89 + 1 + 10 + + + 100 + 1 + 10 + + + 6 + 0.14999999999999999 + 0.029999999999999999 + + + 100 + 10 + + + 200 + 100 + 10 + 10 + + + 100 + 1 + 1 + 10 + + + -1000 + 1000 + 10 + + + -1000 + 1000 + 1 + 10 + + + 250 + 1 + 0.25 + 10 + + + -20 + 250 + 1 + 10 + + + 200 + 100 + 10 + 10 + + + 100 + 1 + 1 + 10 + + + -2000 + 2000 + 1 + + + -2000 + 2000 + 10 + 1 + + + 2 + 0.050000000000000003 + 0.029999999999999999 + + + 2 + 50 + 2 + 0.5 + + + 200 + 100 + 10 + 10 + + + 100 + 1 + 1 + 10 + + + -2000 + 2000 + 1 + + + -89 + 89 + 1 + 10 + + + 20 + 1 + 0.050000000000000003 + 10 + + + 6 + 0.14999999999999999 + 0.02 + 10 + + + 100 + 250 + 10 + 10 + + + 100 + 1 + 1 + 10 + + + -1000 + 1000 + 1 + 10 + + + -1000 + 1000 + 1 + 10 + + + 2 + 0.029999999999999999 + 0.029999999999999999 + + + 200 + 100 + 10 + 10 + + + 100 + 9 + 1 + 10 + + + -2000 + 2000 + 1 + + + 250 + 1 + 0.25 + 10 + + + -20 + 250 + 1 + 10 + + + 200 + 100 + 10 + 10 + + + 100 + 1 + 1 + 10 + + + -2000 + 2000 + 1 + + + 25 + 1 + 0.25 + + + 200 + 50 + 10 + 10 + + + 100 + 5 + 1 + 10 + + + -2000 + 2000 + 1 + + + -2000 + 2000 + 1 + + + -90 + 90 + 1 + 10 + + + 3 + 1 + 0.01 + 10 + + + 2 + 0.14999999999999999 + 0.029999999999999999 + + + 100 + 1 + 10 + + + 20 + 500 + 100 + 10 + 10 + + + 100 + 1 + 1 + 10 + + + -20 + 250 + 15 + 1 + 10 + + + -2000 + 2000 + 1 + + + gtk-media-play + O<boring> call [${bore.x-f}] [${bore.sf-f}] [${bore.cut-f}] [${bore.feed-f}] [${bore.z-f}] [${bore.rad-f}] [${bore.angle-f}] [${bore.tool-s}] [${bore.coolant}] + + + Set Tool + M61 Q${bore.tool-s} G43 H${bore.tool-s} + + + O<chamfer>call [${chamfer.x-f}] [${chamfer.sf-f}] [0.5] [0] [${chamfer.z-f}] [${chamfer.tool-s}] [0] [${chamfer.size-f}] [${chamfer.fo}] [${chamfer.fi}] [${chamfer.bo}] [${chamfer.coolant}] + + + M61 Q${chamfer.tool-s} G43 H${chamfer.tool-s} + + + O<drilling> call [${drill.dia-f}] [${drill.sf-f}] [${drill.feed-f}] [${drill.z-f}] [${drill.peck-f}] [${drill.tool-s}] [${drill.coolant}] + + + Set Tool + Set Tool + M61 Q${drill.tool-s} G43 H${drill.tool-s} + + + O<facing>call [${face.x-f}] [${face.sf-f}] [${face.cut-f}] [${face.feed-f}] [${face.z-f}] [${face.angle-s}] [${face.tool-s}] [${face.coolant}] + + + Set Tool + M61 Q${face.tool-s} G43 H${face.tool-s} + + + O<grooving> call [${groove.x-f}] [${groove.sf-f}] [${groove.feed-f}] [${groove.tool-s}] [${groove.coolant}] + + + Set Tool + Set Tool + M61 Q${groove.tool-s} G43 H${groove.tool-s} + + + False + 5 + dialog + + + + + + True + False + 2 + + + True + False + end + + + OK + 100 + 50 + True + True + True + + + + False + False + 0 + + + + + Cancel + 100 + 50 + True + True + True + + + + False + False + 1 + + + + + False + True + end + 0 + + + + + 60 + True + True + + False + False + + + False + False + 1 + + + + + True + False + 5 + 4 + + + 1 + 50 + 50 + True + True + True + + + + + + 2 + 50 + 20 + True + True + True + + + + 1 + 2 + + + + + 3 + 50 + 20 + True + True + True + + + + 2 + 3 + + + + + DEL + 50 + 20 + True + True + True + + + + 3 + 4 + + + + + 4 + 50 + 50 + True + True + True + + + + 1 + 2 + + + + + 5 + 50 + 20 + True + True + True + + + + 1 + 2 + 1 + 2 + + + + + 6 + 50 + 20 + True + True + True + + + + 2 + 3 + 1 + 2 + + + + + CLR + 50 + 20 + True + True + True + + + + 3 + 4 + 1 + 2 + + + + + 7 + 50 + 50 + True + True + True + + + + 2 + 3 + + + + + 8 + 50 + 20 + True + True + True + + + + 1 + 2 + 2 + 3 + + + + + 9 + 50 + 20 + True + True + True + + + + 2 + 3 + 2 + 3 + + + + + PREV + 50 + 20 + True + True + True + + + + 3 + 4 + 2 + 3 + + + + + +/- + 50 + 50 + True + True + True + + + + 3 + 4 + + + + + 0 + 50 + 20 + True + True + True + + + + 1 + 2 + 3 + 4 + + + + + . + 50 + 20 + True + True + True + + + + 2 + 3 + 3 + 4 + + + + + / + 50 + 20 + True + True + True + + + + 3 + 4 + 3 + 4 + + + + + in->mm + 80 + 40 + True + True + True + + + + 4 + 5 + 4 + 4 + + + + + mm->in + 80 + 40 + True + True + True + + + + 1 + 2 + 4 + 5 + 4 + 4 + + + + + pitch->tpi + 80 + 40 + True + True + True + + + + 2 + 3 + 4 + 5 + 4 + 4 + + + + + tpi->pitch + 80 + 40 + True + True + True + + + + 3 + 4 + 4 + 5 + 4 + 4 + + + + + True + True + 2 + + + + + + button23 + button24 + + + + O<radius> call [${radius.x-f}] [${radius.sf-f}] [0.5] [0][${radius.z-f}] [${radius.tool-s}] [0] [${radius.rad-f}] [${radius.fo}] [${radius.fi}] [${radius.bo}] [${radius.coolant}] + + + Set Tool + M61 Q${radius.tool-s} G43 H${radius.tool-s} + + + O<threading>call [${thread.x-f}] [${thread.sf-f}] [${thread.tool-s}] [${thread.pitch-f}] [${thread.z-f}] [${thread.internal}] [${thread.external}] [${thread.coolant}] + + + M61 Q${thread.tool-s} G43 H${thread.tool-s} + + + O<turning> call [${turn.x-f}] [${turn.sf-f}] [${turn.cut-f}] [${turn.feed-f}] [${turn.z-f}] [${turn.rad-f}] [${turn.angle-f}] [${turn.tool-s}] [${turn.coolant}] + + + Set Tool + M61 Q${turn.tool-s} G43 H${turn.tool-s} + + + False + GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK + 200 + 100 + False + + + + + + True + False + + False + + + True + True + GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK | GDK_SUBSTRUCTURE_MASK | GDK_SCROLL_MASK + left + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 50 + 20 + True + True + <!--1000,654-->Finish Diameter + start + start + + 7 + 0.000 + False + False + False + TurnXAdj + 4 + True + + + + + + 50 + 20 + True + True + <!--635,687-->Feed per Rev + start + start + + 5 + 0.000 + False + False + TurnFeedAdj + 3 + True + + + + 1 + + + + + 50 + 20 + True + True + <!--800,230-->End Radius + start + start + + 5 + 0.000 + False + False + TurnRadAdj + 4 + True + + + + 2 + + + + + 50 + 20 + True + True + <!--821,863-->Cut per pass + start + start + + 5 + 0.000 + False + False + TurnCutAdj + 3 + True + + + + 3 + + + + + 50 + 20 + True + True + <!--125,424-->Finish Z + start + start + + 7 + 0.000 + False + False + TurnZAdj + 4 + True + + + + 4 + + + + + 50 + 20 + True + True + <!--520,474-->Taper angle + start + start + + 5 + 0.0000 + False + False + False + TurnAngAdj + 3 + True + + + + 5 + + + + + 100 + 40 + True + False + end + end + + + gtk-media-play + False + turn.go + 50 + 20 + True + True + True + True + + + + + 10 + + + + + True + False + end + start + + + 50 + 20 + True + True + + 0 + False + False + TurnToolAdj + + + + 1 + 0 + + + + + Set Tool + turn.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + 50 + 20 + True + True + end + start + + 5 + 20 + False + False + TurnSFAdj + 20 + + + + 1 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + + + + 11 + + + + + False + + + + + True + False + Turning + + + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 50 + 20 + True + True + <!--700,280-->Taper Angle + start + start + + 5 + 0.0000 + False + False + BoreAngleAdj + 3 + + + + + + 50 + 20 + True + True + <!--421,520-->Run-out radius + start + start + + 5 + 0.000 + False + False + BoreRadAdj + 4 + + + + 1 + + + + + 50 + 20 + True + True + <!--1080,616-->Finish Diameter + start + start + + 7 + 0.000 + False + False + BoreXAdj + 4 + + + + 2 + + + + + 50 + 20 + True + True + <!--900,825-->Diameter Increment + start + start + + 5 + 0.000 + False + False + BoreCutAdj + 4 + + + + 3 + + + + + 50 + 20 + True + True + <!--530,820-->Feed per rev + start + start + + 5 + 0.000 + False + False + BoreFeedAdj + 4 + + + + 4 + + + + + 100 + 40 + True + False + end + end + + + gtk-media-play + False + bore.go + 50 + 20 + True + True + True + True + True + + + + + 7 + + + + + 50 + 20 + True + True + <!--273,267-->Finish Z + start + start + + 7 + 0.000 + False + False + BoreZAdj + 4 + + + + 9 + + + + + True + False + end + start + + + 50 + 20 + True + True + end + start + + 5 + 0 + False + False + BoreSFAdj + + + + 1 + 1 + + + + + 50 + 20 + True + True + + 0 + False + False + BoreToolAdj + + + + 1 + 0 + + + + + Set Tool + bore.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + + + + 11 + + + + + 1 + False + + + + + True + False + Boring + + + 1 + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 50 + 20 + True + True + <!--156,404-->Finish Z + start + start + + 7 + 0.000 + False + False + FaceZAdj + 4 + + + + 2 + + + + + 50 + 20 + True + True + <!--1115,626-->Finish Diameter + start + start + + 7 + 0.000 + False + False + FaceXAdj + 4 + + + + 3 + + + + + 50 + 20 + True + True + <!--876,886-->Feed per Rev + start + start + + 5 + 0.0000 + False + False + FaceFeedAdj + 3 + + + + 4 + + + + + 50 + 20 + True + True + <!--408,760-->Cut per pass + start + start + + 5 + 0.000 + False + False + FaceCutAdj + 3 + + + + 5 + + + + + 50 + 20 + True + True + <!--1044,364-->Face Angle + start + start + + 5 + 0.0000 + False + False + FaceAngleAdj + 3 + + + + 6 + + + + + 100 + 40 + True + False + end + end + False + + + gtk-media-play + False + face.go + 50 + 20 + True + True + True + True + True + + + + + 9 + + + + + True + False + end + start + + + 50 + 20 + True + True + end + start + + 5 + 0 + False + False + FaceSFAdj + + + + 1 + 1 + + + + + 50 + 20 + True + True + + 0 + False + False + FaceToolAdj + + + + 1 + 0 + + + + + Set Tool + face.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + + + + 10 + + + + + Face + 2 + False + + + + + True + False + Facing + + + 2 + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 50 + 20 + True + True + <!--1018,674-->Radius Inner or Outer Diameter + start + start + + 7 + 0.000 + False + False + RadXAdj + 4 + + + + + + 50 + 20 + True + True + <!--202,334-->Radius Z position + start + start + + 7 + 0.000 + False + False + RadiusZAdj + 4 + + + + 1 + + + + + 50 + 20 + True + True + <!--848,451-->Radius + start + start + + 5 + 0.000 + False + False + RadRadAdj + 3 + + + + 2 + + + + + 100 + 40 + True + False + <!--863,629-->Front Inside Radius + start + start + + + 50 + 20 + True + True + False + True + True + + + + + 3 + + + + + 100 + 40 + True + False + <!--763,680-->Front Outside Radius + start + start + + + 50 + 20 + True + True + False + True + radius.fi + + + + + 4 + + + + + 100 + 40 + True + False + <!--335,448-->Back Outside Radius + start + start + + + 50 + 20 + True + True + False + True + radius.fi + + + + + 5 + + + + + 100 + 40 + True + False + end + end + + + radius.go + 50 + 20 + True + True + True + True + + + True + False + gtk-media-play + + + + + + + 10 + + + + + True + False + end + start + + + 50 + 20 + True + True + end + start + + 5 + 0 + False + False + RadiusSFAdj + + + + 1 + 1 + + + + + 50 + 20 + True + True + + 5 + 0 + False + False + RadiusToolAdj + + + + 1 + 0 + + + + + Set Tool + radius.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + + + + 11 + + + + + Radius + 3 + False + + + + + True + False + Radius + + + 3 + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 50 + 20 + True + True + <!--202,334-->Chamfer Z position + start + start + + 7 + 0.000 + False + False + ChamferZAdj + 4 + + + + + + 50 + 20 + True + True + <!--1112,287-->Chamfer size + start + start + + 5 + 0.0000 + False + False + ChamChamAdj + 3 + + + + 1 + + + + + 50 + 20 + True + True + <!--1033,678-->Chamfer Diametric position + start + start + + 7 + 0.000 + False + False + ChamXAdj + 4 + + + + 2 + + + + + 100 + 40 + True + False + <!--335,448-->Back outside chamfer + start + start + + + 50 + 20 + True + True + False + <!--335,448-->Chamfer Z position + True + True + + + + + 3 + + + + + 100 + 40 + True + False + <!--763,680-->Front Outside Chamfer + start + start + + + 50 + 20 + True + True + False + True + chamfer.bo + + + + + 4 + + + + + 100 + 40 + True + False + <!--863,629-->Front Inside Chamfer + start + start + + + 50 + 16 + True + True + False + 0 + True + chamfer.bo + + + + + 5 + + + + + 100 + 40 + True + False + end + end + + + False + chamfer.go + 50 + 20 + True + True + True + True + + + True + False + gtk-media-play + + + + + + + 10 + + + + + True + False + end + start + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + Set Tool + False + chamfer.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + 50 + 20 + True + True + start + start + + 5 + 0 + False + False + ChamferSFAdj + + + + 1 + 1 + + + + + 50 + 20 + True + True + start + start + + 0 + False + False + ChamferToolAdj + + + + 1 + 0 + + + + + + + + 11 + + + + + Chamfer + 4 + False + + + + + True + False + Chamfer + + + 4 + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 50 + 20 + True + True + <!--268,341-->Finish Z position + start + start + + 7 + 0.000 + False + False + ThreadZAdj + 4 + + + + + + 50 + 20 + True + True + <!--1010,753-->Radius Z position + start + start + + 7 + 0.000 + False + False + ThreadXAdj + 4 + + + + 1 + + + + + 50 + 20 + True + False + <!--652,737-->External Thread + start + start + + + True + True + False + True + True + + + + + 2 + + + + + 50 + 20 + True + True + <!--192,616-->Radius Z position + start + start + + 7 + 0.0000 + False + False + ThreadPitchAdj + 4 + + + + 4 + + + + + 50 + 20 + True + False + <!--754,603-->Internal Thread + start + start + + + True + True + False + True + thread.external + + + + + 6 + + + + + 50 + 20 + True + False + end + end + + + False + thread.go + 50 + 20 + True + True + True + True + + + True + False + gtk-media-play + + + + + + + 7 + + + + + True + False + end + start + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + 50 + 20 + True + True + start + start + + 5 + 20 + False + False + ThreadSFAdj + 20 + + + + 1 + 1 + + + + + Set Tool + False + thread.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + 50 + 20 + True + True + start + start + + 0 + False + False + ThreadToolAdj + + + + 1 + 0 + + + + + + + + 9 + + + + + 5 + False + + + + + True + False + Thread + + + 5 + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 100 + 40 + True + False + end + end + + + False + groove.go + 50 + 20 + True + True + True + True + + + True + False + gtk-media-play + + + + + + + 4 + + + + + 50 + 20 + True + True + <!--1084,672-->Finish Diameter + start + start + + 7 + 0.000 + False + False + GrooveXAdj + 4 + + + + 5 + + + + + True + False + end + start + + + 50 + 20 + True + True + + 0 + False + False + GrooveToolAdj + + + + 1 + 0 + + + + + Set Tool + groove.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + 50 + 20 + True + True + end + start + + 5 + 20 + False + False + GrooveSFAdj + 20 + + + + 1 + 1 + + + + + + + + 8 + + + + + 50 + 20 + True + True + <!--648,864-->Feed per rev + start + start + + 5 + 0.0000 + False + False + GrooveFeedAdj + 3 + + + + 4 + + + + + 6 + + + + + True + False + Groove + + + 6 + False + + + + + True + False + + + True + False + gtk-missing-image + + + -1 + + + + + 100 + 40 + True + False + end + end + + + False + drill.go + 50 + 20 + True + True + True + True + + + True + False + gtk-media-play + + + + + + + 3 + + + + + True + False + end + start + + + 50 + 20 + True + True + end + start + + 5 + 0 + False + False + DrillSFAdj + + + + 1 + 1 + + + + + 50 + 20 + True + True + + 0 + False + False + DrillToolAdj + + + + 1 + 0 + + + + + Set Tool + drill.toolchange + 50 + 20 + True + True + True + True + + + 0 + 0 + + + + + True + False + center + Speed + 1 + + + 0 + 1 + + + + + Coolant + True + True + False + True + + + 1 + 2 + + + + + + + + 3 + + + + + 50 + 20 + True + True + <!--770,900-->Feed per Rev + start + start + + 5 + 0.0000 + False + False + DrillFeedAdj + 3 + + + + 2 + + + + + 50 + 20 + True + True + <!--260,250-->Finish Z + start + start + + 7 + 0.000 + False + False + DrillZAdj + 4 + + + + 3 + + + + + 50 + 20 + True + True + <!--1200,270-->Drill Diameter + start + start + + 7 + 0.000 + False + False + DrillDiaAdj + 4 + + + + 4 + + + + + 50 + 20 + True + True + <!--300,711-->Peck distance + start + start + + 5 + 0.000 + False + False + DrillPeckAdj + 0.25 + 3 + 2 + + + + 5 + + + + + 7 + + + + + True + False + Drill + + + 7 + False + + + + + + + + diff --git a/my-emco-compact-5/macros/radius.ngc b/my-emco-compact-5/macros/radius.ngc new file mode 100644 index 0000000..4ba6e52 --- /dev/null +++ b/my-emco-compact-5/macros/radius.ngc @@ -0,0 +1,76 @@ +;radius + +O sub + +G8 ; Lathe radius Mode +G18 ; XZ Plane +G21 ; Metric Units +G90 ; Absolute Distance + + +M6 T#6 G43 + +#1 = [#1 / 2] ; because of radius mode +#14 = [#<_x>] (starting X) +#13 = [#<_z>] (starting Z) + +G96 D2400 S#2 ; Constant Surface Speed Mode +M3 +g95 F0.1 ; Feed-Per-Rev Mode + +O90 IF [#12 GT 0.5] + M8 +O90 ENDIF + +#20 = 0 +O101 if [#9 GT 0.5] ; Front outside + o100 while [[#20 + #3] lt #8] + #20 = [#20 + #3] + g0 x[#1 - #20] z#13 + g1 z#5 + g3 x#1 z[#5 - #20] K[-#20] + g1 x #14 + g0 z#13 + o100 endwhile + g0 x#14 z#13 + g0 x[#1 - #8] + g1 z#5 + g3 x#1 z[#5 - #8] K[-#8] + g1 x #14 + g0 z#13 +O101 elseif [#10 GT 0.5] ; front inside + o102 while [[#20 + #3] lt #8] + #20 = [#20 + #3] + g0 x[#1 + #20] z#13 + g1 z#5 + g2 x#1 z[#5 - #20] K[-#20] + g1 x #14 + g0 z#13 + o102 endwhile + g0 x#14 z#13 + g0 x[#1 + #8] + g1 z#5 + g2 x#1 z[#5 - #8] K[-#8] + g1 x #14 + g0 z#13 +O101 elseif [#11 GT 0.5] ; back outside + o103 while [[#20 + #3] lt #8] + #20 = [#20 + #3] + g0 x[#1 - #20] z#13 + g1 z#5 + g2 x#1 z[#5 + #20] K#20 + g1 x #14 + g0 z#13 + o103 endwhile + g0 x#14 z#13 + g0 x[#1 - #8] + g1 z#5 + g2 x#1 z[#5 + #8] K#8 + g1 x #14 + g0 z#13 +O101 endif +M5 M9 +G7 +O endsub +m2 +% diff --git a/my-emco-compact-5/macros/threading.ngc b/my-emco-compact-5/macros/threading.ngc new file mode 100644 index 0000000..71c05ef --- /dev/null +++ b/my-emco-compact-5/macros/threading.ngc @@ -0,0 +1,59 @@ +;threading + +O sub + +G7 ; Lathe Diameter Mode +G18 ; XZ Plane +G21 ; Metric Units +G90 ; Absolute Distance + + +M6 T#3 G43 + +#14 = [#<_x> * 2] (starting X) +#13 = #<_z> (starting Z) + +G96 D200 S#2 ; Constant Surface Speed Mode +M3 +g95 F0.25 ; Feed-Per-Rev Mode + +O90 IF [#8 GT 0.5] + M8 +O90 ENDIF + +g4p1 ; Wait to reach speed + +;Threading + O51 IF [#6 GT 0.5] + # = [#1] + # = [#1 - 1.3 * #4] + ;g1X [# - 1] ;thread truncation + ;g0 Z #13 + ;g1 X # + ;g1 Z #5 + G0 X[# - 1] + g0 Z #13 + #3 = [#4 * 1.3] + (debug, INTERNAL Threading thread dia-#1 start-#13 finish-#5 Pitch-#4 Depth-#3) + g1X [# - 1] + g76 p#4 z#5 i1 j1 k#3 h3 r1.5 q29.5 e0 l0 + + O51 ELSE + # = [#1 - 0.108 * #4] + # = [#1 - 1.0825 * #4] + (debug, EXTERNAL Threading OD = # ID = #) + #3 = [#4 * 1.0825] + g1X [# + 1] ;final thread truncation + g0 z#13 + g1 X # + g1 Z #5 + G0 X[# +1] + G0 Z #13 + g76 p#4 z#5 i-1 j1 k#3 h3 r1.5 q29.5 e0 l0 + + O51 ENDIF + G0 Z #13 + m5 M9 +O endsub + +M2 diff --git a/my-emco-compact-5/macros/turning.ngc b/my-emco-compact-5/macros/turning.ngc new file mode 100644 index 0000000..8dc3ec0 --- /dev/null +++ b/my-emco-compact-5/macros/turning.ngc @@ -0,0 +1,66 @@ +;Turning + +O sub + +G8 ; Radius mode (easier maths) +G18 ; XZ Plane +G21 ; Metric Units +G90 ; Absolute Distance +G91.1 ; but not for arcs + +M6 T#8 G43 + +#1 = [#1 / 2] ; because of radius mode +#14 = [#<_x>] (starting X) +#13 = #<_z> (starting Z) + +#20 = [#6 * SIN[#7]] +#21 = [#6 * COS[#7]] +#22 = [#6 / COS[#7]] +#23 = [#5 + #6 - #20] +#24 = [[#13 - #23] * TAN[#7]] + +G96 D2500 S#2 ; Constant Surface Speed Mode +m3 ;Start Spindle +g95 F#4 ; Feed-Per-Rev Mode + +O90 IF [#9 GT 0.5] + M8 +O90 ENDIF +g4p1 ; Wait to reach speed + + O100 WHILE [#14 GT [#1 + #3 / 2]] + g0 X #14 + #14=[#14-#3 / 2] + G1 X #14 + G1 Z #23 X[#14 + #24] + O101 IF [#6 GT 0] + G2 Z#5 X[#14 + #24 + #21] I#21 K#20 + G1 X[#14 + #24 + #21 + #3/2] + O101 ELSE + G1 X[#14 + #24 + [#3 * .6]] + O101 ENDIF + O104 IF [#7 LT 0] + G0 X#14 + O104 ENDIF + G0 Z[#13] + O100 ENDWHILE + + G0 x#1 + G1 Z #23 X[#1 + #24] + O102 IF [#6 GT 0] + G2 Z#5 X[#1 + #24 + #21] I#21 K#20 + G1 X[#1 + #24 + #21 + #3] + O102 ELSE + G1 X[#1 + #24 + #3] + O102 ENDIF + O106 IF [#7 LT 0] + G0 X#14 + O106 ENDIF + M9 + G0 Z #13 + G0 X #1 ; For touch-off + M5 + G7 +O endsub +M2 diff --git a/my-emco-compact-5/mpg.glade b/my-emco-compact-5/mpg.glade new file mode 100644 index 0000000..2ab8ef9 --- /dev/null +++ b/my-emco-compact-5/mpg.glade @@ -0,0 +1,82 @@ + + + + + + + Goto Machine Zero + G53 G0 X0 Y0 Z0 + + + G53 G0 Z88 + + + False + + + + + + True + False + 2 + + + True + False + 0 + + + True + False + 35 + + + True + False + Func Button: + + + 0 + 0 + + + + + True + False + 0 + 0 + + + + 1 + + + + + 1 + 0 + + + + + + + True + False + <b>MPG</b> + True + + + + + False + False + 0 + + + + + + diff --git a/my-emco-compact-5/mpg.hal b/my-emco-compact-5/mpg.hal new file mode 100644 index 0000000..9323893 --- /dev/null +++ b/my-emco-compact-5/mpg.hal @@ -0,0 +1 @@ +net all-homed mpg.mpg \ No newline at end of file diff --git a/my-emco-compact-5/mpg.xml b/my-emco-compact-5/mpg.xml new file mode 100644 index 0000000..364bbc0 --- /dev/null +++ b/my-emco-compact-5/mpg.xml @@ -0,0 +1,10 @@ + + "axis-selector"selas32 + "scale-selector"selss32 + "jog-pos-btn"jposbit + "jog-neg-btn"jnegbit + "estop-btn"estbit + "func-btn"funcbit + "joystick-x"xfloat + "joystick-z"zfloat + diff --git a/my-emco-compact-5/my-emco-compact-5.hal b/my-emco-compact-5/my-emco-compact-5.hal new file mode 100644 index 0000000..c67afd2 --- /dev/null +++ b/my-emco-compact-5/my-emco-compact-5.hal @@ -0,0 +1,101 @@ +# Generated by stepconf 1.1 at Mon Mar 14 20:22:34 2022 +# If you make changes to this file, they will be +# overwritten when you run stepconf again +loadrt [KINS]KINEMATICS +loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS +loadrt encoder num_chan=2 # 0 used for native speed sense, 1 used for testing new encoder +loadrt hal_parport cfg="0 out" +setp parport.0.reset-time 5000 +loadrt stepgen step_type=6,6 +loadrt lowpass +loadrt scale count=5 # 0 used to convert spindle speed from rps to rpm, + # 1 used in cusom.hal to adjust spindle set-speed fequency + # 2 used in cusom.hal for mpg scale/increment selection + # 3 & 4 used in custom.hal for mgp joystic + +addf parport.0.read base-thread +addf encoder.update-counters base-thread +addf stepgen.make-pulses base-thread +addf parport.0.write base-thread +addf parport.0.reset base-thread + +addf stepgen.capture-position servo-thread +addf encoder.capture-position servo-thread +addf motion-command-handler servo-thread +addf motion-controller servo-thread +addf lowpass.0 servo-thread +addf scale.0 servo-thread +addf stepgen.update-freq servo-thread + +net spindle-cmd-rpm <= spindle.0.speed-out +net spindle-cmd-rpm-abs <= spindle.0.speed-out-abs +net spindle-cmd-rps <= spindle.0.speed-out-rps +net spindle-cmd-rps-abs <= spindle.0.speed-out-rps-abs + +net xphasea => parport.0.pin-02-out +net xphaseb => parport.0.pin-03-out +net xphasec => parport.0.pin-04-out +net xphased => parport.0.pin-05-out + +net zphasea => parport.0.pin-06-out +net zphaseb => parport.0.pin-07-out +net zphasec => parport.0.pin-08-out +net zphased => parport.0.pin-09-out + +setp parport.0.pin-01-out-invert 1 +setp parport.0.pin-01-out-reset true +setp parport.0.pin-01-out true # 74ls374 clock pin + +# spindle encoder stuff +setp encoder.0.counter-mode true +setp encoder.0.position-scale 100 +net spindle-index parport.0.pin-12-in-not +net spindle-ppr parport.0.pin-10-in-not +net spindle-ppr encoder.0.phase-A +net spindle-index encoder.0.phase-Z +net spindle-pos spindle.0.revs encoder.0.position-interpolated +net spindle-index-enable spindle.0.index-enable encoder.0.index-enable +net spindle-vel encoder.0.velocity spindle.0.speed-in + +# Filtering and scaling... moved to custom_postgui +#setp scale.0.gain 60 +#setp lowpass.0.gain .07 +#net spindle-vel lowpass.0.in +#net spindle-rps-filtered lowpass.0.out scale.0.in +#net spindle-rpm-filtered scale.0.out + +net estop-external <= parport.0.pin-11-in-not + +setp stepgen.0.position-scale [JOINT_0]SCALE +setp stepgen.0.steplen 20000 +setp stepgen.0.dirdelay 20000 +setp stepgen.0.maxaccel [JOINT_0]STEPGEN_MAXACCEL +net xpos-cmd joint.0.motor-pos-cmd => stepgen.0.position-cmd +net xpos-fb stepgen.0.position-fb => joint.0.motor-pos-fb +net xphasea <= stepgen.0.phase-A +net xphaseb <= stepgen.0.phase-B +net xphasec <= stepgen.0.phase-C +net xphased <= stepgen.0.phase-D +net xenable joint.0.amp-enable-out => stepgen.0.enable + +setp stepgen.1.position-scale [JOINT_1]SCALE +setp stepgen.1.steplen 20000 +setp stepgen.1.dirdelay 20000 +setp stepgen.1.maxaccel [JOINT_1]STEPGEN_MAXACCEL +net zpos-cmd joint.1.motor-pos-cmd => stepgen.1.position-cmd +net zpos-fb stepgen.1.position-fb => joint.1.motor-pos-fb +net zphasea <= stepgen.1.phase-A +net zphaseb <= stepgen.1.phase-B +net zphasec <= stepgen.1.phase-C +net zphased <= stepgen.1.phase-D +net zenable joint.1.amp-enable-out => stepgen.1.enable + +# moved to custom.hal +#net estop-out <= iocontrol.0.user-enable-out +#net estop-ext => iocontrol.0.emc-enable-in + +loadusr -W hal_manualtoolchange +net tool-change iocontrol.0.tool-change => hal_manualtoolchange.change +net tool-changed iocontrol.0.tool-changed <= hal_manualtoolchange.changed +net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number +net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared diff --git a/my-emco-compact-5/my-emco-compact-5.ini b/my-emco-compact-5/my-emco-compact-5.ini new file mode 100644 index 0000000..ae5213c --- /dev/null +++ b/my-emco-compact-5/my-emco-compact-5.ini @@ -0,0 +1,169 @@ +# Generated by stepconf 1.1 at Mon Mar 14 20:22:34 2022 +# If you make changes to this file, they will be +# overwritten when you run stepconf again + +[EMC] +MACHINE = my-emco-compact-5 +DEBUG = 0 +VERSION = 1.1 + +[DISPLAY] +DISPLAY = gmoccapy +EDITOR = gedit +POSITION_OFFSET = RELATIVE +POSITION_FEEDBACK = ACTUAL +ARCDIVISION = 64 +GRIDS = 10mm 20mm 50mm 100mm 1in 2in 5in 10in +MAX_FEED_OVERRIDE = 1.2 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 +DEFAULT_LINEAR_VELOCITY = 1.25 +MIN_LINEAR_VELOCITY = 0 +MAX_LINEAR_VELOCITY = 12.50 +INTRO_GRAPHIC = linuxcnc.gif +INTRO_TIME = 5 +PROGRAM_PREFIX = /home/johan/linuxcnc/nc_files +INCREMENTS = 1mm .1mm .01mm +#INCREMENTS = 5mm 1mm .5mm .1mm .05mm .01mm +LATHE = 1 +MIN_ANGULAR_VELOCITY = 0.1 +MAX_ANGULAR_VELOCITY = 3600 +DEFAULT_ANGULAR_VELOCITY = 360 +DEFAULT_SPINDLE_SPEED = 200 +CYCLE_TIME = 150 +DEFAULT_SPINDLE_0_SPEED = 200 +MIN_SPINDLE_0_SPEED = 100 +MAX_SPINDLE_0_SPEED = 2500 +MAX_SPINDLE_0_OVERRIDE = 1 +MIN_SPINDLE_0_OVERRIDE = 0.5 + +EMBED_TAB_NAME = Spindle Speed Selection +EMBED_TAB_LOCATION = ntb_preview +EMBED_TAB_COMMAND = gladevcp -H spindle_speed_selector.hal -x {XID} spindle_speed_selector.glade + +EMBED_TAB_NAME = Macro +EMBED_TAB_LOCATION = ntb_preview +EMBED_TAB_COMMAND = halcmd loadusr -Wn gladevcp gladevcp -c gladevcp -U notouch=1 -U norun=0 -u macros/lathehandler.py -x {XID} macros/lathemacro.ui + +EMBED_TAB_NAME = MPG +EMBED_TAB_LOCATION = ntb_preview +EMBED_TAB_COMMAND = gladevcp -u gladevcp-handler.py -H mpg.hal -x {XID} mpg.glade + +[PYTHON] +TOPLEVEL=python/toplevel.py +PATH_APPEND=python +#TOPLEVEL=/home/johan/linuxcnc/configs/sim.gmoccapy.lathe_configs/python/toplevel.py +#PATH_APPEND=/home/johan/linuxcnc/configs/sim.gmoccapy.lathe_configs/python + +[FILTER] +PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image +PROGRAM_EXTENSION = .py Python Script +PROGRAM_EXTENSION = .nc,.tap G-Code File +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python + +[TASK] +TASK = milltask +CYCLE_TIME = 0.010 + +[RS274NGC] +PARAMETER_FILE = linuxcnc.var +RS274NGC_STARTUP_CODE = G7 G18 +SUBROUTINE_PATH=custom-m-codes +USER_M_PATH=custom-m-codes +REMAP=S prolog=setspeed_prolog ngc=mysetspeed epilog=setspeed_epilog +REMAP=M0 modalgroup=4 ngc=extend_m0 +REMAP=M1 modalgroup=4 ngc=extend_m1 + +[EMCMOT] +# base freq = 20kHz +# servo freq = 1kHz +EMCMOT = motmod +COMM_TIMEOUT = 1.0 +#BASE_PERIOD = 35000 +BASE_PERIOD = 50000 +SERVO_PERIOD = 1000000 + +[HAL] +HALUI = halui +HALFILE = my-emco-compact-5.hal +HALFILE = custom.hal +POSTGUI_HALFILE = custom_postgui.hal + +[HALUI] +# add halui MDI commands here (max 64) +MDI_COMMAND = O call [100] ;0, connected to mpg button +MDI_COMMAND = O call [100] ;1, connected to mpg button +MDI_COMMAND = O call ;2, connected to mpg button +MDI_COMMAND = O call [0.48483] [20.16466] ;3, spindle speed selection AC1 +MDI_COMMAND = O call [0.32571] [-8.05714] ;4, spindle speed selection AC2 +MDI_COMMAND = O call [0.20098] [22.64117] ;5, spindle speed selection AC3 +MDI_COMMAND = O call [#4998] [#4999] ;6, called to set saved spindle + ; speed selection after homing + +[KINS] +KINEMATICS = trivkins coordinates=XZ +JOINTS = 2 + +[TRAJ] +COORDINATES = X Z +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 2.5 +MAX_LINEAR_VELOCITY = 18 +NO_FORCE_HOMING = 1 +DEFAULT_LINEAR_ACCELERATION = 50.0 +POSITION_FILE = emcopos.txt + +[EMCIO] +EMCIO = io +CYCLE_TIME = 0.100 +TOOL_TABLE = tool.tbl + +[AXIS_X] +MIN_LIMIT = -2500.0 +MAX_LIMIT = 2500.0 +MAX_VELOCITY = 12.5 +MAX_ACCELERATION = 500 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 12.5 +MAX_ACCELERATION = 500 +STEPGEN_MAXACCEL = 625 + +#steps/rev = 72, 0.125 mm/9 steps => 72*(0.125/9) mm/rev +#scale = 72/[72*0.125/9] = 72/(72/72) = 72 steps/mm +SCALE = 72 + +FERROR = 1.0 +MIN_FERROR = 0.25 +MIN_LIMIT = -2500.0 +MAX_LIMIT = 2500.0 +HOME_OFFSET = 0.0 + +[AXIS_Z] +MIN_LIMIT = -2500.0 +MAX_LIMIT = 2500.0 +MAX_VELOCITY = 12.5 +MAX_ACCELERATION = 500 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 12.5 +MAX_ACCELERATION = 500 +STEPGEN_MAXACCEL = 625 + +#steps/rev = 72, 0.125 mm/9 steps => 72*(0.125/9) mm/rev +#scale = 72/[72*0.125/9] = 72 steps/mm +SCALE = 72 + +FERROR = 1.0 +MIN_FERROR = 0.25 +MIN_LIMIT = -2500.0 +MAX_LIMIT = 2500.0 +HOME_OFFSET = 0.0 diff --git a/my-emco-compact-5/my-emco-compact-5.pref b/my-emco-compact-5/my-emco-compact-5.pref new file mode 100644 index 0000000..bff4627 --- /dev/null +++ b/my-emco-compact-5/my-emco-compact-5.pref @@ -0,0 +1,85 @@ +[DEFAULT] +dro_digits = 3 +dro_size = 28 +abs_color = #0000FF +rel_color = #000000 +dtg_color = #FFFF00 +homed_color = #00FF00 +unhomed_color = #FF0000 +enable_dro = False +scale_jog_vel = 7.5 +scale_spindle_override = 1 +scale_feed_override = 1 +scale_rapid_override = 1 +spindle_bar_min = 0.0 +spindle_bar_max = 6000.0 +turtle_jog_factor = 20 +hide_turtle_jog_button = False +unlock_code = 123 +toggle_readout = True +spindle_start_rpm = 300.0 +view = y +blockheight = 0.0 +open_file = +screen1 = window +x_pos = 40 +y_pos = 30 +width = 979 +height = 750 +use_toolmeasurement = False +gtk_theme = Follow System Theme +grid_size = 1.0 +mouse_btn_mode = 4 +hide_cursor = False +system_name_tool = Tool +system_name_g5x = G5x +system_name_rot = Rot +system_name_g92 = G92 +system_name_g54 = G54 +system_name_g55 = G55 +system_name_g56 = G56 +system_name_g57 = G57 +system_name_g58 = G58 +system_name_g59 = G59 +system_name_g59.1 = G59.1 +system_name_g59.2 = G59.2 +system_name_g59.3 = G59.3 +jump_to_dir = /home/johan +show_keyboard_on_offset = False +show_keyboard_on_tooledit = False +show_keyboard_on_edit = False +show_keyboard_on_mdi = False +x_pos_popup = 45.0 +y_pos_popup = 55 +width_popup = 250.0 +max_messages = 10 +message_font = sans 10 +use_frames = True +reload_tool = False +blockdel = False +show_offsets = False +show_dtg = False +view_tool_path = True +view_dimension = True +run_from_line = no_run +unlock_way = use +show_preview_on_offset = False +use_keyboard_shortcuts = False +tool_in_spindle = 3 +radius offset_axis_x = 0 +offset_axis_x = 19.25 +offset_axis_z = 0.0 +hide_tooltips = False +diameter offset_axis_x = 0 +kbd_height = 250 +kbd_width = 880 +kbd_set_height = False +kbd_set_width = False +hide_titlebar = False +icon_theme = classic +gcode_theme = classic +audio_enabled = True +audio_alert = /usr/share/sounds/freedesktop/stereo/dialog-warning.oga +audio_error = /usr/share/sounds/freedesktop/stereo/dialog-error.oga +show_keyboard_on_file_selection = False + diff --git a/my-emco-compact-5/postgui_call_list.hal b/my-emco-compact-5/postgui_call_list.hal new file mode 100644 index 0000000..cc704b3 --- /dev/null +++ b/my-emco-compact-5/postgui_call_list.hal @@ -0,0 +1,6 @@ +# These files are loaded post GUI, in the order they appear +# Generated by stepconf 1.1 at Mon Mar 14 20:22:34 2022 +# If you make changes to this file, they will be +# overwritten when you run stepconf again + +source custom_postgui.hal diff --git a/my-emco-compact-5/python/remap.py b/my-emco-compact-5/python/remap.py new file mode 100644 index 0000000..e1f6685 --- /dev/null +++ b/my-emco-compact-5/python/remap.py @@ -0,0 +1 @@ +from stdglue import * diff --git a/my-emco-compact-5/python/stdglue.py b/my-emco-compact-5/python/stdglue.py new file mode 100644 index 0000000..d501af0 --- /dev/null +++ b/my-emco-compact-5/python/stdglue.py @@ -0,0 +1,672 @@ +#NOTE: +# The legacy names *selected_pocket* and *current_pocket* actually reference +# a sequential tooldata index for tool items loaded from a tool +# table ([EMCIO]TOOL_TABLE) or via a tooldata database ([EMCIO]DB_PROGRAM) + +# stdglue - canned prolog and epilog functions for the remappable builtin codes (T,M6,M61,S,F) +# +# we dont use argspec to avoid the generic error message of the argspec prolog and give more +# concise ones here + +# cycle_prolog,cycle_epilog: generic code-independent support glue for oword sub cycles +# +# these are provided as starting point - for more concise error message you would better +# write a prolog specific for the code +# +# Usage: +#REMAP=G84.3 modalgroup=1 argspec=xyzqp prolog=cycle_prolog ngc=g843 epilog=cycle_epilog + +import emccanon +from interpreter import * +from emccanon import MESSAGE +throw_exceptions = 1 + +# used so screens can get info. +# add this to toplevel to call it: + +# import remap +# def __init__(self): +# if self.task: +# remap.build_hal(self) + +def build_hal(self): + import hal + try: + h=hal.component('remapStat') + h.newpin("tool", hal.HAL_S32, hal.HAL_OUT) + h.newpin("wear", hal.HAL_S32, hal.HAL_OUT) + h.ready() + self.hal_tool_comp = h + except Exception as e: + print(e) + +# REMAP=S prolog=setspeed_prolog ngc=setspeed epilog=setspeed_epilog +# exposed parameter: # + +def setspeed_prolog(self,**words): + try: + c = self.blocks[self.remap_level] + if not c.s_flag: + self.set_errormsg("S requires a value") + return INTERP_ERROR + self.params["speed"] = c.s_number + except Exception as e: + self.set_errormsg("S/setspeed_prolog: %s)" % (e)) + return INTERP_ERROR + return INTERP_OK + +def setspeed_epilog(self,**words): + try: + if not self.value_returned: + r = self.blocks[self.remap_level].executing_remap + self.set_errormsg("the %s remap procedure %s did not return a value" + % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) + return INTERP_ERROR + if self.return_value < -TOLERANCE_EQUAL: # 'less than 0 within interp's precision' + self.set_errormsg("S: remap procedure returned %f" % (self.return_value)) + return INTERP_ERROR + if self.blocks[self.remap_level].builtin_used: + pass + #print "---------- S builtin recursion, nothing to do" + else: + self.speed[0] = self.params["speed"] + emccanon.enqueue_SET_SPINDLE_SPEED(self.speed[0]) + return INTERP_OK + except Exception as e: + self.set_errormsg("S/setspeed_epilog: %s)" % (e)) + return INTERP_ERROR + return INTERP_OK + +# REMAP=F prolog=setfeed_prolog ngc=setfeed epilog=setfeed_epilog +# exposed parameter: # + +def setfeed_prolog(self,**words): + try: + c = self.blocks[self.remap_level] + if not c.f_flag: + self.set_errormsg("F requires a value") + return INTERP_ERROR + self.params["feed"] = c.f_number + except Exception as e: + self.set_errormsg("F/setfeed_prolog: %s)" % (e)) + return INTERP_ERROR + return INTERP_OK + +def setfeed_epilog(self,**words): + try: + if not self.value_returned: + r = self.blocks[self.remap_level].executing_remap + self.set_errormsg("the %s remap procedure %s did not return a value" + % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) + return INTERP_ERROR + if self.blocks[self.remap_level].builtin_used: + pass + #print "---------- F builtin recursion, nothing to do" + else: + self.feed_rate = self.params["feed"] + emccanon.enqueue_SET_FEED_RATE(self.feed_rate) + return INTERP_OK + except Exception as e: + self.set_errormsg("F/setfeed_epilog: %s)" % (e)) + return INTERP_ERROR + return INTERP_OK + +# REMAP=T prolog=prepare_prolog ngc=prepare epilog=prepare_epilog +# exposed parameters: # # + +def prepare_prolog(self,**words): + try: + cblock = self.blocks[self.remap_level] + if not cblock.t_flag: + self.set_errormsg("T requires a tool number") + return INTERP_ERROR + tool = cblock.t_number + if tool: + (status, pocket) = self.find_tool_pocket(tool) + if status != INTERP_OK: + self.set_errormsg("T%d: pocket not found" % (tool)) + return status + else: + pocket = -1 # this is a T0 - tool unload + self.params["tool"] = tool + self.params["pocket"] = pocket + return INTERP_OK + except Exception as e: + self.set_errormsg("T%d/prepare_prolog: %s" % (int(words['t']), e)) + return INTERP_ERROR + +def prepare_epilog(self, **words): + try: + if not self.value_returned: + r = self.blocks[self.remap_level].executing_remap + self.set_errormsg("the %s remap procedure %s did not return a value" + % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) + return INTERP_ERROR + if self.blocks[self.remap_level].builtin_used: + #print "---------- T builtin recursion, nothing to do" + return INTERP_OK + else: + if self.return_value > 0: + self.selected_tool = int(self.params["tool"]) + self.selected_pocket = int(self.params["pocket"]) + emccanon.SELECT_TOOL(self.selected_tool) + return INTERP_OK + else: + self.set_errormsg("T%d: aborted (return code %.1f)" % (int(self.params["tool"]),self.return_value)) + return INTERP_ERROR + except Exception as e: + self.set_errormsg("T%d/prepare_epilog: %s" % (tool,e)) + return INTERP_ERROR + +# REMAP=M6 modalgroup=6 prolog=change_prolog ngc=change epilog=change_epilog +# exposed parameters: +# # +# # +# # +# # + +def change_prolog(self, **words): + try: + # this is relevant only when using iocontrol-v2. + if self.params[5600] > 0.0: + if self.params[5601] < 0.0: + self.set_errormsg("Toolchanger hard fault %d" % (int(self.params[5601]))) + return INTERP_ERROR + print("change_prolog: Toolchanger soft fault %d" % int(self.params[5601])) + + if self.selected_pocket < 0: + self.set_errormsg("M6: no tool prepared") + return INTERP_ERROR + if self.cutter_comp_side: + self.set_errormsg("Cannot change tools with cutter radius compensation on") + return INTERP_ERROR + self.params["tool_in_spindle"] = self.current_tool + self.params["selected_tool"] = self.selected_tool + self.params["current_pocket"] = self.current_pocket + self.params["selected_pocket"] = self.selected_pocket + return INTERP_OK + except Exception as e: + self.set_errormsg("M6/change_prolog: %s" % (e)) + return INTERP_ERROR + +def change_epilog(self, **words): + try: + if not self.value_returned: + r = self.blocks[self.remap_level].executing_remap + self.set_errormsg("the %s remap procedure %s did not return a value" + % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) + yield INTERP_ERROR + # this is relevant only when using iocontrol-v2. + if self.params[5600] > 0.0: + if self.params[5601] < 0.0: + self.set_errormsg("Toolchanger hard fault %d" % (int(self.params[5601]))) + yield INTERP_ERROR + print("change_epilog: Toolchanger soft fault %d" % int(self.params[5601])) + + if self.blocks[self.remap_level].builtin_used: + #print "---------- M6 builtin recursion, nothing to do" + yield INTERP_OK + else: + if self.return_value > 0.0: + # commit change + self.selected_pocket = int(self.params["selected_pocket"]) + emccanon.CHANGE_TOOL(self.selected_pocket) + self.current_pocket = self.selected_pocket + self.selected_pocket = -1 + self.selected_tool = -1 + # cause a sync() + self.set_tool_parameters() + self.toolchange_flag = True + yield INTERP_EXECUTE_FINISH + else: + # yield to print any messages from the NGC program + yield INTERP_EXECUTE_FINISH + self.set_errormsg("M6 aborted (return code %.1f)" % (self.return_value)) + yield INTERP_ERROR + except Exception as e: + self.set_errormsg("M6/change_epilog: %s" % (e)) + yield INTERP_ERROR + +# REMAP=M61 modalgroup=6 prolog=settool_prolog ngc=settool epilog=settool_epilog +# exposed parameters: # # + +def settool_prolog(self,**words): + try: + c = self.blocks[self.remap_level] + if not c.q_flag: + self.set_errormsg("M61 requires a Q parameter") + return INTERP_ERROR + tool = int(c.q_number) + if tool < -TOLERANCE_EQUAL: # 'less than 0 within interp's precision' + self.set_errormsg("M61: Q value < 0") + return INTERP_ERROR + (status,pocket) = self.find_tool_pocket(tool) + if status != INTERP_OK: + self.set_errormsg("M61 failed: requested tool %d not in table" % (tool)) + return status + self.params["tool"] = tool + self.params["pocket"] = pocket + return INTERP_OK + except Exception as e: + self.set_errormsg("M61/settool_prolog: %s)" % (e)) + return INTERP_ERROR + +def settool_epilog(self,**words): + try: + if not self.value_returned: + r = self.blocks[self.remap_level].executing_remap + self.set_errormsg("the %s remap procedure %s did not return a value" + % (r.name,r.remap_ngc if r.remap_ngc else r.remap_py)) + return INTERP_ERROR + + if self.blocks[self.remap_level].builtin_used: + #print "---------- M61 builtin recursion, nothing to do" + return INTERP_OK + else: + if self.return_value > 0.0: + self.current_tool = int(self.params["tool"]) + self.current_pocket = int(self.params["pocket"]) + emccanon.CHANGE_TOOL_NUMBER(self.current_pocket) + # cause a sync() + self.tool_change_flag = True + self.set_tool_parameters() + else: + self.set_errormsg("M61 aborted (return code %.1f)" % (self.return_value)) + return INTERP_ERROR + except Exception as e: + self.set_errormsg("M61/settool_epilog: %s)" % (e)) + return INTERP_ERROR + +# educational alternative: M61 remapped to an all-Python handler +# demo - this really does the same thing as the builtin (non-remapped) M61 +# +# REMAP=M61 modalgroup=6 python=set_tool_number + +def set_tool_number(self, **words): + try: + c = self.blocks[self.remap_level] + if c.q_flag: + toolno = int(c.q_number) + else: + self.set_errormsg("M61 requires a Q parameter") + return status + (status,pocket) = self.find_tool_pocket(toolno) + if status != INTERP_OK: + self.set_errormsg("M61 failed: requested tool %d not in table" % (toolno)) + return status + if words['q'] > -TOLERANCE_EQUAL: # 'greater equal 0 within interp's precision' + self.current_pocket = pocket + self.current_tool = toolno + emccanon.CHANGE_TOOL_NUMBER(pocket) + # cause a sync() + self.tool_change_flag = True + self.set_tool_parameters() + return INTERP_OK + else: + self.set_errormsg("M61 failed: Q=%4" % (toolno)) + return INTERP_ERROR + except Exception as e: + self.set_errormsg("M61/set_tool_number: %s" % (e)) + return INTERP_ERROR + +_uvw = ("u","v","w","a","b","c") +_xyz = ("x","y","z","a","b","c") +# given a plane, return sticky words, incompatible axis words and plane name +# sticky[0] is also the movement axis +_compat = { + emccanon.CANON_PLANE_XY : (("z","r"),_uvw,"XY"), + emccanon.CANON_PLANE_YZ : (("x","r"),_uvw,"YZ"), + emccanon.CANON_PLANE_XZ : (("y","r"),_uvw,"XZ"), + emccanon.CANON_PLANE_UV : (("w","r"),_xyz,"UV"), + emccanon.CANON_PLANE_VW : (("u","r"),_xyz,"VW"), + emccanon.CANON_PLANE_UW : (("v","r"),_xyz,"UW")} + +# extract and pass parameters from current block, merged with extra parameters on a continuation line +# keep tjose parameters across invocations +# export the parameters into the oword procedure +def cycle_prolog(self,**words): + # self.sticky_params is assumed to have been initialized by the + # init_stgdlue() method below + global _compat + try: + # determine whether this is the first or a subsequent call + c = self.blocks[self.remap_level] + r = c.executing_remap + if c.g_modes[1] == r.motion_code: + # first call - clear the sticky dict + self.sticky_params[r.name] = dict() + + self.params["motion_code"] = c.g_modes[1] + + (sw,incompat,plane_name) =_compat[self.plane] + for (word,value) in list(words.items()): + # inject current parameters + self.params[word] = value + # record sticky words + if word in sw: + if self.debugmask & 0x00080000: print("%s: record sticky %s = %.4f" % (r.name,word,value)) + self.sticky_params[r.name][word] = value + if word in incompat: + return "%s: Cannot put a %s in a canned cycle in the %s plane" % (r.name, word.upper(), plane_name) + + # inject sticky parameters which were not in words: + for (key,value) in list(self.sticky_params[r.name].items()): + if not key in words: + if self.debugmask & 0x00080000: print("%s: inject sticky %s = %.4f" % (r.name,key,value)) + self.params[key] = value + + if not "r" in self.sticky_params[r.name]: + return "%s: cycle requires R word" % (r.name) + else: + if self.sticky_params[r.name]['r'] <= 0.0: + return "%s: R word must be > 0 if used (%.4f)" % (r.name, words["r"]) + + if "l" in words: + # checked in interpreter during block parsing + # if l <= 0 or l not near an int + self.params["l"] = words["l"] + + if "p" in words: + p = words["p"] + if p < 0.0: + return "%s: P word must be >= 0 if used (%.4f)" % (r.name, p) + self.params["p"] = p + + if self.feed_rate == 0.0: + return "%s: feed rate must be > 0" % (r.name) + if self.feed_mode == INVERSE_TIME: + return "%s: Cannot use inverse time feed with canned cycles" % (r.name) + if self.cutter_comp_side: + return "%s: Cannot use canned cycles with cutter compensation on" % (r.name) + return INTERP_OK + + except Exception as e: + raise + return "cycle_prolog failed: %s" % (e) + +# make sure the next line has the same motion code, unless overridden by a +# new G-code +def cycle_epilog(self,**words): + try: + c = self.blocks[self.remap_level] + self.motion_mode = c.executing_remap.motion_code # retain the current motion mode + return INTERP_OK + except Exception as e: + return "cycle_epilog failed: %s" % (e) + +# this should be called from TOPLEVEL __init__() +def init_stdglue(self): + self.sticky_params = dict() + +##################################### +# pure python remaps +##################################### + +# REMAP=M6 python=ignore_m6 +# +# m5 silently ignored +# +def ignore_m6(self,**words): + try: + return INTERP_OK + except Exception as e: + return "Ignore M6 failed: %s" % (e) + +# REMAP=T python=index_lathe_tool_with_wear +# +# uses T101 for tool 1, wear 1 no M6 needed +# tool offsets for tool 1 and tool 10001 are added together. +# +def index_lathe_tool_with_wear(self,**words): + # only run this if we are really moving the machine + # skip this if running task for the screen + if not self.task: + yield INTERP_OK + try: + # check there is a tool number from the Gcode + cblock = self.blocks[self.remap_level] + if not cblock.t_flag: + self.set_errormsg("T requires a tool number") + yield INTERP_ERROR + tool_raw = int(cblock.t_number) + + # interpret the raw tool number into tool and wear number + # If it's less then 100 someone forgot to add the wear #, so we added it automatically + # separate out tool number (tool) and wear number (wear), add 10000 to wear number + if tool_raw <100: + tool_raw=tool_raw*100 + tool = int(tool_raw/100) + wear = 10000 + tool_raw % 100 + + # uncomment for debugging + #print'***tool#',cblock.t_number,'toolraw:',tool_raw,'tool split:',tool,'wear split',wear + if tool: + # check for tool number entry in tool file + (status, pocket) = self.find_tool_pocket(tool) + if status != INTERP_OK: + self.set_errormsg("T%d: tool entry not found" % (tool)) + yield status + else: + tool = -1 + pocket = -1 + wear = -1 + self.params["tool"] = tool + self.params["pocket"] = pocket + self.params["wear"] = wear + try: + self.hal_tool_comp['tool']= tool_raw + self.hal_tool_comp['wear']= wear + except: + pass + # index tool immediately to tool number + self.selected_tool = int(self.params["tool"]) + self.selected_pocket = int(self.params["pocket"]) + emccanon.SELECT_TOOL(self.selected_tool) + if self.selected_pocket < 0: + self.set_errormsg("T0 not valid") + yield INTERP_ERROR + if self.cutter_comp_side: + self.set_errormsg("Cannot change tools with cutter radius compensation on") + yield INTERP_ERROR + self.params["tool_in_spindle"] = self.current_tool + self.params["selected_tool"] = self.selected_tool + self.params["current_pocket"] = self.current_pocket + self.params["selected_pocket"] = self.selected_pocket + + # change tool + try: + self.selected_pocket = int(self.params["selected_pocket"]) + emccanon.CHANGE_TOOL(self.selected_pocket) + self.current_pocket = self.selected_pocket + self.selected_pocket = -1 + self.selected_tool = -1 + # cause a sync() + self.set_tool_parameters() + self.toolchange_flag = True + except: + self.set_errormsg("T change aborted (return code %.1f)" % (self.return_value)) + yield INTERP_ERROR + + # add tool offset + self.execute("g43 h%d"% tool) + # if the wear offset is specified, add it's offset + try: + if wear>10000: + self.execute("g43.2 h%d"% wear) + yield INTERP_OK + except: + self.set_errormsg("Tool change aborted - No wear %d entry found in tool table" %wear) + yield INTERP_ERROR + except: + self.set_errormsg("Tool change aborted (return code %.1f)" % (self.return_value)) + yield INTERP_ERROR + + +# REMAP=M6 modalgroup=10 python=tool_probe_m6 +# +# auto tool probe on m6 +# move to tool change position for toolchange +# wait for acknowledge of tool change +# move to tool setter probe position +# probe tool on tool setter +# move back to tool change position +# set offsets +# based on Versaprobe remap +# +# param 5000 holds the work piece height +# param 4999 should be set to 1 if the +# machine is based in imperial +# +# required INI settings +# (Abs coordinates/ machine based units) +# +#[CHANGE_POSITION] +#X = 5 +#Y = 0 +#Z = 0 + +#[TOOLSENSOR] +#X = 5.00 +#Y = -1 +#Z = -1 +#PROBEHEIGHT = 2.3 +#MAXPROBE = -3 +#SEARCH_VEL = 20 +#PROBE_VEL = 5 + +def tool_probe_m6(self, **words): + + # only run this if we are really moving the machine + # skip this if running task for the screen + if not self.task: + yield INTERP_OK + + IMPERIAL_BASED = not(bool(self.params['_metric_machine'])) + + try: + # we need to be in machine based units + # if we aren't - switch + # remember so we can switch back later + switchUnitsFlag = False + if bool(self.params["_imperial"]) != IMPERIAL_BASED: + print ("not right Units: {}".format(bool(self.params["_imperial"]))) + if IMPERIAL_BASED: + print ("switched Units to imperial") + self.execute("G20") + else: + print ("switched Units to metric") + self.execute("G21") + switchUnitsFlag = True + + self.params["tool_in_spindle"] = self.current_tool + self.params["selected_tool"] = self.selected_tool + self.params["current_pocket"] = self.current_pocket + self.params["selected_pocket"] = self.selected_pocket + + # cancel tool offset + self.execute("G49") + + # change tool where ever we are + # user sets toolchange position prior to toolchange + # we will return here after + + try: + self.selected_pocket = int(self.params["selected_pocket"]) + emccanon.CHANGE_TOOL(self.selected_pocket) + self.current_pocket = self.selected_pocket + self.selected_pocket = -1 + self.selected_tool = -1 + # cause a sync() + self.set_tool_parameters() + self.toolchange_flag = True + except InterpreterException as e: + self.set_errormsg("tool_probe_m6 remap error: %s" % (e)) + yield INTERP_ERROR + + yield INTERP_EXECUTE_FINISH + + # record current position; probably should record every axis + self.params[4999] = emccanon.GET_EXTERNAL_POSITION_X() + self.params[4998] = emccanon.GET_EXTERNAL_POSITION_Y() + self.params[4997] = emccanon.GET_EXTERNAL_POSITION_Z() + + try: + # move to tool probe position (from INI) + self.execute("G90") + self.execute("G53 G0 X[#<_ini[TOOLSENSOR]X>] Y[#<_ini[TOOLSENSOR]Y>]") + self.execute("G53 G0 Z[#<_ini[TOOLSENSOR]Z>]") + + # set incremental mode + self.execute("G91") + + # course probe + self.execute("F [#<_ini[TOOLSENSOR]SEARCH_VEL>]") + self.execute("G38.2 Z [#<_ini[TOOLSENSOR]MAXPROBE>]") + + # Wait for results + yield INTERP_EXECUTE_FINISH + + # FIXME if there is an error it never comes back + # which leaves linuxcnc in g91 state + if self.params[5070] == 0 or self.return_value > 0.0: + self.execute("G90") + self.set_errormsg("tool_probe_m6 remap error:") + yield INTERP_ERROR + + # rapid up off trigger point to do it again + if bool(self.params["_imperial"]): + f = 0.25 + else: + f = 4.0 + self.execute("G0 Z{}".format(f)) + + self.execute("F [#<_ini[TOOLSENSOR]PROBE_VEL>]") + self.execute("G38.2 Z-0.5") + yield INTERP_EXECUTE_FINISH + + # FIXME if there is an error it never comes back + # which leaves linuxcnc in g91 state + if self.params[5070] == 0 or self.return_value > 0.0: + self.execute("G90") + self.set_errormsg("tool_probe_m6 remap error:") + yield INTERP_ERROR + + # set back absolute state + self.execute("G90") + + # return to recorded tool change position + self.execute("G53 G0 Z[#4997]") + yield INTERP_EXECUTE_FINISH + self.execute("G53 G0 X[#4999] Y[#4998]") + + # adjust tool offset from calculations + proberesult = self.params[5063] + probeheight = self.params["_ini[TOOLSENSOR]PROBEHEIGHT"] + workheight = self.params[5000] + + adj = proberesult - probeheight + workheight + self.execute("G10 L1 P# Z{}".format(adj)) + + # apply tool offset + self.execute("G43") + + # if we switched units for tool change - switch back + if switchUnitsFlag: + if IMPERIAL_BASED: + self.execute("G21") + print ("switched Units back to metric") + else: + self.execute("G20") + print ("switched Units back to imperial") + + except InterpreterException as e: + msg = "%d: '%s' - %s" % (e.line_number,e.line_text, e.error_message) + print (msg) + yield INTERP_ERROR + + except: + self.set_errormsg("tool_probe_m6 remap error." ) + yield INTERP_ERROR + + + diff --git a/my-emco-compact-5/python/toplevel.py b/my-emco-compact-5/python/toplevel.py new file mode 100644 index 0000000..0dc38fa --- /dev/null +++ b/my-emco-compact-5/python/toplevel.py @@ -0,0 +1 @@ +import remap diff --git a/my-emco-compact-5/serialEventHandler.py b/my-emco-compact-5/serialEventHandler.py new file mode 100644 index 0000000..8514707 --- /dev/null +++ b/my-emco-compact-5/serialEventHandler.py @@ -0,0 +1,347 @@ +#! /usr/bin/python +"""usage serialEventHanlder.py -h -c -d/--debug= -p/--port= in_file.xml +in_file - input xml-file describing what knobs and/or button are on the pendant +-c # name of component in HAL. 'my-mpg' default +-d/--debug= # debug level, default 0 +-p/--port= # serial port to use. '/dev/ttyUSB0' default +-h # Help +python serialEventHandler.py -w mpg_pendant/config/mpg.xml +""" + +### https://docs.python.org/2/library/xml.etree.elementtree.html + +import time +import getopt +import sys +import comms +import xml.etree.ElementTree as ET +import hal +from collections import namedtuple + +class Pin: + """ General representation of a Pin and it's data""" + def __init__(self, name, type, observer = None): + self.name = name # HAL pin name + self.val = 0 # current value of pin, e.g. 1 - on, 0 - off + self.type = type # type (string read from xml) + self.observer = None + + if observer != None: + self.attach(observer) + + def __repr__(self): + return 'pin name: ' + self.name + '\tval: ' + str(self.val) + '\ttype: ' + self.type + + def attach(self, observer): + self.observer = observer + + def _notify(self): + if self.observer != None: + self.observer.update(self.name, self.val) + + def update_hal(self, v): + """ to be overriden in child-class""" + pass + + def set(self, v): + pass + + def _type_saturate(self, type, val): + """ helper function to convert type read from xml to HAL-type """ + retVal = 0 + + if type == 'bit': + if val >= 1: + retVal = 1 + + if type == 'float': + retVal = val + + if type == 's32': + retVal = val + + if type == 'u32': + retVal = val + + return retVal + + def _get_hal_type(self, str): + """ helper function to convert type read from xml to HAL-type """ + retVal = '' + + if str == 'bit': + retVal = hal.HAL_BIT + + if str == 'float': + retVal = hal.HAL_FLOAT + + if str == 's32': + retVal = hal.HAL_S32 + + if str == 'u32': + retVal = hal.HAL_U32 + + return retVal + +class InPin(Pin): + """ Specialization of Pin-class""" + def __init__(self, hal_ref, name, type, observer = None): + Pin.__init__(self, name, type, observer) + + hal_ref.newpin(name, self._get_hal_type(type), hal.HAL_IN) # create the user space HAL-pin + + def __repr__(self): + return 'Input pin ' + Pin.__repr__(self) + + def update_hal(self, hal): + if self.val != hal[self.name]: + self.val = hal[self.name] + self._notify() + +class OutPin(Pin): + """ Specialization of Pin-class""" + def __init__(self, hal_ref, name, type, observer = None): + Pin.__init__(self, name, type, observer) + + hal_ref.newpin(name, self._get_hal_type(type), hal.HAL_OUT) # create the user space HAL-pin + + def __repr__(self): + return 'Output pin ' + Pin.__repr__(self) + + def update_hal(self, hal): + hal[self.name] = self.val + + def set(self, v): + try: + self.val = self._type_saturate(self.type, int(v)) + except ValueError: + print('OutPin::set() value error catched on: ' + self.name) + +class Observer: + """ container for notification-function """ + def __init__(self, update_cb): + self.update_cb = update_cb + + def update(self, name, val): + #pass + try: + #print 'observer::update name: ' + name + ' val: ' + str(val) + self.update_cb(name, val) + except ValueError: + print('Observer::notify() value error catched on: ' + self.name) + +class HALComponentWrapper: + def __init__(self, name): + self.pin_dict = {} # dictionary used to map event to pin + self.hal = hal.component(name) # instanciate the HAL-component + self.observer = None + + def __repr__(self): + tmp_str = '' + for k in self.pin_dict: + tmp_str += 'event: ' + k + '\t' + str(self.pin_dict[k]) + '\n' + return tmp_str + + def __getitem__(self, key): + if key in self.pin_dict: + return self.pin_dict[key].val + + def __setitem__(self, key, val): + self.set_pin(key, val) + + def add_pin(self, event_name, hal_name, type, direction = 'out'): + self.pin_dict[event_name] = self._createPin(hal_name, type, direction) + + def event_set_pin(self, event): + """ updates pin value with new data + input: pin name, set value' + output: nothing. """ + if event.name in self.pin_dict: + self.pin_dict[event.name].set(event.data) + + def set_pin(self, key, value): + """ updates pin value with new data + input: event name, set value' + output: nothing. """ + if key in self.pin_dict: + self.pin_dict[key].set(value) + + def setReady(self): + self.hal.ready() + + def update_hal(self): + for key in self.pin_dict: + self.pin_dict[key].update_hal(self.hal) + + def attach(self, observer): + self.observer = observer + + def _createPin(self, hal_name, type, direction): + """ factory function to create pin""" + if direction == 'in': + return InPin(self.hal, hal_name, type, Observer(self.notify)) + + if direction == 'out': + return OutPin(self.hal, hal_name, type) + + def notify(self, hal_name, val): + # convert pin-name to event-name + for key in self.pin_dict: + if self.pin_dict[key].name == hal_name and self.observer != None: + self.observer.update(key, val) + +class OptParser: + def __init__(self, argv): + self.xml_file = '' # input xml-file describing what knobs and/or button are on the pendant + self.name = 'my-mpg' # default name of component in HAL + self.port = '/dev/ttyUSB0' # default serial port to use + self.watchdog_reset = False + + self._get_options(argv) + + def __repr__(self): + return 'xml_file: ' + self.xml_file + '\tname: ' + self.name + '\tport: ' + self.port + + def _get_options(self, argv): + try: + opts, args = getopt.getopt(argv, "hwp:c:", ["input=", "port="]) + except getopt.GetoptError as err: + # print help information and exit: + print(err) # will print something like "option -a not recognized" + sys.exit(2) + + ### parse input command line + for o, a in opts: + if o == "-h": + self._usage() + sys.exit() + if o == "-c": + self.name = a + elif o == "--input": + self.xml_file = a + elif o in ("-p", "--port"): + self.port = a + elif o == "-w": + self.watchdog_reset = True + else: + print(o, a) + assert False, "unhandled option" + + if self.xml_file == '': + if len(sys.argv) < 2: + self._usage() + sys.exit(2) + else: + self.xml_file = argv[-1] + + def get_name(self): + return self.name + + def get_port(self): + return self.port + + def get_XML_file(self): + return self.xml_file + + def get_watchdog_reset(self): + return self.watchdog_reset + + def _usage(self): + """ print command line options """ + print("usage serialEventHandler.py -h -c -d/--debug= -p/--port= in_file.xml\n"\ + "in_file - input xml-file describing what knobs and/or button are on the pendant\n"\ + "-c # name of component in HAL. 'mpg' default\n"\ + "-p/--port= # default serial port to use. '/dev/ttyS2' default\n"\ + "-w # start watchdog deamon" \ + "-h # Help test") + +""" Parser data container""" +HalPin = namedtuple("HalPin", ['name', 'event', 'type', 'direction']) + +class XmlParser: + def __init__(self, f): + self.tree = [] + self.parsed_data = [] #array of named tuples (HalPin) + + self._parse_file(f) + + def __repr__(self): + tmp_str = '' + + for element in self.parsed_data: + tmp_str += 'name: ' + element.name + '\t' + 'event: ' + element.event + '\t' + 'type: ' + element.type + '\n' + return tmp_str + + def get_parsed_data(self): + return self.parsed_data + + def _parse_file(self, f): + self.tree = ET.parse(f) + root = self.tree.getroot() + + for halpin in root.iter('halpin'): + name = halpin.text.strip('"') + type = 'u32' if halpin.find('type') is None else halpin.find('type').text + event = name if halpin.find('event') is None else halpin.find('event').text + direction = 'out' if halpin.find('direction') is None else halpin.find('direction').text + + if self._check_supported_HAL_type(type) and self._check_supported_HAL_direction(direction): + self.parsed_data.append(HalPin(name, event, type, direction)) + + def _check_supported_HAL_type(self, str): + """ helper function to check if type is supported """ + retVal = False + + if str == 'bit' or str == 'float' or str == 's32' or str == 'u32': + retVal = True + + return retVal + + def _check_supported_HAL_direction(self, str): + """ helper function to check if direction is supported """ + retVal = False + + if str == 'in' or str == 'out': + retVal = True + + return retVal + +################################################ +def main(): + optParser = OptParser(sys.argv[1:]) + componentName = optParser.get_name() + portName = optParser.get_port() + xmlFile = optParser.get_XML_file() + watchdogEnabled = optParser.get_watchdog_reset() + print(optParser) + + xmlParser = XmlParser(xmlFile) + + c = HALComponentWrapper(componentName) #HAL adaptor, takes care of mapping incomming events to actual hal-pin + serialEventGenerator = comms.instrument(portName, c.event_set_pin, watchdogEnabled, 5, 1) #serial adaptor + c.attach(Observer(serialEventGenerator.generateEvent)) + + # add/create the HAL-pins from parsed xml and attach them to the adaptor event handler + parsed_data = xmlParser.get_parsed_data() + for pin in parsed_data: + c.add_pin(pin.event, pin.name, pin.type, pin.direction) + + print(c) + + # ready signal to HAL, component and it's pins are ready created + c.setReady() + + time.sleep(0.5) + + try: + while 1: + serialEventGenerator.readMessages() #blocks until '\n' received or timeout + c.update_hal() + + time.sleep(0.1) + + except KeyboardInterrupt: + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/my-emco-compact-5/speeds.png b/my-emco-compact-5/speeds.png new file mode 100644 index 0000000..d8b44cf Binary files /dev/null and b/my-emco-compact-5/speeds.png differ diff --git a/my-emco-compact-5/spindle_speed_selector.glade b/my-emco-compact-5/spindle_speed_selector.glade new file mode 100644 index 0000000..7f6145d --- /dev/null +++ b/my-emco-compact-5/spindle_speed_selector.glade @@ -0,0 +1,114 @@ + + + + + + + False + + + + + + True + False + vertical + + + True + False + spindle speed selection: + + + False + True + 0 + + + + + True + False + + + True + False + speeds.png + 3 + + + False + True + 0 + + + + + True + False + + + AC2 + True + True + False + 15 + True + True + radio1 + + + 0 + 1 + + + + + AC3 + True + True + False + 15 + True + True + radio1 + + + 0 + 2 + + + + + AC1 + True + True + False + 15 + True + True + + + 0 + 0 + + + + + False + True + 10 + 1 + + + + + False + True + 1 + + + + + + diff --git a/my-emco-compact-5/spindle_speed_selector.hal b/my-emco-compact-5/spindle_speed_selector.hal new file mode 100644 index 0000000..4e53df7 --- /dev/null +++ b/my-emco-compact-5/spindle_speed_selector.hal @@ -0,0 +1,12 @@ +net all-homed spindle_speed_selector.table1 +net all-homed and2.1.in0 +net all-homed and2.2.in0 +net all-homed and2.3.in0 + +net spindle-speed-selector-panel-radio1 spindle_speed_selector.radio1 and2.1.in1 +net spindle-speed-selector-panel-radio2 spindle_speed_selector.radio2 and2.2.in1 +net spindle-speed-selector-panel-radio3 spindle_speed_selector.radio3 and2.3.in1 + +net and2-1-out and2.1.out halui.mdi-command-03 +net and2-2-out and2.2.out halui.mdi-command-04 +net and2-3-out and2.3.out halui.mdi-command-05 diff --git a/my-emco-compact-5/sync-files.sh b/my-emco-compact-5/sync-files.sh new file mode 100644 index 0000000..1008572 --- /dev/null +++ b/my-emco-compact-5/sync-files.sh @@ -0,0 +1,9 @@ +find . -type f -name "*.py"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.ngc"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.hal"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.ini"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.sh"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.clp"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.tbl"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.var"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 +find . -type f -name "*.xml"|xargs python3 ~/git-clones/linuxcnc-configs/sync-file.py -p -d -c ~/git-clones/linuxcnc-configs/my-emco-compact-5 diff --git a/my-emco-compact-5/test_ladder.clp b/my-emco-compact-5/test_ladder.clp new file mode 100644 index 0000000..51d5cc7 --- /dev/null +++ b/my-emco-compact-5/test_ladder.clp @@ -0,0 +1,334 @@ +_FILES_CLASSICLADDER +_FILE-com_params.txt +MODBUS_MASTER_SERIAL_PORT= +MODBUS_MASTER_SERIAL_SPEED=9600 +MODBUS_MASTER_SERIAL_DATABITS=8 +MODBUS_MASTER_SERIAL_STOPBITS=1 +MODBUS_MASTER_SERIAL_PARITY=0 +MODBUS_ELEMENT_OFFSET=0 +MODBUS_MASTER_SERIAL_USE_RTS_TO_SEND=0 +MODBUS_MASTER_TIME_INTER_FRAME=100 +MODBUS_MASTER_TIME_OUT_RECEIPT=500 +MODBUS_MASTER_TIME_AFTER_TRANSMIT=0 +MODBUS_DEBUG_LEVEL=0 +MODBUS_MAP_COIL_READ=0 +MODBUS_MAP_COIL_WRITE=0 +MODBUS_MAP_INPUT=0 +MODBUS_MAP_HOLDING=0 +MODBUS_MAP_REGISTER_READ=0 +MODBUS_MAP_REGISTER_WRITE=0 +_/FILE-com_params.txt +_FILE-timers.csv +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +_/FILE-timers.csv +_FILE-rung_0.csv +#VER=2.0 +#LABEL= +#COMMENT= +#PREVRUNG=4 +#NEXTRUNG=-1 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +1-0-50/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/20 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/0 , 50-0-60/4 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 9-1-0/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/9 , 50-0-60/5 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +1-0-50/1 , 99-0-0/0 , 99-0-0/0 , 20-0-0/21 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/11 , 50-0-60/6 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 9-1-0/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/13 , 50-0-60/7 +_/FILE-rung_0.csv +_FILE-timers_iec.csv +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +_/FILE-timers_iec.csv +_FILE-ioconf.csv +#VER=1.0 +_/FILE-ioconf.csv +_FILE-sections.csv +#VER=1.0 +#NAME000=Prog1 +000,0,-1,1,0,0 +_/FILE-sections.csv +_FILE-arithmetic_expressions.csv +#VER=2.0 +0000,@270/1@<3 +0001,@270/0@=1 +0002,@270/0@=0 +0003,@270/0@=3 +0004,@270/0@=2 +0005,@270/1@=0 +0006,@310/0@=10 +0007,@270/1@=1 +0008,@310/0@=1 +0009,@270/1@=3 +0010,@270/1@=2 +0011,@270/1@<3 +0012,@310/0@=100 +0013,@270/1@=3 +0020,@270/0@<2 +0021,@270/0@<2 +0022,@270/0@=2 +0024,@270/0@=2 +_/FILE-arithmetic_expressions.csv +_FILE-counters.csv +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +_/FILE-counters.csv +_FILE-rung_2.csv +#VER=2.0 +#LABEL= +#COMMENT= +#PREVRUNG=1 +#NEXTRUNG=4 +99-0-0/0 , 99-0-0/0 , 20-0-0/5 , 9-0-0/5 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 60-0-0/8 +0-0-0/0 , 0-0-0/0 , 0-0-0/6 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/9 +99-0-0/0 , 99-0-0/0 , 20-0-0/7 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 60-0-0/6 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/13 +99-0-0/0 , 99-0-0/0 , 20-0-0/10 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/12 , 60-0-60/12 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +_/FILE-rung_2.csv +_FILE-rung_4.csv +#VER=2.0 +#LABEL= +#COMMENT= +#PREVRUNG=2 +#NEXTRUNG=0 +1-0-50/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/22 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/8 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +1-0-50/1 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 20-0-0/24 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/9 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/23 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +_/FILE-rung_4.csv +_FILE-rung_1.csv +#VER=2.0 +#LABEL= +#COMMENT= +#PREVRUNG=2 +#NEXTRUNG=2 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +99-0-0/0 , 99-0-0/0 , 20-0-0/2 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/0 +99-0-0/0 , 99-0-0/0 , 20-0-0/1 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/1 +99-0-0/0 , 99-0-0/0 , 20-0-0/4 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/2 +99-0-0/0 , 99-0-0/0 , 20-0-0/3 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/3 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +_/FILE-rung_1.csv +_FILE-monostables.csv +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +_/FILE-monostables.csv +_FILE-symbols.csv +#VER=1.0 +%I0,%jog-plus,no signal connected +%I1,%jog-minu, +%I2,%sp-sel1, +%I3,%sp-sel2, +%I4,%sp-sel3, +%I5,%I5, +%I6,%I6, +%I7,%I7, +%I8,%I8, +%I9,%I9, +%I10,%I10, +%I11,%I11, +%I12,%I12, +%I13,%I13, +%I14,%I14, +%Q0,%x-axis, +%Q1,%z-axis, +%Q2,%s-ctrl, +%Q3,%t-ctrl, +%Q4,%jog-inc+, +%Q5,%jog+, +%Q6,%jog-inc-, +%Q7,%jog-, +%Q8,%Q8, +%Q9,%Q9, +%Q10,%Q10, +%Q11,%Q11, +%Q12,%Q12, +%Q13,%Q13, +%Q14,%Q14, +%B0,%B0, +%B1,%B1, +%B2,%B2, +%B3,%B3, +%B4,%B4, +%B5,%B5, +%B6,%B6, +%B7,%B7, +%B8,%B8, +%B9,%B9, +%B10,%B10, +%B11,%B11, +%B12,%B12, +%B13,%B13, +%B14,%B14, +%B15,%B15, +%B16,%B16, +%B17,%B17, +%B18,%B18, +%B19,%B19, +%W0,%W0, +%W1,%W1, +%W2,%W2, +%W3,%W3, +%W4,%W4, +%W5,%W5, +%W6,%W6, +%W7,%W7, +%W8,%W8, +%W9,%W9, +%W10,%W10, +%W11,%W11, +%W12,%W12, +%W13,%W13, +%W14,%W14, +%W15,%W15, +%W16,%W16, +%W17,%W17, +%W18,%W18, +%W19,%W19, +%IW0,%sel-a, +%IW1,%sel-s, +%IW2,%IW2, +%IW3,%IW3, +%IW4,%IW4, +%IW5,%IW5, +%IW6,%IW6, +%IW7,%IW7, +%IW8,%IW8, +%IW9,%IW9, +%QW0,%QW0, +%QW1,%QW1, +%QW2,%QW2, +%QW3,%QW3, +%QW4,%QW4, +%QW5,%QW5, +%QW6,%QW6, +%QW7,%QW7, +%QW8,%QW8, +%QW9,%QW9, +%IF0,%IF0, +%IF1,%IF1, +%IF2,%IF2, +%IF3,%IF3, +%IF4,%IF4, +%IF5,%IF5, +%IF6,%IF6, +%IF7,%IF7, +%IF8,%IF8, +%IF9,%IF9, +%QF0,%scale, +%QF1,%QF1, +%QF2,%QF2, +%QF3,%QF3, +%QF4,%QF4, +%QF5,%QF5, +%QF6,%QF6, +%QF7,%QF7, +%QF8,%QF8, +%QF9,%QF9, +%T0,%T0,Old Timer +%T1,%T1,Old Timer +%T2,%T2,Old Timer +%T3,%T3,Old Timer +%T4,%T4,Old Timer +%T5,%T5,Old Timer +%T6,%T6,Old Timer +%T7,%T7,Old Timer +%T8,%T8,Old Timer +%T9,%T9,Old Timer +%TM0,%TM0,New Timer +%TM1,%TM1,New Timer +%TM2,%TM2,New Timer +%TM3,%TM3,New Timer +%TM4,%TM4,New Timer +%TM5,%TM5,New Timer +%TM6,%TM6,New Timer +%TM7,%TM7,New Timer +%TM8,%TM8,New Timer +%TM9,%TM9,New Timer +%M0,%M0,One-shot +%M1,%M1,One-shot +%M2,%M2,One-shot +%M3,%M3,One-shot +%M4,%M4,One-shot +%M5,%M5,One-shot +%M6,%M6,One-shot +%M7,%M7,One-shot +%M8,%M8,One-shot +%M9,%M9,One-shot +%C0,%C0,Counter +%C1,%C1,Counter +%C2,%C2,Counter +%C3,%C3,Counter +%C4,%C4,Counter +%C5,%C5,Counter +%C6,%C6,Counter +%C7,%C7,Counter +%C8,%C8,Counter +%C9,%C9,Counter +%E0,%E0,Error Flag Bit +%E1,%E1,Error Flag Bit +%E2,%E2,Error Flag Bit +%E3,%E3,Error Flag Bit +%E4,%E4,Error Flag Bit +%E5,%E5,Error Flag Bit +%E6,%E6,Error Flag Bit +%E7,%E7,Error Flag Bit +%E8,%E8,Error Flag Bit +%E9,%E9,Error Flag Bit +_/FILE-symbols.csv +_FILE-general.txt +PERIODIC_REFRESH=50 +SIZE_NBR_RUNGS=100 +SIZE_NBR_BITS=20 +SIZE_NBR_WORDS=20 +SIZE_NBR_TIMERS=10 +SIZE_NBR_MONOSTABLES=10 +SIZE_NBR_COUNTERS=10 +SIZE_NBR_TIMERS_IEC=10 +SIZE_NBR_PHYS_INPUTS=15 +SIZE_NBR_PHYS_OUTPUTS=15 +SIZE_NBR_ARITHM_EXPR=100 +SIZE_NBR_SECTIONS=10 +SIZE_NBR_SYMBOLS=160 +_/FILE-general.txt +_FILE-modbusioconf.csv +#VER=1.0 +_/FILE-modbusioconf.csv +_FILE-sequential.csv +#VER=1.0 +_/FILE-sequential.csv +_/FILES_CLASSICLADDER diff --git a/my-emco-compact-5/tool.tbl b/my-emco-compact-5/tool.tbl new file mode 100644 index 0000000..10c1982 --- /dev/null +++ b/my-emco-compact-5/tool.tbl @@ -0,0 +1,4 @@ +T1 P1 X0.0 Y0.0 Z0.0 A0.0 B0.0 C0.0 U0.0 V0.0 W0.0 D0.4 I87.0 J32.0 Q2.0 ;Right hand +T2 P2 X0.0 Y0.0 Z0.0 A0.0 B0.0 C0.0 U0.0 V0.0 W0.0 D0.4 I93.0 J148.0 Q1.0 ;Left hand +T3 P3 X0.0 Y0.0 Z0.0 A0.0 B0.0 C0.0 U0.0 V0.0 W0.0 D0.4 I117.0 J63.0 Q6.0 ;Neutral +T4 P4 X0.0 Y0.0 Z0.0 A0.0 B0.0 C0.0 U0.0 V0.0 W0.0 D0.1 I0.0 J0.0 Q6.0 ;Stick diff --git a/my-emco-compact-5/watchdog.py b/my-emco-compact-5/watchdog.py new file mode 100644 index 0000000..365d086 --- /dev/null +++ b/my-emco-compact-5/watchdog.py @@ -0,0 +1,93 @@ +#! /usr/bin/python +import time +import threading +import sys + +class WatchDog(): + def __init__(self, timeout): + self.timeout = timeout + self.last_ping_time = time.time() + + def ping(self): + self.last_ping_time = time.time() + + def check(self): + if time.time() - self.last_ping_time > self.timeout: + self.last_ping_time = time.time() #reset tick time + return True + else: + return False + + def insideMargin(self): + if time.time() - self.last_ping_time <= self.timeout: + return True + else: + self.last_ping_time = time.time() #reset tick time + return False + + +class WatchDogDaemon(threading.Thread): + def __init__(self, timeout, periodicity, enable = True): + self.wd = WatchDog(timeout) + self.periodicity = periodicity + self.enabled = enable + self._start() + + def _start(self): + threading.Thread.__init__(self) + self.daemon = True + self.start() + + def ping(self): + self.wd.ping() + + def run(self): + print("Starting watchdog deamon...") + while(self.enabled): + time.sleep(self.periodicity) + + if not self.wd.insideMargin(): + self.reset() + + print("stopping watchdog deamon...") + + def setEnabled(self, enabled): + if self.enabled == False and enabled == True: + self.enabled = True + self.wd.ping() # reset tick time + self._start() + + if enabled == False: + self.enabled = False + + def reset(self): + """to be overriden by client""" + pass + + +def reset(): + print('reset') + +def main(): + i = 0 + wdd = WatchDogDaemon(2, 0.5, False) + wdd.reset = reset + try: + while 1: + time.sleep(1) + print('main_' + str(i)) + print(wdd.is_alive()) + i = i+1 + + if i == 5 or i == 15: + wdd.setEnabled(True) + if i == 10: + wdd.setEnabled(False) + + wdd.ping() + + except KeyboardInterrupt: + raise SystemExit + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/my-emco/Misc/kopplingar.txt b/my-emco/Misc/kopplingar.txt new file mode 100644 index 0000000..c38b282 --- /dev/null +++ b/my-emco/Misc/kopplingar.txt @@ -0,0 +1,45 @@ +Märkning I/O Beskrivning +---------------------------------------------------------------------------- + P1 + P2 X step + P3 X dir + P4 Y step + P5 Y dir + P6 Z step + P7 Z dir + +R1 P8 (i/o-kort) Relä spindel CW +R2 P9 -"- Relä oljepump, spindel +M2 P14 -"- MOS-FET tryckluftsventil dimsmörjning + P16 -"- PWM spindel +M1 P17 -"- MOS-FET tryckluftsventil, spindel + + +P1 P10 -"- Z proximity sensor, home position +P2 P11 -"- Y proximity sensor, home and max position +P3 P12 -"- X proximity sensor, home and max position + P13 + P15 + +brun/PHASE1(A) encoder phaseA+ +grå/PHASE2(B) encoder phaseB+ +röd/PHASE3(Z) encoder phaseZ+, index pulse +blå 5V supply encoder +2st vit GND encoder + + + + + + +#P4 X rotations sensor, per ledstångsvarvvarv +#P5 Y rotations sensor, per ledstångsvarvvarv +#P6 Z rotations sensor, per ledstångsvarvvarv + +#COL1 P12 (i/o-kort) collector transistor1, downsampled phaseA +#COL2 P13 (i/o-kort) collector transistor2, downsampled phaseB +#COL3 P15 (i/o-kort) collector transistor3, pulse stretched phaseZ index + +#BASE1 D3 (arduino) base transistor1, downsampled phaseA +#BASE2 D5 (arduino) base transistor2, downsampled phaseB +#BASE3 D7 (arduino) base transistor3, downsampled phaseZ index diff --git a/my-emco/Misc/pid-tuning.ods b/my-emco/Misc/pid-tuning.ods new file mode 100644 index 0000000..1fef7fb Binary files /dev/null and b/my-emco/Misc/pid-tuning.ods differ diff --git a/my-emco/comms.py b/my-emco/comms.py new file mode 100644 index 0000000..fe22c55 --- /dev/null +++ b/my-emco/comms.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# list available ports with 'python -m serial.tools.list_ports' +import serial +import watchdog + +## Default values ## +BAUDRATE = 38400 +"""Default value for the baudrate in Baud (int).""" + +PARITY = 'N' #serial.PARITY_NONE +"""Default value for the parity. See the pySerial module for documentation. Defaults to serial.PARITY_NONE""" + +BYTESIZE = 8 +"""Default value for the bytesize (int).""" + +STOPBITS = 1 +"""Default value for the number of stopbits (int).""" + +TIMEOUT = 0.05 +"""Default value for the timeout value in seconds (float).""" + +CLOSE_PORT_AFTER_EACH_CALL = False +"""Default value for port closure setting.""" + + +class Message: + """'container for messages. keeps two strings and """ + def __init__(self, name = '', data = ''): + self.name = name + self.data = data + + def __repr__(self): + return 'msg: ' + self.name + ' val: ' + self.data + + def copy(self, msg): + self.name = msg.name + self.data = msg.data + +class instrument: + """rs232 port""" + + def __init__(self, + port, + msg_handler, + watchdog_enabled = False, + watchdog_timeout = 2, + watchdog_periodicity = 0.5): + self.serial = serial.Serial() + self.serial.port = port + self.serial.baudrate = BAUDRATE + self.serial.parity = PARITY + self.serial.bytesize = BYTESIZE + self.serial.stopbits = STOPBITS + self.serial.xonxoff = False # disable software flow control + self.serial.timeout = TIMEOUT + self.portOpened = False + self.msg_hdlr = msg_handler + + self.watchdog_daemon = watchdog.WatchDogDaemon(watchdog_timeout, + watchdog_timeout, + watchdog_enabled) + self.watchdog_daemon.reset = self._watchdogClose #register watchdog reset function + self.closed_by_watchdog = False + + self.open() + + def open(self): + try: + self.serial.open() + self.portOpened = True + print 'comms::opening port' + except serial.SerialException: + self.portOpened = False + print 'unable to open port...' + + def close(self): + self.serial.close() + self.portOpened = False + print 'comms::closeing port' + + def dataReady(self): + if self.portOpened: + return self.serial.in_waiting + else: + return False + + def readMessages(self): + """reads serial port. creates an array of events + output: array of events: + """ + if self.closed_by_watchdog: + self.closed_by_watchdog = False + self.open() + + while self.dataReady(): + msg_str = self._read().split('_', 1) + + if msg_str[0] != '': + self.msg_hdlr(Message(*msg_str)) + self.watchdog_daemon.ping() + + def generateEvent(self, name, data = ''): + self.writeMessage(Message(name, data)) + + def writeMessage(self, m): + self._write(m.name) + if m.data != '': + self._write('_' + str(m.data)) + self._write('\n') + + def enableWatchdog(self, enable): + self.watchdog_daemon.setEnabled(enable) + + def _write(self, str): + if self.portOpened == True: + #serial expects a byte-array and not a string + self.serial.write(''.join(str).encode('utf-8', 'ignore')) + + def _read(self): + """ returns string read from serial port """ + b = '' + if self.portOpened == True: + b = self.serial.read_until() #blocks until '\n' received or timeout + + return b.decode('utf-8', 'ignore') #convert byte array to string + + def _watchdogClose(self): + self.closed_by_watchdog = True + self.close() + + def _is_number(self, s): + """ helper function to evaluate if input text represents an integer or not """ + try: + int(s) + return True + except ValueError: + return False diff --git a/my-emco/custom-m-codes/M101 b/my-emco/custom-m-codes/M101 new file mode 100644 index 0000000..c3873f9 --- /dev/null +++ b/my-emco/custom-m-codes/M101 @@ -0,0 +1,4 @@ +#!/bin/bash +# file to turn on parport pin 17 to open the spindle air valve +halcmd setp parport.0.pin-17-out True +exit 0 diff --git a/my-emco/custom-m-codes/M102 b/my-emco/custom-m-codes/M102 new file mode 100644 index 0000000..f377f79 --- /dev/null +++ b/my-emco/custom-m-codes/M102 @@ -0,0 +1,4 @@ +#!/bin/bash +# file to turn off parport pin 17 to open the spindle air valve +halcmd setp parport.0.pin-17-out False +exit 0 diff --git a/my-emco/custom-m-codes/M103 b/my-emco/custom-m-codes/M103 new file mode 100644 index 0000000..56dcc29 --- /dev/null +++ b/my-emco/custom-m-codes/M103 @@ -0,0 +1,4 @@ +#!/bin/bash +# axis reload after +axis-remote --reload +exit 0 diff --git a/my-emco/custom-m-codes/mychange.ngc b/my-emco/custom-m-codes/mychange.ngc new file mode 100644 index 0000000..ec9603c --- /dev/null +++ b/my-emco/custom-m-codes/mychange.ngc @@ -0,0 +1,19 @@ +o sub + o10 if [#<_current_tool> NE #<_selected_tool>] + ;(DEBUG, current tool: #<_current_tool>, selected_tool: #<_selected_tool>) + # = [#<_z>] ; save position + #4999 = #<_selected_tool> ; store selected tool to use M61 at start-up + G53 G0 Z87 ; rapid to tool change location + M6 + ;G53 G0 Z50 + ;M101 ; engage spindle air blower + ;G53 G0 Z35 + ;M102 ; disengage spindle air blower + ;(DEBUG, saved-z: #) + G43 + G0 Z[#] ; restore position + o10 else + (DEBUG, tool #<_selected_tool> already in spindle) + o10 endif +o endsub +M2 \ No newline at end of file diff --git a/my-emco/custom-m-codes/myspindlestart.ngc b/my-emco/custom-m-codes/myspindlestart.ngc new file mode 100644 index 0000000..877d7b7 --- /dev/null +++ b/my-emco/custom-m-codes/myspindlestart.ngc @@ -0,0 +1,9 @@ +o sub + o10 if [#<_spindle_on> EQ 1] + M5 + o10 else + S800 + M3 + o10 endif +o endsub +M2 \ No newline at end of file diff --git a/my-emco/custom-m-codes/mytouch.ngc b/my-emco/custom-m-codes/mytouch.ngc new file mode 100644 index 0000000..aa161fd --- /dev/null +++ b/my-emco/custom-m-codes/mytouch.ngc @@ -0,0 +1,30 @@ +o sub + o10 if [EXISTS[#<_hal[jog-axis-sel]>]] + # = #<_hal[jog-axis-sel]> + ;(DEBUG, my-mpg.axis-selector: #) + + (touch off z axis) + o20 if [# EQ 0] + G10 L20 P0 Z0 + M103 + (MSG, touch off z axis) + o20 endif + + (touch off y axis) + o30 if [# EQ 1] + G10 L20 P0 Y0 + M103 + (MSG, touch off y axis) + o30 endif + + (touch off x axis) + o40 if [# EQ 2] + G10 L20 P0 X0 + M103 + (MSG, touch off x axis) + o40 endif + o10 else + (DEBUG, didn't exist) + o10 endif +o endsub +M2 \ No newline at end of file diff --git a/my-emco/custom.hal b/my-emco/custom.hal new file mode 100644 index 0000000..9d5e70d --- /dev/null +++ b/my-emco/custom.hal @@ -0,0 +1,140 @@ +# Include your customized HAL commands here +# This file will not be overwritten when you run stepconf again + +loadrt scale count=2 # 0 used to convert spindle rps-to-rpm, 1 used to scale jog-scale output from classicladder +loadrt near names=spindle-at-speed +loadrt pid names=spindle-speed-ctrl +loadrt limit2 names=spindle-ramp +loadrt not count=1 # used for ramping spindle speed +loadrt and2 count=3 # and2.0 used for MPG run-button, and2.1 for e-stop-chain, and2.2 for setting tool after homeing +loadrt classicladder_rt +loadrt conv_float_u32 # user in postgui for converting analog signal to integer + +loadusr -Wn my-mpg python serialEventHandler.py --port=/dev/ttyUSB0 -c my-mpg mpg.xml +loadusr -Wn my-encoder python fake_encoder.py --port=/dev/ttyS0 -c my-encoder +loadusr classicladder test_ladder.clp --nogui + +addf scale.0 servo-thread +addf scale.1 servo-thread +addf spindle-at-speed servo-thread +addf spindle-speed-ctrl.do-pid-calcs servo-thread +addf spindle-ramp servo-thread +addf not.0 servo-thread +addf and2.0 servo-thread +addf and2.1 servo-thread +addf and2.2 servo-thread +addf classicladder.0.refresh servo-thread +addf conv-float-u32.0 servo-thread + +### spindel speed ramping +setp spindle-ramp.maxv 500 +net spindle-cmd-rpm => spindle-ramp.in +net spindle-ramped <= spindle-ramp.out => pwmgen.0.value +net spindle-on not.0.in +net spindle-off not.0.out +net spindle-off spindle-ramp.load +net spindle-ramped => spindle-at-speed.in2 + +### spindle at speed monitoring ### +setp spindle-at-speed.scale 0.98 +setp spindle-at-speed.difference 10 +setp scale.0.gain 60 # rps to rpm +setp scale.0.offset 0 + +net spindle-velocity-rpm <= scale.0.out +net spindle-cmd-rpm => spindle-at-speed.in1 +#net spindle-velocity-rpm => spindle-at-speed.in2 +net spindle-ramped => spindle-at-speed.in2 +net spindle-ready <= spindle-at-speed.out => spindle.0.at-speed + +### encoder ### +net spindle-position my-encoder.position => spindle.0.revs +net spindle-velocity-rps my-encoder.velocity +net spindle-velocity-rps => spindle.0.speed-in +net spindle-velocity-rps => scale.0.in +net spindle-index-enable my-encoder.index-enable <=> spindle.0.index-enable +net watchdog-enable my-encoder.watchdog-enable # connected to checkbox in postgui + +### PID ctrl ### +net spindle-cmd-rpm => spindle-speed-ctrl.command +setp spindle-speed-ctrl.Pgain 2.5 +setp spindle-speed-ctrl.Igain 3 +setp spindle-speed-ctrl.Dgain 2.3 +setp spindle-speed-ctrl.FF0 0 +setp spindle-speed-ctrl.FF1 1.5 +setp spindle-speed-ctrl.maxoutput 4500 +setp spindle-speed-ctrl.deadband 25 +#setp spindle-speed-ctrl.maxerror 1000 +setp spindle-speed-ctrl.enable 0 + +net spindle-velocity-rpm => spindle-speed-ctrl.feedback +#net spindle-speed-ctrl-out spindle-speed-ctrl.output => pwmgen.0.value +net spindle-on => spindle-speed-ctrl.enable #from spindle.0.on +net spindle-index-enable => spindle-speed-ctrl.index-enable + +### mist coolant ctrl ### +net mist-cmd iocontrol.0.coolant-mist => parport.0.pin-14-out + +### e-stop chain ### +net estop-internal <= iocontrol.0.user-enable-out +net estop-external <= parport.0.pin-13-in-not + +net estop-internal => and2.1.in0 +net estop-external => and2.1.in1 +net estop-chain and2.1.out => iocontrol.0.emc-enable-in + +## restoring tool after homing ################################################# +# note, logic assumes z-axis homed first, when x and y axis' are +# homed, all axis are done +net x-homed halui.joint.0.is-homed and2.2.in0 +net y-homed halui.joint.1.is-homed and2.2.in1 +net xy-homed and2.2.out +net xy-homed halui.mdi-command-02 +net xy-homed halui.mdi-command-03 + +### pendant ########################################## +# jog wheel connects to x, y, z axis +net mpg-jog-counts joint.0.jog-counts axis.x.jog-counts <= my-mpg.jog-counts +net mpg-jog-counts joint.1.jog-counts axis.y.jog-counts +net mpg-jog-counts joint.2.jog-counts axis.z.jog-counts + +# axis selector connects to x, y, z axis enable +net jog-axis-sel classicladder.0.s32in-00 +net jog-x-enable classicladder.0.out-00 +net jog-y-enable classicladder.0.out-01 +net jog-z-enable classicladder.0.out-02 + +net jog-axis-sel my-mpg.axis-selector +net jog-x-enable axis.x.jog-enable +net jog-y-enable axis.y.jog-enable +net jog-z-enable axis.z.jog-enable + +# jog scale selector connects to x, y, z axis jog scale and jog velocity mode +setp scale.1.gain 0.01 +setp scale.1.offset 0 +net jog-scale-100 classicladder.0.floatout-00 scale.1.in +net jog-scale-sel classicladder.0.s32in-01 +net jog-scale scale.1.out + +net jog-scale-sel my-mpg.scale-selector +net jog-scale joint.0.jog-scale axis.x.jog-scale +net jog-scale joint.1.jog-scale axis.y.jog-scale +net jog-scale joint.2.jog-scale axis.z.jog-scale + +net vel-mode-sel classicladder.0.out-03 +net vel-mode-sel joint.0.jog-vel-mode axis.x.jog-vel-mode +net vel-mode-sel joint.1.jog-vel-mode axis.y.jog-vel-mode +net vel-mode-sel joint.2.jog-vel-mode axis.z.jog-vel-mode + +### connect the buttons +# connect Func-button +net func-button my-mpg.func-btn #connected to gladevcp-component in postgui + +# connect Run button +net run-button halui.mode.auto and2.0.in0 <= my-mpg.prog-run-btn +net program-run-ok and2.0.in1 <= halui.mode.is-auto +net remote-program-run halui.program.run <= and2.0.out + +# connect E-Stop button +net estop-button halui.estop.activate <= my-mpg.estop-btn + diff --git a/my-emco/custom_postgui.hal b/my-emco/custom_postgui.hal new file mode 100644 index 0000000..0713853 --- /dev/null +++ b/my-emco/custom_postgui.hal @@ -0,0 +1,38 @@ +# Include your customized HAL commands here +# The commands in this file are run after the AXIS GUI (including PyVCP panel) starts + +### virtual panel ############################################################## + +## connect the frame-enable-signals +net xy-homed gladevcp.commands +net xy-homed gladevcp.tool +net xy-homed gladevcp.mpg +setp gladevcp.lube 1 + +## connect spindle frame +net spindle-cmd-rpm => gladevcp.spindle-ref-rpm +net spindle-velocity-rpm => gladevcp.spindle-curr-rpm +net spindle-velocity-rpm => gladevcp.spindle-rpm-hbar +#net spindle-duty pwmgen.0.curr-dc => pyvcp.spindle-pwm-duty +net spindle-ready => gladevcp.led-spindle-at-speed +net watchdog-enable gladevcp.wd-chkbtn + +## connect command frame +net tc-pos halui.mdi-command-01 <= gladevcp.tc-button +net panel-rth-button halui.mdi-command-00 <= gladevcp.rth-button + +## connect the current tool bumber +net current-tool-number iocontrol.0.tool-number => gladevcp.current-tool + +#set the gladevcp-tool-combo to show current tool at start +net set-start-tool motion.analog-out-00 conv-float-u32.0.in +net start-tool-pin conv-float-u32.0.out gladevcp.saved-tool-pin + +## connect the mpg frame +net func-button gladevcp.trigger_pin + +## connect the luber frame +net luber-acc-dist gladevcp.acc-distance +net luber-cmd gladevcp.lube-cmd +net luber-ext-req gladevcp.lube-cmd-btn +net luber-reset gladevcp.lube-reset-btn diff --git a/my-emco/emco-buttons.xml b/my-emco/emco-buttons.xml new file mode 100644 index 0000000..23113b7 --- /dev/null +++ b/my-emco/emco-buttons.xml @@ -0,0 +1,158 @@ + + + ("Helvetica",16) + + + + RIDGE + 3 + + + + + + + RIDGE + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RIDGE + 3 + + RIDGE + 2 + + + "spindle-ref-rpm" + "+4.2f" + + + + RIDGE + 2 + + + "spindle-curr-rpm" + "+4.2f" + + + + RIDGE + 2 + + + "spindle-pwm-duty" + "+4.2f" + + + + RIDGE + 2 + + + "led-spindle-at-speed" + "green" + "red" + + + + RIDGE + 2 + + + "current-tool" + "2d" + + + + + + + "wd-chkbtn" + "Watchdog Enable " + 1 + + + + diff --git a/my-emco/fake_encoder.py b/my-emco/fake_encoder.py new file mode 100644 index 0000000..ccf09da --- /dev/null +++ b/my-emco/fake_encoder.py @@ -0,0 +1,126 @@ +#! /usr/bin/python + +import sys +import comms +import hal +import getopt +import time + +class FakeEncoder: + def __init__(self, dT, scale): + self._position = 0 # scaled value from count + self._velocity = 0 # units per sec, i.e. rps + self._dT = dT # delta time between samples [s] + self._scale = scale # nbr of pulses / rev + + def clear(self): + self._position = 0 + print 'FakeEncoder::clearing position data' + + def handleEvent(self, event): + if (event.name == 'pos'): + self._velocity = float(event.data)/(self._scale*self._dT) #pos per dT to rps + self._position += float(event.data)/self._scale + + def getVelocity(self): + return self._velocity + + def getPosition(self): + return self._position + + +class HalAdapter: + def __init__(self, name, clear_cb): + self.h = hal.component(name) + self.clearCallback = clear_cb + + self.h.newpin("velocity", hal.HAL_FLOAT, hal.HAL_OUT) + self.h.newpin("position", hal.HAL_FLOAT, hal.HAL_OUT) + self.h.newpin("index-enable", hal.HAL_BIT, hal.HAL_IO) + self.h.newpin("watchdog-enable", hal.HAL_BIT, hal.HAL_IN) + self.h.ready() + + def update(self, vel, pos): + self.h['velocity'] = vel + self.h['position'] = pos + + if self.h['index-enable'] == 1: + self.clearCallback() + self.h['position'] = 0 + self.h['index-enable'] = 0 + + def isWatchdogEnabled(self): + return self.h['watchdog-enable'] + +class OptParser: + def __init__(self, argv): + self.name = 'my-encoder' # default name of component in HAL + self.port = '/dev/ttyUSB1' # default serial port to use + + self._getOptions(argv) + + def __repr__(self): + return 'name: ' + self.name + '\tport: ' + self.port + + def _getOptions(self, argv): + if argv != []: + try: + opts, args = getopt.getopt(argv, "hp:c:", ["port="]) + except getopt.GetoptError as err: + # print help information and exit: + print(err) # will print something like "option -a not recognized" + sys.exit(2) + + ### parse input command line + for o, a in opts: + if o == "-h": + self._usage() + sys.exit() + if o == "-c": + self.name = a + elif o in ("-p", "--port"): + self.port = a + else: + print o, a + assert False, "unhandled option" + + + def getName(self): + return self.name + + def getPort(self): + return self.port + + def _usage(self): + """ print command line options """ + print "usage serial_mpg.py -h -c -p/--port= \n"\ + "-c # name of component in HAL. 'mpg' default\n"\ + "-p/--port= # default serial port to use. '/dev/ttyS2' default\n"\ + "-h # print this test" + + +def main(): + optParser = OptParser(sys.argv[1:]) + componentName = optParser.getName() + portName = optParser.getPort() + + print optParser + + fakeEncoder = FakeEncoder(0.05, 500) + speedCounter = comms.instrument(portName, fakeEncoder.handleEvent, False) #serial adaptor, watchdog disabled + halAdapter = HalAdapter(componentName, fakeEncoder.clear) + + try: + while 1: + speedCounter.enableWatchdog(halAdapter.isWatchdogEnabled()) + speedCounter.readMessages() + + halAdapter.update(fakeEncoder.getVelocity(), fakeEncoder.getPosition()) + + time.sleep(0.05) + + except KeyboardInterrupt: + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/my-emco/func-btn.xml b/my-emco/func-btn.xml new file mode 100644 index 0000000..db5afeb --- /dev/null +++ b/my-emco/func-btn.xml @@ -0,0 +1,6 @@ + + Touch off selected axisO<mytouch>call + Spindle Start/StopO<myspindlestart>call + Return to safe ZG53 G0 Z0 + Return to homeG53 G0 X0 Y0 Z0 + \ No newline at end of file diff --git a/my-emco/gladevcp-handler.py b/my-emco/gladevcp-handler.py new file mode 100644 index 0000000..bd9de0d --- /dev/null +++ b/my-emco/gladevcp-handler.py @@ -0,0 +1,138 @@ +#!/usr/bin/ python + +import gtk +import gobject +import linuxcnc +import hal +import hal_glib +import xml.etree.ElementTree as ET + +debug = 0 + +class ToolTableParser: + def __init__(self, f): + self.f = open(f, 'r') + self.list = gtk.ListStore(int, str, str) + self._parse_file() + self.f.close() + + def __repr__(self): + ret_str = '' + for l in self.list: + ret_str += str(l) + '\n' + return ret_str + + def get_parsed_data(self): + return self.list + + def _parse_file(self): + lines = self.f.readlines() + + i = 0 + for line in lines: + tool_nbr = line.split(' ')[0] + tool_descr = tool_nbr + ' ' + line.split(';')[1] + self.list.append([i, tool_descr, tool_nbr]) + i = i+1 + +class XmlParser: + def __init__(self, f): + self.tree = [] + self.list = gtk.ListStore(int, str, str) + + self._parse_file(f) + + def get_parsed_data(self): + return self.list + + def _parse_file(self, f): + self.tree = ET.parse(f) + root = self.tree.getroot() + + i = 0 + for func in root.iter('function'): + gcode = func.find('gcode') + + # create the LinuxCNC hal pin and create mapping dictionary binding incomming events with data and the hal pins + if gcode is not None: + self.list.append([i, func.text, gcode.text]) + i = i+1 + +class HandlerClass: + + def on_destroy(self,obj,data=None): + print "on_destroy, combobox active=%d" %(self.combo.get_active()) + self.halcomp.exit() # avoid lingering HAL component + gtk.main_quit() + + def on_changed(self, combobox, data=None): + if self.tool_combo_initiated: + model = combobox.get_model() + tool_change_cmd = 'M6' + ' ' + model[combobox.get_active()][2] + ' ' + 'G43' + self._send_mdi(tool_change_cmd) + print tool_change_cmd + + def __init__(self, halcomp, builder, useropts): + self.linuxcnc_status = linuxcnc.stat() + self.linuxcnc_cmd = linuxcnc.command() + self.halcomp = halcomp + self.builder = builder + self.useropts = useropts + + self.trigger1 = hal_glib.GPin(halcomp.newpin('trigger_pin', hal.HAL_BIT, hal.HAL_IN)) + self.trigger1.connect('value-changed', self._trigger_change) + + self.trigger2 = hal_glib.GPin(halcomp.newpin('saved-tool-pin', hal.HAL_U32, hal.HAL_IN)) + self.trigger2.connect('value-changed', self._init_tool_combo) + + func_list = XmlParser('func-btn.xml').get_parsed_data() + self.func_combo = self.builder.get_object('func-btn-combo') + self.func_combo.set_model(func_list) + self.func_combo.set_entry_text_column(1) + self.func_combo.set_active(0) + + tool_list = ToolTableParser('tool.tbl').get_parsed_data() + self.tool_combo = self.builder.get_object('tool-combo') + self.tool_combo.set_model(tool_list) + self.tool_combo.set_entry_text_column(2) + self.tool_combo.set_active(0) + + renderer_text = gtk.CellRendererText() + self.func_combo.pack_start(renderer_text, True) + self.tool_combo.pack_start(renderer_text, True) + self.tool_combo_initiated = False + + def _trigger_change(self, pin, userdata = None): + #setp gladevcp.trigger_pin 1 + #print "pin value changed to: " + str(pin.get()) + #print "pin name= " + pin.get_name() + #print "pin type= " + str(pin.get_type()) + #print "active " + str(self.combo.get_active()) + if pin.get() is True: + model = self.func_combo.get_model() + self._send_mdi(model[self.func_combo.get_active()][2]) + + def _init_tool_combo(self, pin, userdata = None): + #setp gladevcp.saved_tool_pin 2 + self.tool_combo.set_active(pin.get()) + self.tool_combo_initiated = True + + + def _ok_for_mdi(self): + self.linuxcnc_status.poll() + return not self.linuxcnc_status.estop and self.linuxcnc_status.enabled and (self.linuxcnc_status.homed.count(1) == self.linuxcnc_status.joints) and (self.linuxcnc_status.interp_state == linuxcnc.INTERP_IDLE) + + def _send_mdi(self, mdi_cmd_str): + if self._ok_for_mdi(): + self.linuxcnc_cmd.mode(linuxcnc.MODE_MDI) + self.linuxcnc_cmd.wait_complete() # wait until mode switch executed + self.linuxcnc_cmd.mdi(mdi_cmd_str) + +def get_handlers(halcomp, builder, useropts): + + global debug + for cmd in useropts: + exec cmd in globals() + + return [HandlerClass(halcomp, builder, useropts)] + diff --git a/my-emco/linuxcnc.var b/my-emco/linuxcnc.var new file mode 100644 index 0000000..cd15c49 --- /dev/null +++ b/my-emco/linuxcnc.var @@ -0,0 +1,120 @@ +4999 7.000000 +5161 0.000000 +5162 0.000000 +5163 0.000000 +5164 0.000000 +5165 0.000000 +5166 0.000000 +5167 0.000000 +5168 0.000000 +5169 0.000000 +5181 0.000000 +5182 0.000000 +5183 0.000000 +5184 0.000000 +5185 0.000000 +5186 0.000000 +5187 0.000000 +5188 0.000000 +5189 0.000000 +5210 0.000000 +5211 0.000000 +5212 0.000000 +5213 0.000000 +5214 0.000000 +5215 0.000000 +5216 0.000000 +5217 0.000000 +5218 0.000000 +5219 0.000000 +5220 1.000000 +5221 23.092490 +5222 -2.040103 +5223 -105.797929 +5224 0.000000 +5225 0.000000 +5226 0.000000 +5227 0.000000 +5228 0.000000 +5229 0.000000 +5230 0.000000 +5241 -6.758898 +5242 32.897192 +5243 -21.519200 +5244 0.000000 +5245 0.000000 +5246 0.000000 +5247 0.000000 +5248 0.000000 +5249 0.000000 +5250 0.000000 +5261 25.241102 +5262 32.897192 +5263 -21.519200 +5264 0.000000 +5265 0.000000 +5266 0.000000 +5267 0.000000 +5268 0.000000 +5269 0.000000 +5270 0.000000 +5281 57.241102 +5282 32.897192 +5283 -21.519200 +5284 0.000000 +5285 0.000000 +5286 0.000000 +5287 0.000000 +5288 0.000000 +5289 0.000000 +5290 0.000000 +5301 0.000000 +5302 0.000000 +5303 0.000000 +5304 0.000000 +5305 0.000000 +5306 0.000000 +5307 0.000000 +5308 0.000000 +5309 0.000000 +5310 0.000000 +5321 0.000000 +5322 0.000000 +5323 0.000000 +5324 0.000000 +5325 0.000000 +5326 0.000000 +5327 0.000000 +5328 0.000000 +5329 0.000000 +5330 0.000000 +5341 0.000000 +5342 0.000000 +5343 0.000000 +5344 0.000000 +5345 0.000000 +5346 0.000000 +5347 0.000000 +5348 0.000000 +5349 0.000000 +5350 0.000000 +5361 0.000000 +5362 0.000000 +5363 0.000000 +5364 0.000000 +5365 0.000000 +5366 0.000000 +5367 0.000000 +5368 0.000000 +5369 0.000000 +5370 0.000000 +5381 0.000000 +5382 0.000000 +5383 0.000000 +5384 0.000000 +5385 0.000000 +5386 0.000000 +5387 0.000000 +5388 0.000000 +5389 0.000000 +5390 0.000000 diff --git a/my-emco/luber.hal b/my-emco/luber.hal new file mode 100644 index 0000000..53cefb4 --- /dev/null +++ b/my-emco/luber.hal @@ -0,0 +1,16 @@ +loadusr -Wn my-luber python luber.py -c my-luber luber.xml + +net x-vel joint.0.vel-cmd => my-luber.x-vel +net y-vel joint.1.vel-cmd => my-luber.y-vel +net z-vel joint.2.vel-cmd => my-luber.z-vel + +setp my-luber.lube-level-ok 1 +net iocontrol.0.lube-level <= my-luber.lube-level-alarm + +net luber-reset my-luber.reset +net luber-cmd my-luber.lube-cmd => parport.0.pin-09-out + +## create the gui signals +net luber-acc-dist my-luber.accumulated-distance +net luber-ext-req my-luber.lube-ext-req +net luber-reset my-luber.reset \ No newline at end of file diff --git a/my-emco/luber.py b/my-emco/luber.py new file mode 100644 index 0000000..4f2de05 --- /dev/null +++ b/my-emco/luber.py @@ -0,0 +1,234 @@ +#! /usr/bin/python + +import sys +import getopt +import xml.etree.ElementTree as ET +import hal +import time +from collections import namedtuple + +class Pin: + """ Representation of a Pin and it's data""" + def __init__(self, type, dir): + self.val = 0 # current value of pin, e.g. 1 - on, 0 - off + self.type = type # type (string read from xml) + self.dir = dir + + def __repr__(self): + return 'val: ' + str(self.val) + '\ttype: ' + self.type + '\tdir: ' + self.dir + +class HalAdapter: + def __init__(self, name): + self.h = hal.component(name) + self.h.newpin("velocity", hal.HAL_FLOAT, hal.HAL_OUT) + self.h.newpin('x-vel', hal.HAL_FLOAT, hal.HAL_IN) + self.h.newpin('y-vel', hal.HAL_FLOAT, hal.HAL_IN) + self.h.newpin('z-vel', hal.HAL_FLOAT, hal.HAL_IN) + self.h.newpin('lube-level-ok',hal.HAL_BIT, hal.HAL_IN) + self.h.newpin('reset', hal.HAL_BIT, hal.HAL_IN) + self.h.newpin('lube-ext-req', hal.HAL_BIT, hal.HAL_IN) + self.h.newpin('lube-cmd', hal.HAL_BIT, hal.HAL_OUT) + self.h.newpin('lube-level-alarm', hal.HAL_BIT, hal.HAL_OUT) + self.h.newpin('accumulated-distance', hal.HAL_FLOAT, hal.HAL_OUT) + self.h.ready() + + def __repr__(self): + tmp_str = '' + return tmp_str + + def is_lube_level_ok(self): + return self.h['lube-level-ok'] + + def is_reset(self): + return self.h['reset'] + + def is_lube_ext_req(self): + return self.h['lube-ext-req'] + + def get_velocities(self): + velocities = namedtuple("velocities", ["x", "y", "z"]) + return velocities( + self.h['x-vel'], + self.h['y-vel'], + self.h['z-vel']) + + def set_lube_on(self, request): + if request >= 1: + self.h['lube-cmd'] = 1 + else: + self.h['lube-cmd'] = 0 + + def set_lube_level_alarm(self, level_ok): + if level_ok >= 1: + self.h['lube-level-alarm'] = 1 + else: + self.h['lube-level-alarm'] = 0 + + def set_accumulated_distance(self, d): + self.h['accumulated-distance'] = d + +class parameterContainer: + def __init__(self, xml_file): + self.paramDict = {} + self._xmlFile = xml_file + + self.tree = ET.parse(self._xmlFile) + self._parse() + + def _parse(self): + root = self.tree.getroot() + for param in root.iter('parameter'): + #print param.attrib['name'], param.attrib['value'] + self.paramDict[param.attrib['name']] = float(param.attrib['value']) + + def getParam(self, name): + if name in self.paramDict: + return self.paramDict[name] + else: + return None + + def getParams(self): + return self.paramDict + + def writeToFile(self): + for parName in self.paramDict: + self._writeToTree(parName, self.paramDict[parName]) + + self.tree.write(self._xmlFile) + + def writeParam(self, parName, value): + if parName in self.paramDict: + self.paramDict[parName] = value + + def _writeToTree(self, parName, value): + """update parameter in xml-tree""" + root = self.tree.getroot() + + for param in root.iter('parameter'): + if param.attrib['name'] == parName: + param.attrib['value'] = str(round(value, 2)) + break + + +class LubeControl: + def __init__(self, lube_on_time, accumulated_distance, distance_threshold, number_of_lubings): + self.lubeOnTime = lube_on_time # [sec] + self.total_distance = accumulated_distance # [mm] + self.distance_threshold = distance_threshold # [mm] + self.numberOfLubings = number_of_lubings + + self.state = 'OFF' + self.lubeLevelOkOut = True + self._lubeLevelOkIn = True + self.prev_time = time.time() + + def calc_dist_from_vel(self, v_x, v_y, v_z): + current_time = time.time() + time_delta = current_time - self.prev_time + + self.total_distance += abs(v_x) * time_delta + self.total_distance += abs(v_y) * time_delta + self.total_distance += abs(v_z) * time_delta + + self.prev_time = current_time + + + def runStateMachine(self, ext_req): + currentTime = time.time() + if self.total_distance >= self.distance_threshold or ext_req == True: + self.state = 'ON' + self.timeout = self.lubeOnTime + currentTime + self.total_distance = 0 + self.numberOfLubings += 1 + + if self.state == 'ON': + if currentTime > self.timeout: + #check lube pressure sensor + self.lubeLevelOkOut = self._lubeLevelOkIn + + self.state = 'OFF' + + + def setLubeLevelOK(self, levelOk): + self._lubeLevelOkIn = levelOk + + def reset(self): + self.total_distance = 0 + self.state = 'OFF' + self.lubeLevelOkOut = True + +def _usage(): + """ print command line options """ + print "usage luber.py -h -c in_file.xml\n"\ + "in_file # input xml-file describing what knobs and/or button are on the pendant\n"\ + "-c # name of component in HAL. 'my-luber' default\n"\ + "-h # Help test" + +def main(): + xmlFile = 'luber.xml' + #xmlFile = '' + name = 'my-luber' # default name of component in HAL + + try: + opts, args = getopt.getopt(sys.argv[1:], "hc:", ["input="]) + except getopt.GetoptError as err: + # print help information and exit: + print(err) # will print something like "option -a not recognized" + sys.exit(2) + + for o, a in opts: + if o == "-h": + _usage() + sys.exit() + elif o == "-c": + name = a + elif o == "--input": + xmlFile = a + else: + print o + assert False, "unhandled option" + + if xmlFile == '': + if len(sys.argv) < 2: + _usage() + sys.exit(2) + else: + xmlFile = sys.argv[-1] + + p = parameterContainer(xmlFile) + + h = HalAdapter(name) + + totalDistance = p.getParam('totalDistance') + distanceThreshold = p.getParam('distanceThreshold') + lubeOnTime = p.getParam('lubePulseTime') + nbrOfLubings = p.getParam('numberOfLubings') + + lubeCtrl = LubeControl(lubeOnTime, totalDistance, distanceThreshold, nbrOfLubings) + + try: + while 1: + if h.is_reset(): + lubeCtrl.reset() + + lubeCtrl.setLubeLevelOK(h.is_lube_level_ok()) + v = h.get_velocities() + lubing_external_request = h.is_lube_ext_req() + lubeCtrl.calc_dist_from_vel(v.x, v.y, v.z) + + lubeCtrl.runStateMachine(lubing_external_request) + + h.set_lube_on(lubeCtrl.state == 'ON') + h.set_lube_level_alarm(lubeCtrl.lubeLevelOkOut) + h.set_accumulated_distance(lubeCtrl.total_distance) + + time.sleep(0.1) + + except KeyboardInterrupt: + p.writeParam('totalDistance', lubeCtrl.total_distance) + p.writeParam('numberOfLubings', lubeCtrl.numberOfLubings) + p.writeToFile() + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/my-emco/luber.xml b/my-emco/luber.xml new file mode 100644 index 0000000..e4d8adf --- /dev/null +++ b/my-emco/luber.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/my-emco/mpg.xml b/my-emco/mpg.xml new file mode 100644 index 0000000..fdbaae0 --- /dev/null +++ b/my-emco/mpg.xml @@ -0,0 +1,8 @@ + + "jog-counts"jogs32 + "axis-selector"selas32 + "scale-selector"selss32 + "func-btn"funcbit + "prog-run-btn"runbit + "estop-btn"estbit + diff --git a/my-emco/my-emco.hal b/my-emco/my-emco.hal new file mode 100644 index 0000000..40a76d5 --- /dev/null +++ b/my-emco/my-emco.hal @@ -0,0 +1,110 @@ +# Generated by stepconf 1.1 at Mon Nov 4 14:01:20 2019 +# If you make changes to this file, they will be +# overwritten when you run stepconf again +loadrt [KINS]KINEMATICS +#autoconverted trivkins +loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS +loadrt hal_parport cfg="0 out" +setp parport.0.reset-time 5000 +loadrt stepgen step_type=0,0,0 +loadrt pwmgen output_type=0 + +addf parport.0.read base-thread +addf stepgen.make-pulses base-thread +addf pwmgen.make-pulses base-thread +addf parport.0.write base-thread +addf parport.0.reset base-thread + +addf stepgen.capture-position servo-thread +addf motion-command-handler servo-thread +addf motion-controller servo-thread +addf stepgen.update-freq servo-thread +addf pwmgen.update servo-thread + +net spindle-cmd-rpm <= spindle.0.speed-out +#net spindle-cmd-rpm pwmgen.0.value <= spindle.0.speed-out +net spindle-on <= spindle.0.on => pwmgen.0.enable +net spindle-pwm <= pwmgen.0.pwm + +setp pwmgen.0.pwm-freq 100.0 +setp pwmgen.0.scale 4500 #duty_cycle = (value/scale) + offset, with 1.0 meaning 100% +#setp pwmgen.0.offset 0.02 + +setp pwmgen.0.dither-pwm true + +net spindle-cmd-rpm-abs <= spindle.0.speed-out-abs +net spindle-cmd-rps <= spindle.0.speed-out-rps +net spindle-cmd-rps-abs <= spindle.0.speed-out-rps-abs +net spindle-cw <= spindle.0.forward + +net spindle-pwm => parport.0.pin-16-out +net xstep => parport.0.pin-02-out +setp parport.0.pin-02-out-reset 1 +setp parport.0.pin-03-out-invert 1 +net xdir => parport.0.pin-03-out +net ystep => parport.0.pin-04-out +setp parport.0.pin-04-out-reset 1 +net ydir => parport.0.pin-05-out +net zstep => parport.0.pin-06-out +setp parport.0.pin-06-out-reset 1 +setp parport.0.pin-07-out-invert 1 +net zdir => parport.0.pin-07-out +net spindle-cw => parport.0.pin-08-out +net home-z <= parport.0.pin-10-in-not +net home-y <= parport.0.pin-11-in-not +net home-x <= parport.0.pin-12-in-not +#net max-home-y <= parport.0.pin-11-in-not +#net max-home-x <= parport.0.pin-12-in-not + +setp stepgen.0.position-scale [JOINT_0]SCALE +setp stepgen.0.steplen 1 +setp stepgen.0.stepspace 0 +setp stepgen.0.dirhold 35000 +setp stepgen.0.dirsetup 35000 +setp stepgen.0.maxaccel [JOINT_0]STEPGEN_MAXACCEL +net xpos-cmd joint.0.motor-pos-cmd => stepgen.0.position-cmd +net xpos-fb stepgen.0.position-fb => joint.0.motor-pos-fb +net xstep <= stepgen.0.step +net xdir <= stepgen.0.dir +net xenable joint.0.amp-enable-out => stepgen.0.enable +#net max-home-x => joint.0.home-sw-in +#net max-home-x => joint.0.pos-lim-sw-in +net home-x => joint.0.home-sw-in + +setp stepgen.1.position-scale [JOINT_1]SCALE +setp stepgen.1.steplen 1 +setp stepgen.1.stepspace 0 +setp stepgen.1.dirhold 35000 +setp stepgen.1.dirsetup 35000 +setp stepgen.1.maxaccel [JOINT_1]STEPGEN_MAXACCEL +net ypos-cmd joint.1.motor-pos-cmd => stepgen.1.position-cmd +net ypos-fb stepgen.1.position-fb => joint.1.motor-pos-fb +net ystep <= stepgen.1.step +net ydir <= stepgen.1.dir +net yenable joint.1.amp-enable-out => stepgen.1.enable +#net max-home-y => joint.1.home-sw-in +#net max-home-y => joint.1.pos-lim-sw-in +net home-y => joint.1.home-sw-in + +setp stepgen.2.position-scale [JOINT_2]SCALE +setp stepgen.2.steplen 1 +setp stepgen.2.stepspace 0 +setp stepgen.2.dirhold 35000 +setp stepgen.2.dirsetup 35000 +setp stepgen.2.maxaccel [JOINT_2]STEPGEN_MAXACCEL +net zpos-cmd joint.2.motor-pos-cmd => stepgen.2.position-cmd +net zpos-fb stepgen.2.position-fb => joint.2.motor-pos-fb +net zstep <= stepgen.2.step +net zdir <= stepgen.2.dir +net zenable joint.2.amp-enable-out => stepgen.2.enable +net home-z => joint.2.home-sw-in + +# moved to custom.hal +#net estop-out <= iocontrol.0.user-enable-out +#net estop-out => iocontrol.0.emc-enable-in + +loadusr -W hal_manualtoolchange +net tool-change iocontrol.0.tool-change => hal_manualtoolchange.change +net tool-changed iocontrol.0.tool-changed <= hal_manualtoolchange.changed +net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number +net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared diff --git a/my-emco/my-emco.ini b/my-emco/my-emco.ini new file mode 100644 index 0000000..ee1a850 --- /dev/null +++ b/my-emco/my-emco.ini @@ -0,0 +1,169 @@ +# This config file was created 2021-03-08 20:17:44.282043 by the update_ini script +# The original config files may be found in the /home/johan/linuxcnc/configs/my-emco/my-emco.old directory + +# Generated by stepconf 1.1 at Mon Nov 4 14:01:20 2019 +# If you make changes to this file, they will be +# overwritten when you run stepconf again + +[EMC] +# The version string for this INI file. +VERSION = 1.1 + +MACHINE = my-emco +DEBUG = 0 + +[DISPLAY] +DISPLAY = axis +EDITOR = gedit +POSITION_OFFSET = RELATIVE +POSITION_FEEDBACK = ACTUAL +ARCDIVISION = 64 +GRIDS = 10mm 20mm 50mm 100mm +MAX_FEED_OVERRIDE = 1.2 +MIN_SPINDLE_OVERRIDE = 0.5 +MAX_SPINDLE_OVERRIDE = 1.2 +DEFAULT_LINEAR_VELOCITY = 25.0 +MIN_LINEAR_VELOCITY = 0 +MAX_LINEAR_VELOCITY = 25.00 +INTRO_GRAPHIC = linuxcnc.gif +INTRO_TIME = 5 +PROGRAM_PREFIX = /home/johan/linuxcnc/nc_files +INCREMENTS = 5mm 1mm .5mm .1mm .05mm .01mm .005mm +GLADEVCP= -u ./gladevcp-handler.py ./my-emco.ui + +[FILTER] +PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image +PROGRAM_EXTENSION = .py Python Script +png = image-to-gcode +gif = image-to-gcode +jpg = image-to-gcode +py = python + +[RS274NGC] +PARAMETER_FILE=linuxcnc.var +SUBROUTINE_PATH=custom-m-codes +USER_M_PATH=custom-m-codes +REMAP=M6 modalgroup=6 ngc=mychange + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 1.0 +BASE_PERIOD = 35000 +SERVO_PERIOD = 1000000 + +[TASK] +TASK = milltask +CYCLE_TIME = 0.010 + +[HAL] +HALUI = halui +HALFILE = my-emco.hal +HALFILE = custom.hal +HALFILE = luber.hal +POSTGUI_HALFILE = custom_postgui.hal + +[HALUI] +# add halui MDI commands here (max 64) +MDI_COMMAND = G53 G0 X0 Y0 Z0 ;cmd 0 "return to home" used by MPG +MDI_COMMAND = G53 G0 Z88 ;cmd 1 "tool change position" +MDI_COMMAND = M61 Q#4999 G43 ;cmd 2 called after homing to set tool saved at last tool change +MDI_COMMAND = M68 E0 Q#4999 ;cmd 3 called after homing to output current tool on analog signal + +[TRAJ] +COORDINATES = XYZ +LINEAR_UNITS = mm +ANGULAR_UNITS = degree +DEFAULT_LINEAR_VELOCITY = 25.0 +MAX_LINEAR_VELOCITY = 25.00 +DEFAULT_LINEAR_ACCELERATION = 150.0 +MAX_LINEAR_ACCELERATION = 250.0 +JOINTS = 3 +HOME = 0 0 0 + +[EMCIO] +EMCIO = io +CYCLE_TIME = 0.100 +TOOL_TABLE = tool.tbl + +[KINS] +KINEMATICS = trivkins coordinates=XYZ +#This is a best-guess at the number of joints, it should be checked +JOINTS = 3 + +[AXIS_X] +MIN_LIMIT = -85.0 +MAX_LIMIT = 92.0 +MAX_VELOCITY = 23.75 +MAX_ACCELERATION = 250.0 +# vi testar att sänka MAX_ACCELERATION = 750.0 + +[JOINT_0] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 23.75 +MAX_ACCELERATION = 250.0 +STEPGEN_MAXACCEL = 300 +#MAX_ACCELERATION = 750.0 +#STEPGEN_MAXACCEL = 937.5 +SCALE = 1000.0 +FERROR = 1 +MIN_FERROR = .25 +MIN_LIMIT = -85.0 +MAX_LIMIT = 92.0 +HOME_OFFSET = 93.000000 +HOME_SEARCH_VEL = 5.500000 +HOME_LATCH_VEL = 0.500000 +HOME_IGNORE_LIMITS = YES +HOME_SEQUENCE = 1 + +[AXIS_Y] +#tog bort givarna som ändlägesstopp, används bara vid homing +#kunde lägga till lite på pos-y... +#MIN_LIMIT = -45.0 +#MAX_LIMIT = 45.0 +MIN_LIMIT = -43.0 +MAX_LIMIT = 61.0 +MAX_VELOCITY = 23.75 +#MAX_ACCELERATION = 750.0 +MAX_ACCELERATION = 250.0 + +[JOINT_1] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 23.75 +MAX_ACCELERATION = 250.0 +STEPGEN_MAXACCEL = 300 +#MAX_ACCELERATION = 750.0 +#STEPGEN_MAXACCEL = 937.5 +SCALE = 1000.0 +FERROR = 1 +MIN_FERROR = 0.25 +MIN_LIMIT = -43.0 +MAX_LIMIT = 61.0 +HOME_OFFSET = 46.000000 +HOME_SEARCH_VEL = 5.500000 +HOME_LATCH_VEL = 0.500000 +HOME_IGNORE_LIMITS = YES +HOME_SEQUENCE = 1 + +[AXIS_Z] +MIN_LIMIT = -112.0 +MAX_LIMIT = 88.0 +MAX_VELOCITY = 5.0 +MAX_ACCELERATION = 25.0 + +[JOINT_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 5.0 +MAX_ACCELERATION = 25.0 +STEPGEN_MAXACCEL = 31.25 +SCALE = 1000.0 +FERROR = 1 +MIN_FERROR = .25 +MIN_LIMIT = -112.0 +MAX_LIMIT = 88.0 +HOME_OFFSET = 0.0 +HOME_SEARCH_VEL = 2.500000 +HOME_LATCH_VEL = 0.500000 +HOME_SEQUENCE = 0 diff --git a/my-emco/my-emco.ui b/my-emco/my-emco.ui new file mode 100644 index 0000000..14a7883 --- /dev/null +++ b/my-emco/my-emco.ui @@ -0,0 +1,508 @@ + + + + + + + Goto Machine Zero + G53 G0 X0 Y0 Z0 + + + G53 G0 Z88 + + + False + + + True + False + 2 + + + True + False + 0 + + + True + False + 5 + 5 + 12 + 12 + + + True + False + 5 + True + + + True + False + #bebebebebebe + 6000 + 1 + 0.019999999552965164 + 0.69999998807907104 + #0000ffff0000 + 0.89999997615814209 + #ffffffff0000 + #ffff00000000 + + + False + True + 0 + + + + + True + False + 3 + 2 + + + True + False + Spindle cmd: + + + + + True + False + label + 1 + %.1f rpm + + + 1 + 2 + + + + + True + False + Spindle actual: + + + 1 + 2 + + + + + True + False + label + 1 + %.1f rpm + + + 1 + 2 + 1 + 2 + + + + + True + False + Spindle at Speed: + + + 2 + 3 + + + + + True + False + 0 + #ffff00000000 + #0000ffff0000 + + + 1 + 2 + 2 + 3 + + + + + True + True + 1 + + + + + Spindle Feedback Watchdog Enable + True + True + False + True + True + + + True + False + 2 + + + + + + + + + True + False + <b>Spindle</b> + True + + + + + False + False + 0 + + + + + True + False + 0 + + + True + False + 5 + 5 + 12 + 12 + + + True + False + 2 + 2 + + + True + False + Current Tool: + + + + + True + False + label + + + 1 + 2 + + + + + True + False + Set Tool: + + + 1 + 2 + + + + + True + False + 0 + on + 0 + + + + + 1 + + + + + 1 + 2 + 1 + 2 + + + + + + + + + True + False + <b>Tool</b> + True + + + + + False + False + 1 + + + + + True + False + 0 + + + True + False + 5 + 5 + 12 + 12 + + + True + False + 20 + True + + + Goto Machine Zero + True + True + True + + + True + True + 0 + + + + + Goto Tool Change Position + True + True + True + + + True + True + 1 + + + + + + + + + True + False + <b>Commands</b> + True + + + + + False + False + 2 + + + + + True + False + 0 + + + True + False + 5 + 5 + 12 + 12 + + + True + False + 2 + + + True + False + Func Button: + + + + + True + False + 0 + 0 + + + + 1 + + + + + 1 + 2 + + + + + + + + + True + False + <b>MPG</b> + True + + + + + False + False + 3 + + + + + True + False + 0 + + + True + False + 5 + 5 + 12 + 12 + + + True + False + 3 + 2 + 20 + True + + + True + False + Accumulated Distance: + + + + + True + False + Lube Pump: + + + 1 + 2 + + + + + Reset Saved Data + True + True + True + + + 2 + 3 + + + + + True + False + label + 1 + %.2f mm + + + 1 + 2 + + + + + True + False + 0 + #ffff00000000 + #0000ffff0000 + + + 1 + 2 + 1 + 2 + + + + + Lube + True + True + True + + + 1 + 2 + 2 + 3 + + + + + + + + + True + False + <b>Lube</b> + True + + + + + False + False + 4 + + + + + + diff --git a/my-emco/postgui_backup.hal b/my-emco/postgui_backup.hal new file mode 100644 index 0000000..bc69494 --- /dev/null +++ b/my-emco/postgui_backup.hal @@ -0,0 +1,4 @@ +# Include your customized HAL commands here +# The commands in this file are run after the AXIS GUI (including PyVCP panel) starts + +sets spindle-at-speed true diff --git a/my-emco/serialEventHandler.py b/my-emco/serialEventHandler.py new file mode 100644 index 0000000..e9916cb --- /dev/null +++ b/my-emco/serialEventHandler.py @@ -0,0 +1,281 @@ +#! /usr/bin/python +"""usage serialEventHanlder.py -h -c -d/--debug= -p/--port= in_file.xml +in_file - input xml-file describing what knobs and/or button are on the pendant +-c # name of component in HAL. 'my-mpg' default +-d/--debug= # debug level, default 0 +-p/--port= # serial port to use. '/dev/ttyUSB0' default +-h # Help +python serialEventHandler.py -w mpg_pendant/config/mpg.xml +""" + +### https://docs.python.org/2/library/xml.etree.elementtree.html + +import time +import getopt +import sys +import comms +import xml.etree.ElementTree as ET +import hal + +class Pin: + """ Representation of a Pin and it's data""" + def __init__(self, name, type): + self.name = name # HAL pin name + self.val = 0 # current value of pin, e.g. 1 - on, 0 - off + self.type = type # type (string read from xml) + + def __repr__(self): + return 'pin name: ' + self.name + '\tval: ' + str(self.val) + '\ttype: ' + self.type + +class ComponentWrapper: + def __init__(self, name): + self.pin_dict = {} # dictionary used to map event to pin + self.hal = hal.component(name) # instanciate the HAL-component + + def __repr__(self): + tmp_str = '' + for k in self.pin_dict: + tmp_str += 'event: ' + k + '\t' + str(self.pin_dict[k]) + '\n' + return tmp_str + + def __getitem__(self, name): + if name in self.pin_dict: + return self.pin_dict[name].val + + def __setitem__(self, name, val): + self.set_pin(name, val) + + def add_pin(self, name, hal_name, type): + self.pin_dict[name] = Pin(hal_name, type) + self._add_hal_pin(hal_name, type) + + def event_set_pin(self, event): + """ updates pin value with new data + input: pin name, set value' + output: nothing. """ + if event.name in self.pin_dict: + try: + self.pin_dict[event.name].val = self._type_saturate(self.pin_dict[event.name].type, int(event.data)) + except ValueError: + print 'bad event' + + + def set_pin(self, name, value): + """ updates pin value with new data + input: pin name, set value' + output: nothing. """ + if name in self.pin_dict: + try: + self.pin_dict[name].val = self._type_saturate(self.pin_dict[name].type, int(value)) + except ValueError: + print 'bad event' + + def setReady(self): + self.hal.ready() + + def update_hal(self): + for key in self.pin_dict: + self.hal[self.pin_dict[key].name] = self.pin_dict[key].val + + def _add_hal_pin(self, hal_name, type): + self.hal.newpin(hal_name, self._get_hal_type(type), hal.HAL_OUT) # create the user space HAL-pin + + def _type_saturate(self, type, val): + """ helper function to convert type read from xml to HAL-type """ + retVal = 0 + + if type == 'bit': + if val >= 1: + retVal = 1 + + if type == 'float': + retVal = val + + if type == 's32': + retVal = val + + if type == 'u32': + retVal = val + + return retVal + + def _get_hal_type(self, str): + """ helper function to convert type read from xml to HAL-type """ + retVal = '' + + if str == 'bit': + retVal = hal.HAL_BIT + + if str == 'float': + retVal = hal.HAL_FLOAT + + if str == 's32': + retVal = hal.HAL_S32 + + if str == 'u32': + retVal = hal.HAL_U32 + return retVal + +class OptParser: + def __init__(self, argv): + self.xml_file = '' # input xml-file describing what knobs and/or button are on the pendant + self.name = 'my-mpg' # default name of component in HAL + self.port = '/dev/ttyUSB0' # default serial port to use + self.watchdog_reset = False + + self._get_options(argv) + + def __repr__(self): + return 'xml_file: ' + self.xml_file + '\tname: ' + self.name + '\tport: ' + self.port + + def _get_options(self, argv): + try: + opts, args = getopt.getopt(argv, "hwp:c:", ["input=", "port="]) + except getopt.GetoptError as err: + # print help information and exit: + print(err) # will print something like "option -a not recognized" + sys.exit(2) + + ### parse input command line + for o, a in opts: + if o == "-h": + self._usage() + sys.exit() + if o == "-c": + self.name = a + elif o == "--input": + self.xml_file = a + elif o in ("-p", "--port"): + self.port = a + elif o == "-w": + self.watchdog_reset = True + else: + print o, a + assert False, "unhandled option" + + if self.xml_file == '': + if len(sys.argv) < 2: + self._usage() + sys.exit(2) + else: + self.xml_file = argv[-1] + + def get_name(self): + return self.name + + def get_port(self): + return self.port + + def get_XML_file(self): + return self.xml_file + + def get_watchdog_reset(self): + return self.watchdog_reset + + def _usage(self): + """ print command line options """ + print "usage serialEventHandler.py -h -c -d/--debug= -p/--port= in_file.xml\n"\ + "in_file - input xml-file describing what knobs and/or button are on the pendant\n"\ + "-c # name of component in HAL. 'mpg' default\n"\ + "-p/--port= # default serial port to use. '/dev/ttyS2' default\n"\ + "-w # start watchdog deamon" \ + "-h # Help test" + +class XmlParser: + def __init__(self, f): + self.tree = [] + self.pin_dict = {} + + self._parse_file(f) + + def __repr__(self): + tmp_str = '' + + for k in self.pin_dict: + tmp_str += 'event: ' + k + '\t' + str(self.pin_dict[k]) + '\n' + return tmp_str + + def get_parsed_data(self): + return self.pin_dict + + def _parse_file(self, f): + self.tree = ET.parse(f) + root = self.tree.getroot() + + for halpin in root.iter('halpin'): + type = halpin.find('type') + event = halpin.find('event') + + # create the LinuxCNC hal pin and create mapping dictionary binding incomming events with data and the hal pins + if type is not None and event is not None: + if self._check_supported_HAL_type(type.text) == True: + self.pin_dict[event.text] = Pin(halpin.text.strip('"'), type.text) + + def _check_supported_HAL_type(self, str): + """ helper function to check if type is supported """ + retVal = False + + if str == 'bit' or str == 'float' or str == 's32' or str == 'u32': + retVal = True + + return retVal + +class BrokeeContainer: + def __init__(self, handler, args): + self.handler = handler + self.args = args + +class EventBroker: + def __init__(self): + self.brokee_dict = {} + self.received_event = comms.Message('') + + def attach_handler(self, event_name, handler, args = ()): + self.brokee_dict[event_name] = BrokeeContainer(handler, args) + + def handle_event(self, event): + self.received_event.copy(event) + + if event.name in self.brokee_dict: + self.brokee_dict[event.name].handler(*self.brokee_dict[event.name].args) + +################################################ +def main(): + optParser = OptParser(sys.argv[1:]) + componentName = optParser.get_name() + portName = optParser.get_port() + xmlFile = optParser.get_XML_file() + print optParser + + xmlParser = XmlParser(xmlFile) + + c = ComponentWrapper(componentName) #HAL adaptor + eventBroker = EventBroker() #maps incomming events to the correct handler + serialEventGenerator = comms.instrument(portName, eventBroker.handle_event, True, 5, 1) #serial adaptor + + # add/create the HAL-pins from parsed xml and attach them to the adaptor event handler + parsedXmlDict = xmlParser.get_parsed_data() + for key in parsedXmlDict: + c.add_pin(key, parsedXmlDict[key].name, parsedXmlDict[key].type) + eventBroker.attach_handler(key, c.event_set_pin, args = (eventBroker.received_event,)) + # TODO eventBroker.attach_handler(key, c.set_pin, args = (eventBroker.received_event.name, eventBroker.received_event.data)) + + print c + + # ready signal to HAL, component and it's pins are ready created + c.setReady() + + time.sleep(0.5) + + try: + while 1: + serialEventGenerator.readMessages() #blocks until '\n' received or timeout + c.update_hal() + + time.sleep(0.1) + + except KeyboardInterrupt: + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/my-emco/test_ladder.clp b/my-emco/test_ladder.clp new file mode 100644 index 0000000..85bb750 --- /dev/null +++ b/my-emco/test_ladder.clp @@ -0,0 +1,301 @@ +_FILES_CLASSICLADDER +_FILE-rung_1.csv +#VER=2.0 +#LABEL= +#COMMENT= +#PREVRUNG=2 +#NEXTRUNG=2 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +99-0-0/0 , 99-0-0/0 , 20-0-0/2 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/0 +99-0-0/0 , 99-0-0/0 , 20-0-0/3 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/1 +99-0-0/0 , 99-0-0/0 , 20-0-0/4 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/2 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 +_/FILE-rung_1.csv +_FILE-sections.csv +#VER=1.0 +#NAME000=Prog1 +000,0,-1,1,2,0 +_/FILE-sections.csv +_FILE-counters.csv +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +_/FILE-counters.csv +_FILE-arithmetic_expressions.csv +#VER=2.0 +0000,@310/0@=100 +0002,@270/0@=2 +0003,@270/0@=1 +0004,@270/0@=0 +0005,@270/1@=1 +0006,@270/1@=2 +0007,@270/1@=3 +0008,@310/0@=100 +0009,@310/0@=10 +0010,@270/1@=0 +0011,@310/0@=1 +_/FILE-arithmetic_expressions.csv +_FILE-timers.csv +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +_/FILE-timers.csv +_FILE-monostables.csv +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +1,0 +_/FILE-monostables.csv +_FILE-ioconf.csv +#VER=1.0 +_/FILE-ioconf.csv +_FILE-modbusioconf.csv +#VER=1.0 +_/FILE-modbusioconf.csv +_FILE-sequential.csv +#VER=1.0 +_/FILE-sequential.csv +_FILE-symbols.csv +#VER=1.0 +%I0,%func-btn,no signal connected +%I1,%f-disabl, +%I2,%f-enable, +%I3,%f-move1, +%I4,%f-move2, +%I5,%I5, +%I6,%I6, +%I7,%I7, +%I8,%I8, +%I9,%I9, +%I10,%I10, +%I11,%I11, +%I12,%I12, +%I13,%I13, +%I14,%I14, +%Q0,%x-axis, +%Q1,%y-axis, +%Q2,%z-axis, +%Q3,%vel-mode, +%Q4,%Q4, +%Q5,%Q5, +%Q6,%Q6, +%Q7,%Q7, +%Q8,%Q8, +%Q9,%Q9, +%Q10,%Q10, +%Q11,%Q11, +%Q12,%Q12, +%Q13,%Q13, +%Q14,%Q14, +%B0,%B0, +%B1,%B1, +%B2,%B2, +%B3,%B3, +%B4,%B4, +%B5,%B5, +%B6,%B6, +%B7,%B7, +%B8,%B8, +%B9,%B9, +%B10,%B10, +%B11,%B11, +%B12,%B12, +%B13,%B13, +%B14,%B14, +%B15,%B15, +%B16,%B16, +%B17,%B17, +%B18,%B18, +%B19,%B19, +%W0,%W0, +%W1,%W1, +%W2,%W2, +%W3,%W3, +%W4,%W4, +%W5,%W5, +%W6,%W6, +%W7,%W7, +%W8,%W8, +%W9,%W9, +%W10,%W10, +%W11,%W11, +%W12,%W12, +%W13,%W13, +%W14,%W14, +%W15,%W15, +%W16,%W16, +%W17,%W17, +%W18,%W18, +%W19,%W19, +%IW0,%sel-a, +%IW1,%sel-s, +%IW2,%IW2, +%IW3,%IW3, +%IW4,%IW4, +%IW5,%IW5, +%IW6,%IW6, +%IW7,%IW7, +%IW8,%IW8, +%IW9,%IW9, +%QW0,%QW0, +%QW1,%QW1, +%QW2,%QW2, +%QW3,%QW3, +%QW4,%QW4, +%QW5,%QW5, +%QW6,%QW6, +%QW7,%QW7, +%QW8,%QW8, +%QW9,%QW9, +%IF0,%IF0, +%IF1,%IF1, +%IF2,%IF2, +%IF3,%IF3, +%IF4,%IF4, +%IF5,%IF5, +%IF6,%IF6, +%IF7,%IF7, +%IF8,%IF8, +%IF9,%IF9, +%QF0,%scale, +%QF1,%QF1, +%QF2,%QF2, +%QF3,%QF3, +%QF4,%QF4, +%QF5,%QF5, +%QF6,%QF6, +%QF7,%QF7, +%QF8,%QF8, +%QF9,%QF9, +%T0,%T0,Old Timer +%T1,%T1,Old Timer +%T2,%T2,Old Timer +%T3,%T3,Old Timer +%T4,%T4,Old Timer +%T5,%T5,Old Timer +%T6,%T6,Old Timer +%T7,%T7,Old Timer +%T8,%T8,Old Timer +%T9,%T9,Old Timer +%TM0,%TM0,New Timer +%TM1,%TM1,New Timer +%TM2,%TM2,New Timer +%TM3,%TM3,New Timer +%TM4,%TM4,New Timer +%TM5,%TM5,New Timer +%TM6,%TM6,New Timer +%TM7,%TM7,New Timer +%TM8,%TM8,New Timer +%TM9,%TM9,New Timer +%M0,%M0,One-shot +%M1,%M1,One-shot +%M2,%M2,One-shot +%M3,%M3,One-shot +%M4,%M4,One-shot +%M5,%M5,One-shot +%M6,%M6,One-shot +%M7,%M7,One-shot +%M8,%M8,One-shot +%M9,%M9,One-shot +%C0,%C0,Counter +%C1,%C1,Counter +%C2,%C2,Counter +%C3,%C3,Counter +%C4,%C4,Counter +%C5,%C5,Counter +%C6,%C6,Counter +%C7,%C7,Counter +%C8,%C8,Counter +%C9,%C9,Counter +%E0,%E0,Error Flag Bit +%E1,%E1,Error Flag Bit +%E2,%E2,Error Flag Bit +%E3,%E3,Error Flag Bit +%E4,%E4,Error Flag Bit +%E5,%E5,Error Flag Bit +%E6,%E6,Error Flag Bit +%E7,%E7,Error Flag Bit +%E8,%E8,Error Flag Bit +%E9,%E9,Error Flag Bit +_/FILE-symbols.csv +_FILE-general.txt +PERIODIC_REFRESH=1 +SIZE_NBR_RUNGS=100 +SIZE_NBR_BITS=20 +SIZE_NBR_WORDS=20 +SIZE_NBR_TIMERS=10 +SIZE_NBR_MONOSTABLES=10 +SIZE_NBR_COUNTERS=10 +SIZE_NBR_TIMERS_IEC=10 +SIZE_NBR_PHYS_INPUTS=15 +SIZE_NBR_PHYS_OUTPUTS=15 +SIZE_NBR_ARITHM_EXPR=100 +SIZE_NBR_SECTIONS=10 +SIZE_NBR_SYMBOLS=160 +_/FILE-general.txt +_FILE-com_params.txt +MODBUS_MASTER_SERIAL_PORT= +MODBUS_MASTER_SERIAL_SPEED=9600 +MODBUS_MASTER_SERIAL_DATABITS=8 +MODBUS_MASTER_SERIAL_STOPBITS=1 +MODBUS_MASTER_SERIAL_PARITY=0 +MODBUS_ELEMENT_OFFSET=0 +MODBUS_MASTER_SERIAL_USE_RTS_TO_SEND=0 +MODBUS_MASTER_TIME_INTER_FRAME=100 +MODBUS_MASTER_TIME_OUT_RECEIPT=500 +MODBUS_MASTER_TIME_AFTER_TRANSMIT=0 +MODBUS_DEBUG_LEVEL=0 +MODBUS_MAP_COIL_READ=0 +MODBUS_MAP_COIL_WRITE=0 +MODBUS_MAP_INPUT=0 +MODBUS_MAP_HOLDING=0 +MODBUS_MAP_REGISTER_READ=0 +MODBUS_MAP_REGISTER_WRITE=0 +_/FILE-com_params.txt +_FILE-rung_2.csv +#VER=2.0 +#LABEL= +#COMMENT= +#PREVRUNG=1 +#NEXTRUNG=-1 +99-0-0/0 , 99-0-0/0 , 20-0-0/5 , 9-0-0/5 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 60-0-0/8 +99-0-0/0 , 99-0-0/0 , 20-0-0/6 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 60-0-0/9 +99-0-0/0 , 99-0-0/0 , 20-0-0/7 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 99-0-0/0 , 99-0-0/0 , 60-0-0/11 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/10 +99-0-0/0 , 99-0-0/0 , 20-0-0/10 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 9-0-0/0 , 50-0-60/3 +0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 0-0-0/0 , 99-1-0/0 , 99-0-0/0 , 60-0-0/0 +_/FILE-rung_2.csv +_FILE-timers_iec.csv +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +1,0,0 +_/FILE-timers_iec.csv +_/FILES_CLASSICLADDER diff --git a/my-emco/tool.tbl b/my-emco/tool.tbl new file mode 100644 index 0000000..52a72bc --- /dev/null +++ b/my-emco/tool.tbl @@ -0,0 +1,9 @@ +T1 P1 Z-8.28607 D12 ;12mm end mill, 4 flutes +T2 P2 Z-13.3224 D6 ;6mm end mill alu, 3 flutes +T3 P3 Z-18.0309 D2.5 ;2.5mm dubhole drill +T4 P4 Z-4.83769 D1 ;1mm end mill +T5 P5 Z-11.5912 D2 ;2mm end mill, 3 flutes +T6 P6 Z0 D10 ;10mm end mill alu, 3 flutes +T8 P8 Z0 D3 ;engraver +T10 P10 Z0 D10 ;10 mm 4 flutes 20230820 +T7 P7 Z0 D4 ;4mm alu diff --git a/my-emco/watchdog.py b/my-emco/watchdog.py new file mode 100644 index 0000000..2b4148e --- /dev/null +++ b/my-emco/watchdog.py @@ -0,0 +1,94 @@ +#! /usr/bin/python +import time +import threading +import sys + +class WatchDog(): + def __init__(self, timeout): + self.timeout = timeout + self.last_ping_time = time.time() + + def ping(self): + self.last_ping_time = time.time() + + def check(self): + if time.time() - self.last_ping_time > self.timeout: + self.last_ping_time = time.time() #reset tick time + return True + else: + return False + + def insideMargin(self): + if time.time() - self.last_ping_time <= self.timeout: + return True + else: + self.last_ping_time = time.time() #reset tick time + return False + + +class WatchDogDaemon(threading.Thread): + def __init__(self, timeout, periodicity, enable = True): + self.wd = WatchDog(timeout) + self.periodicity = periodicity + self.enabled = enable + self._start() + + def _start(self): + threading.Thread.__init__(self) + self.daemon = True + self.start() + + def ping(self): + self.wd.ping() + + def run(self): + print "Starting watchdog deamon..." + while(self.enabled): + time.sleep(self.periodicity) + + if not self.wd.insideMargin(): + print "Watchdog outside margin" + self.reset() + + print "stopping watchdog deamon..." + + def setEnabled(self, enabled): + if self.enabled == False and enabled == True: + self.enabled = True + self.wd.ping() # reset tick time + self._start() + + if enabled == False: + self.enabled = False + + def reset(self): + """to be overriden by client""" + pass + + +def reset(): + print 'reset' + +def main(): + i = 0 + wdd = WatchDogDaemon(2, 0.5, False) + wdd.reset = reset + try: + while 1: + time.sleep(1) + print 'main_' + str(i) + print wdd.is_alive() + i = i+1 + + if i == 5 or i == 15: + wdd.setEnabled(True) + if i == 10: + wdd.setEnabled(False) + + wdd.ping() + + except KeyboardInterrupt: + raise SystemExit + +if __name__ == '__main__': + main() \ No newline at end of file