adding files

This commit is contained in:
2026-03-21 23:48:08 +01:00
parent eba2b73dec
commit 18f86cfd1e
105 changed files with 13770 additions and 0 deletions

140
my-emco-compact-5/comms.py Normal file
View File

@@ -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 <message> and <value>"""
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

View File

@@ -0,0 +1,4 @@
#!/bin/bash
# axis reload after
axis-remote --reload
exit 0

View File

@@ -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

View File

@@ -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<extend_m0> sub
;(debug, extend_m0:)
; record whether mist/flood were on
#<mist> = #<_mist>
#<flood> = #<_flood>
#<spindle_on> = #<_spindle_on>
M5 M9 ; stop spindle, mist+flood off
m0 (refer to builtin m0)
; restore mist, flood setting
o100 if [#<mist>]
m7
o100 endif
o200 if [#<flood>]
m8
o200 endif
o300 if [#<spindle_on>]
m3 ; spindle on
o300 endif
;(debug, extend_m0 done)
o<extend_m0> endsub
m2

View File

@@ -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<extend_m1> sub
(debug, extend_m1:)
; record whether mist/flood were on
#<mist> = #<_mist>
#<flood> = #<_flood>
/M5 M9 ; stop spindle, mist+flood off
/m1 (refer to builtin m1)
; restore mist, flood setting
/o100 if [#<mist>]
/ m7
/o100 endif
/o200 if [#<flood>]
/ m8
/o200 endif
/M3 ; spindle on
(debug, extend_m1 done)
o<extend_m1> endsub
m2

View File

@@ -0,0 +1,31 @@
o<mysetspeed> sub
(DEBUG, S#<speed> setspeed)
o10 if [#<speed> LE 950]
o11 if [#4997 NE 1]
(MSG, Set spindle speed selection belt in AC1 position)
O<myspindlegain> call [0.48483] [20.16466]
#4997 = 1
o11 endif
o10 else
o20 if [#<speed> LE 1500]
o21 if [#4997 NE 2]
(MSG, Set spindle speed selection belt in AC2 position)
O<myspindlegain> call [0.32571] [-8.05714]
#4997 = 2
o21 endif
o20 else
o30 if [#<speed> LE 2400]
o31 if [#4997 NE 3]
(MSG, Set spindle speed selection belt in AC3 position)
O<myspindlegain> 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#<speed>
M0
o<mysetspeed> endsub [1]
M2

View File

@@ -0,0 +1,6 @@
o<myspindlegain> sub
M199 P#1 Q#2
#4998 = #1
#4999 = #2
o<myspindlegain> endsub
M2

View File

@@ -0,0 +1,12 @@
o<myspindlespeeddown> sub
o10 if [#<_spindle_on> EQ 1]
O20 if [#<_rpm> GT 100]
#<speed-cmd> = [#<_rpm> - 100]
O20 else
#<speed-cmd> = 0
M5
O20 endif
S#<speed-cmd>
o10 endif
o<myspindlespeeddown> endsub
M2

View File

@@ -0,0 +1,11 @@
o<myspindlespeedup> sub
;o10 if [#<_spindle_on> EQ 1]
#<speed-cmd> = [#<_rpm>+100]
O10 if [#<speed-cmd> GT 4500]
#<speed-cmd> = 4500
O10 endif
S#<speed-cmd>
M3
;o10 endif
o<myspindlespeedup> endsub
M2

View File

@@ -0,0 +1,10 @@
o<myspindlestart> sub
o10 if [#<_spindle_on> EQ 1]
M5
o10 else
S800
M3
o10 endif
;M103
o<myspindlestart> endsub
M2

View File

@@ -0,0 +1,23 @@
o<mytouch> sub
o10 if [EXISTS[#<_hal[jog-axis-sel]>]]
#<selected-axis> = #<_hal[jog-axis-sel]>
;(DEBUG, my-mpg.axis-selector: #<selected-axis>)
(touch off)
o20 if [#<selected-axis> EQ 0]
G10 L20 P0 X0
M103
(MSG, touch off x axis)
o20 endif
(touch off z axis)
o30 if [#<selected-axis> EQ 1]
G10 L20 P0 Z0
M103
(MSG, touch off z axis)
o30 endif
o10 else
(DEBUG, didn't exist)
o10 endif
o<mytouch> endsub
M2

View File

@@ -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<myspindlegain> 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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
<mpg>
<function>Touch off selected axis<gcode>O&lt;mytouch&gt;call</gcode></function>
<function>Return to safe Z<gcode>G53 G0 Z0</gcode></function>
<function>Return to home<gcode>G53 G0 X0 Y0 Z0</gcode></function>
</mpg>

View File

@@ -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)]

View File

@@ -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

View File

@@ -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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.8 MiB

View File

@@ -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:
<!--300,711->Peck distance
Make sure the comment has "use markup" selected for the tooltip.
Also ensure that the control has the "show_keyb" function allocated for
the Widget->button_press event. If you copy-paste a tab and copy-paste
extra controls this should be automatic.
_All_ your new spinboxes will need their own new Adjustment, or they will
change value when you alter the original spinbox that they are a copy of.

View File

@@ -0,0 +1,64 @@
;boring
O<boring> 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 = [[#23 - #13] * 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
(debug, Turning finish dia #1 start dia #14 start length #13 finish length #5 coolant #9)
O100 WHILE [#14 LT [#1 - #3]]
g0 X #14
#14=[#14 + #3]
G1 X #14
G1 Z #23 X[#14 + #24]
O101 IF [#6 GT 0]
G3 Z#5 X[#14 + #24 + #21] I#21 K#20
G1 X[#14 + #24 + #21 - #3]
O101 ELSE
G1 X[#14 + #24 - [#3 * 1.5]]
O101 ENDIF
G0 Z[#13]
O100 ENDWHILE
G0 x#1
G1 Z #23 X[#1 + #24]
O102 IF [#6 GT 0]
G3 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
G0 Z #13
G0 X #1 ; For touch-off
M5 M9
G7
O<boring> endsub
M2

View File

@@ -0,0 +1,77 @@
;chamfer
O<chamfer> 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 D1500 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
g1 x#1 z[#5 - #20]
g1 x #14
g0 z#13
o100 endwhile
g0 x#14 z#13
g0 x[#1 - #8]
g1 z#5
g1 x#1 z[#5 - #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
g1 x#1 z[#5 - #20]
g1 x #14
g0 z#13
o102 endwhile
g0 x#14 z#13
g0 x[#1 + #8]
g1 z#5
g1 x#1 z[#5 - #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
g1 x#1 z[#5 + #20]
g1 x #14
g0 z#13
o103 endwhile
g0 x#14 z#13
g0 x[#1 - #8]
g1 z#5
g1 x#1 z[#5 + #8]
g1 x #14
g0 z#13
O101 endif
M5 M9
G7
O<chamfer> endsub
m2
%

View File

@@ -0,0 +1,49 @@
;drilling
; Use T = 0 for tailstock drilling, then this just sets speed
O<drilling> SUB
G18 ; XZ Plane
G21 ; Metric Units
G90 ; Absolute Distance
G91.1 ; but not for arcs
#10 = [#2 * 1000 / [ #1 * 3.141592]]
(debug, #10)
O90 IF [#7 GT 0.5]
M8
O90 ENDIF
O100 IF [#6 LT 0.5]
G97 M3 S#10
O<drilling> RETURN
O100 ENDIF
M6 T#6 G43
G0 X0
O83 IF [#5 GT 0] ; Pecking
G17
G95 F#3 ; Feed-Per-Rev Mode
G97 M3 S#10
G98
G83 R#<_z> Q#5 Z#4
M5 M9 G18
O<drilling> RETURN
O83 ENDIF
O82 IF [1]; not pecking
G17
G95 F#3 ; Feed-Per-Rev Mode
G97 M3 S#10
G98
G82 R#<_z> P0.5 Z#4
M5 M9 G18
O82 ENDIF
O<drilling> ENDSUB
O<drilling> call [10] [100] [0.03] [0] [2] [0] [1]
M2

View File

@@ -0,0 +1,45 @@
;Facing
O<facing> sub
G7 ; Lathe Diameter Mode
G18 ; XZ Plane
G21 ; Metric Units
G90 ; Absolute Distance
M6 T#7 G43
O90 IF [#8 GT 0.5]
M8
O90 ENDIF
O10 IF [#6 NE 0]
(MSG, Angled facing isn't supported yet)
O10 ENDIF
#14 = [#<_x> * 2] (starting X)
#13 = #<_z> (starting Z)
G96 D2500 S#2 ; Constant Surface Speed Mode
M3
g95 F#4 ; Feed-Per-Rev Mode
g4p1 ; Wait to reach speed
O200 WHILE [#13 GT #5 + #3]
#13=[#13-#3]
G1 Z#13
G1 X#1
G0 Z[#13+#3]
G0 X#14
G0 Z#13
O200 ENDWHILE
G1 Z#5
G1 X#1
G0 Z[#13+#3]
G0 X[#14+#3]
G0 Z#5 ; For touch-off
M5 M9
O<facing> endsub
M2

View File

@@ -0,0 +1,32 @@
;grooving
O<grooving> sub
G8 ; Radius mode (easier maths)
G18 ; XZ Plane
G21 ; Metric Units
G90 ; Absolute Distance
G91.1 ; but not for arcs
M6 T#4 G43
#1 = [#1 / 2] ; because of radius mode
#14 = [#<_x>] (starting X)
G96 D1500 S#2 ; Constant Surface Speed Mode
m3 ;Start Spindle
g95 F#3 ; Feed-Per-Rev Mode
O90 IF [#5 GT 0.5]
M8
O90 ENDIF
g4p1 ; Wait to reach speed
G1 F#3 X#1
G0 X#14
M5 M9
G7
O<grooving> endsub
M2

View File

@@ -0,0 +1,165 @@
# EMC controller parameters for a simulated machine.
# General note: Comments can either be preceded with a # or ; - either is
# acceptable, although # is in keeping with most linux config files.
# General section -------------------------------------------------------------
[EMC]
VERSION = 1.1
MACHINE = gmoccapy_lathe
#DEBUG = 0x7FFFFFFF
DEBUG = 0
# for details see nc_files/subroutines/maco_instructions.txt
[DISPLAY]
DISPLAY = gmoccapy
LATHE = 1
BACK_TOOL_LATHE = 0
# Cycle time, in milliseconds, that display will sleep between polls
CYCLE_TIME = 100
# Highest value that will be allowed for feed override, 1.0 = 100%
MAX_FEED_OVERRIDE = 1.5
MAX_SPINDLE_OVERRIDE = 1.2
MIN_SPINDLE_OVERRIDE = .5
# Prefix to be used
PROGRAM_PREFIX = ../../nc_files/:./
# Introductory graphic
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
# list of selectable jog increments
INCREMENTS = 1.000 mm, 0.100 mm, 0.010 mm, 0.001 mm
EMBED_TAB_NAME = Cycles
EMBED_TAB_LOCATION = ntb_preview
#EMBED_TAB_LOCATION = ntb_user_tabs
EMBED_TAB_COMMAND = halcmd loadusr -Wn gladevcp gladevcp -c gladevcp -U notouch=1 -U norun=0 -u lathehandler.py -x {XID} lathemacro.ui
[FILTER]
PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image
PROGRAM_EXTENSION = .py Python Script
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python
# Task controller section -----------------------------------------------------
[RS274NGC]
RS274NGC_STARTUP_CODE = G18 G21 G40 G49 G54 G80 G90 G94 G8 M9 M5 G64 P0.005
PARAMETER_FILE = sim.var
SUBROUTINE_PATH = macros:./
# Motion control section ------------------------------------------------------
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
BASE_PERIOD = 100000
SERVO_PERIOD = 1000000
# Hardware Abstraction Layer section --------------------------------------------------
[TASK]
TASK = milltask
CYCLE_TIME = 0.001
# Part program interpreter section --------------------------------------------
[HAL]
HALFILE = core_sim_lathe.hal
HALFILE = spindle_sim.hal
HALFILE = simulated_home_lathe.hal
# Single file that is executed after the GUI has started.
#POSTGUI_HALFILE = gmoccapy_postgui.hal
HALUI = halui
# Trajectory planner section --------------------------------------------------
[HALUI]
#No Content
[TRAJ]
COORDINATES = X Z
LINEAR_UNITS = mm
ANGULAR_UNITS = degree
DEFAULT_LINEAR_VELOCITY = 50
MAX_LINEAR_VELOCITY = 234
POSITION_FILE = position.txt
#NO_FORCE_HOMING = 1
# First axis
[EMCIO]
EMCIO = io
CYCLE_TIME = 0.100
# tool table file
TOOL_TABLE = lathe.tbl
[KINS]
KINEMATICS = trivkins coordinates=XZ
JOINTS = 2
[AXIS_X]
MIN_LIMIT = -50.0
MAX_LIMIT = 200.0
MAX_VELOCITY = 166
MAX_ACCELERATION = 1500.0
[JOINT_0]
TYPE = LINEAR
MAX_VELOCITY = 166
MAX_ACCELERATION = 1500.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -50.0
MAX_LIMIT = 200.0
FERROR = 0.050
MIN_FERROR = 0.010
HOME_OFFSET = 0.0
HOME = 10
HOME_SEARCH_VEL = 200.0
HOME_LATCH_VEL = 20.0
HOME_USE_INDEX = NO
HOME_IGNORE_LIMITS = NO
HOME_SEQUENCE = 1
HOME_IS_SHARED = 1
# Third axis
[AXIS_Z]
MIN_LIMIT = -75.0
MAX_LIMIT = 1000.0
MAX_VELOCITY = 166
MAX_ACCELERATION = 1500.0
[JOINT_1]
TYPE = LINEAR
MAX_VELOCITY = 166
MAX_ACCELERATION = 1500.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -75.0
MAX_LIMIT = 1000.0
FERROR = 0.050
MIN_FERROR = 0.010
HOME_OFFSET = 1.0
HOME = -10
HOME_SEARCH_VEL = 200.0
HOME_LATCH_VEL = 20.0
HOME_USE_INDEX = NO
HOME_IGNORE_LIMITS = NO
HOME_SEQUENCE = 0
HOME_IS_SHARED = 1
# section for main IO controller parameters -----------------------------------
[MACROS]
MACRO = i_am_lost
MACRO = halo_world
MACRO = jog_around
MACRO = increment xinc yinc
MACRO = go_to_position X-pos Y-pos Z-pos

View File

@@ -0,0 +1,219 @@
#!/usr/bin/env python3
# vim: sts=4 sw=4 et
# This is a component of EMC
# savestate.py copyright 2013 Andy Pugh
# based on code from
# probe.py Copyright 2010 Michael Haberler
#
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA''''''
import os,sys
from gladevcp.persistence import IniFile,widget_defaults,set_debug,select_widgets
import hal
import hal_glib
import glib
import linuxcnc
import cairo
import signal
import re
import gi
gi.require_version('Rsvg', '2.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GObject
from gi.repository import Pango
from gi.repository import Rsvg
from gi.repository import GdkPixbuf
debug = 0
notouch = 0
norun = 0
svgfile = os.path.join(os.path.dirname(__file__), "LatheMacro.svg")
class HandlerClass:
active = False
tab_num = 0
def on_expose(self,nb,data=None):
tab_num = nb.get_current_page()
tab = nb.get_nth_page(tab_num)
alloc = tab.get_allocation()
x, y, w, h = (alloc.x, alloc.y, alloc.width, alloc.height)
pixbuf = self.svg.get_pixbuf_sub(f'#layer{tab_num}').scale_simple(w-10, h-10, GdkPixbuf.InterpType.BILINEAR)
im = self.builder.get_object(f'Image{tab_num}')
im.set_from_pixbuf(pixbuf)
for c in im.get_parent().get_children():
if c.get_has_tooltip():
m = re.findall(r'<!--(\d+),(\d+)-->', 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)]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
;radius
O<radius> 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<radius> endsub
m2
%

View File

@@ -0,0 +1,59 @@
;threading
O<threading> 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]
#<OD> = [#1]
#<ID> = [#1 - 1.3 * #4]
;g1X [#<ID> - 1] ;thread truncation
;g0 Z #13
;g1 X #<ID>
;g1 Z #5
G0 X[#<ID> - 1]
g0 Z #13
#3 = [#4 * 1.3]
(debug, INTERNAL Threading thread dia-#1 start-#13 finish-#5 Pitch-#4 Depth-#3)
g1X [#<ID> - 1]
g76 p#4 z#5 i1 j1 k#3 h3 r1.5 q29.5 e0 l0
O51 ELSE
#<OD> = [#1 - 0.108 * #4]
#<ID> = [#1 - 1.0825 * #4]
(debug, EXTERNAL Threading OD = #<OD> ID = #<ID>)
#3 = [#4 * 1.0825]
g1X [#<OD> + 1] ;final thread truncation
g0 z#13
g1 X #<OD>
g1 Z #5
G0 X[#<OD> +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<threading> endsub
M2

View File

@@ -0,0 +1,66 @@
;Turning
O<turning> 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<turning> endsub
M2

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<requires lib="gladevcp" version="0.0"/>
<object class="EMC_Action_MDI" id="hal_action_mdi1">
<property name="label" translatable="yes">Goto Machine Zero</property>
<property name="command">G53 G0 X0 Y0 Z0</property>
</object>
<object class="EMC_Action_MDI" id="hal_action_mdi2">
<property name="command">G53 G0 Z88</property>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkFrame" id="frame4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<child>
<object class="HAL_Table" id="mpg">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">35</property>
<child>
<object class="GtkLabel" id="mpg-func-btn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Func Button:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="HAL_ComboBox" id="func-btn-combo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active">0</property>
<property name="column">0</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;MPG&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1 @@
net all-homed mpg.mpg

10
my-emco-compact-5/mpg.xml Normal file
View File

@@ -0,0 +1,10 @@
<mpg>
<halpin>"axis-selector"<event>sela</event><type>s32</type></halpin>
<halpin>"scale-selector"<event>sels</event><type>s32</type></halpin>
<halpin>"jog-pos-btn"<event>jpos</event><type>bit</type></halpin>
<halpin>"jog-neg-btn"<event>jneg</event><type>bit</type></halpin>
<halpin>"estop-btn"<event>est</event><type>bit</type></halpin>
<halpin>"func-btn"<event>func</event><type>bit</type></halpin>
<halpin>"joystick-x"<event>x</event><type>float</type></halpin>
<halpin>"joystick-z"<event>z</event><type>float</type></halpin>
</mpg>

View File

@@ -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

View File

@@ -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<myspindlespeedup> call [100] ;0, connected to mpg button
MDI_COMMAND = O<myspindlespeeddown> call [100] ;1, connected to mpg button
MDI_COMMAND = O<mytouch> call ;2, connected to mpg button
MDI_COMMAND = O<myspindlegain> call [0.48483] [20.16466] ;3, spindle speed selection AC1
MDI_COMMAND = O<myspindlegain> call [0.32571] [-8.05714] ;4, spindle speed selection AC2
MDI_COMMAND = O<myspindlegain> call [0.20098] [22.64117] ;5, spindle speed selection AC3
MDI_COMMAND = O<myspindlegain> 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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
from stdglue import *

View File

@@ -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: #<speed>
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: #<feed>
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: #<tool> #<pocket>
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:
# #<tool_in_spindle>
# #<selected_tool>
# #<current_pocket>
# #<selected_pocket>
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: #<tool> #<pocket>
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#<selected_tool> 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

View File

@@ -0,0 +1 @@
import remap

View File

@@ -0,0 +1,347 @@
#! /usr/bin/python
"""usage serialEventHanlder.py -h -c <name> -d/--debug= <level> -p/--port= <serial port> <path/>in_file.xml
in_file - input xml-file describing what knobs and/or button are on the pendant
-c <name> # name of component in HAL. 'my-mpg' default
-d/--debug= <level> # debug level, default 0
-p/--port= <serial 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 <name> -d/--debug=<level> -p/--port= <serial port> <path/>in_file.xml\n"\
"in_file - input xml-file describing what knobs and/or button are on the pendant\n"\
"-c <name> # name of component in HAL. 'mpg' default\n"\
"-p/--port= <serial 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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<requires lib="gladevcp" version="0.0"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">spindle speed selection:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="img1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixbuf">speeds.png</property>
<property name="icon_size">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HAL_Table" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="HAL_RadioButton" id="radio2">
<property name="label" translatable="yes">AC2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="margin_top">15</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">radio1</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="HAL_RadioButton" id="radio3">
<property name="label" translatable="yes">AC3</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="margin_top">15</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">radio1</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="HAL_RadioButton" id="radio1">
<property name="label" translatable="yes">AC1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="margin_top">15</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()