Im vergleich zu den Anpassungen am Postprozessor für die alte Sinumerik muss hier nur wenig geändert werden, da wir bereits einen sicheren Werkzeugwechsel haben. Aber ich wollte auch hier die Möglichkeit haben die Tischseite vorgeben zu können. Außerdem hatte ich den Effekt das bei hohen Vorschüben LinuxCNC dazu neigte den Vorschub über die Genauigkeit zu stellen, also wollte ich die zusätzlichen Toleranzen setzten daher habe ich drei Zeilen in den // user-defined properties ergänzt:
indexTable: 3, //Side of index table under Spindle 3 if no change useG61orG64: true,// use G64 or G61 for tolerance control G64tolerance: 0.005, //G64 Tolenace uses G61 if 0
Dann mussten das ganze noch umgesetzt werden. Dazu habe ich dann am Ende von function onOpen() noch den dazugehörigen Code ergänzt
//custom codes for Igor
//index Table
if(properties.indexTable == 1)
{
writeBlock(mFormat.format(31));
}
else if(properties.indexTable == 2)
{
writeBlock(mFormat.format(32));
}
//end index table
//begin tolecrance control
if(properties.useG61orG64 == true)
{if(properties.G64tolerance == 0)
{
writeBlock(gFormat.format(61)); // G61
}
else
{
writeBlock(gFormat.format(64), "P" + properties.G64tolerance ); // G64 PQ
}}
//end tolerance control
Ein zweiter Punkt sind meine Werkzeugnummern. Ich verwende vierstellige Werkzeugnummern. Die erst Stelle steht für den Typ und die drei folgenden stellen sind der Durchmesser in 1/10” mm. Also ein Bohrer mit 10,5mm Durchmesser wäre 1105 verschieden die Wahrscheinlichkeit, dass ich zwei gleiche Werkzeuge mit unterschiedlichen Längen in einem Programm brauche sind im Hobbyeinsatz eher gering. Und 10-99 wären dafür noch frei:
Nr
Typ
1.stelle
2.Stelle
3.Stelle
4.Stelle
0
Werkzeug in Spindel
0
0
0
0
001
temporäre werkzeuge
0
0
Typ
Typ
01
Probes
0
1
Typ
Typ
02
Spindle
0
2
typ
typ
03
T-Slot
0
3
10er
1er
04
Scheibenfräser
0
4
druchmesser 10er
Durchmesser 1er
05
Prismenfräser
0
5
Winkel 10er
Winkel 1er
1
Drill
1
10
1
0,1
2
Spotdrill
2
Typ
Typ
Typ
3
Index
3
10
1
0,1
4
Endmill
4
10
1
0,1
5
Roughingendmill
5
10
1
0,1
6
Bullnose
6
10
1
Radius
7
Ball endmill
7
10
1
0,1
8
Formfräser
8
Typ
Typ
Typ
Der Standard-Post für LinuxCNC unterstützt keine 9999 Werkzeuge, daher mussten hier zwei Zeilen angepasst werden:
if (tool.number > 9999) {
warning(localize("Tool number exceeds maximum value."));
}
und
if (lengthOffset > 9999) {
error(localize("Length offset out of range."));
return;
}
Nach all der Arbeit, läuft Igor nun. Damit konnte man sich nun den “Kleinigkeiten” widmen. Wenn der Notaus ausgelöst wurde konnte die Spindel ab 2000 U/min nicht mehr gebremst werden, da zu früh die Stromversorgung zur Steuerung getrennt wurde. Deshalb habe ich das Ladder-Programm überarbeitet. Zum einen habe ich es in drei unabhängige Stränge geteilt. Der erst aktiviert die Steuerung. Kommt von dieser das OK weird der Strohm zu den Motoren eingeschaltet. Außerdem gibt es hier jetzt einen Selbsterhalt, der beim deaktivieren der Steuerung durch den Notaus die Stromversorgung aufrecht erhält bis I3 den Stillstand der Spindel meldet. Der dritte Strang dient zum Lösen der Z-Achs-Bremse, wenn die Steuerung betriebsbereit und die Motoren aktiv sind.
kommen wir jetzt zum Komfort. Ich habe des öfteren vergessen den Kompressor aus zu schalten, deswegen habe ich ein Shelly Funkrelais in den Kompressor gebaut, das ich an Linuxcnc gekoppelt habe. So kann ich nicht mehr nacht vom Kompressor geweckt werden, weil ich vergessen habe ihn aus zu schalten. Außerdem kann ich den 2. Kanal des Shelly als Zeitrelais zum automatischen entwässern des Kessels verwenden. Möglich wurde das durch ein Pythonscript mit dem es möglich ist Hal pins zu erzeugen und so in Linuxcnc zu integrieren.
#!/usr/bin/python
import time
import hal
import urllib3
import atexit
import time
delta_t = 1 # seconds poll interval, hold inputs at least this long
#hal
h = hal.component("compressor")
h.newpin("active",hal.HAL_BIT,hal.HAL_IN)
h.ready()
def finaloff():
r = http.request('GET', 'http://192.168.178.89/relay/1?turn=off')
r = http.request('GET', 'http://192.168.178.89/relay/0?turn=on')
atexit.register(finaloff)
old_start_pin_value = False
started = False
http = urllib3.PoolManager()
while True:
time.sleep(delta_t)
#print h["active"]
start_pin_value = h["active"]
if start_pin_value != old_start_pin_value:
#print("changed")
if started:
started = False
print("compressor off")
r = http.request('GET', 'http://192.168.178.89/relay/1?turn=off')
r = http.request('GET', 'http://192.168.178.89/relay/0?turn=on')
else:
started = True
print("compressor on")
r = http.request('GET', 'http://192.168.178.89/relay/1?turn=on')
r = http.request('GET', 'http://192.168.178.89/relay/0?turn=on')
old_start_pin_value = start_pin_value
Dann habe ich ein weiteres Python script geschrieben mit dem ich die Maschinenstunden erfassen und Wartungsintervalle signalisieren kann. Dazu läuft ein Timer wenn die Maschine in Eingeschaltet und betriebsbereit ist und wird gespeichert. Außerdem gehen gelbe Hinweislampen an, wenn das 50 Stunden oder 2000 Stunden Wartungsintervall erreicht ist.
#!/usr/bin/python
import time
import hal
import atexit
fname = "timelog.txt"
sumlog = "time.txt"
delta_t = 1 # seconds poll interval, hold inputs at least this long
f = open(fname,mode="a+") # a: append or create if file doesnt exist
h = hal.component("timelog")
h.newpin("active",hal.HAL_BIT,hal.HAL_IN)
h.newpin("alarm",hal.HAL_BIT,hal.HAL_OUT)
h.newpin("alarm50",hal.HAL_BIT,hal.HAL_OUT)
h.newpin("alarm2000",hal.HAL_BIT,hal.HAL_OUT)
h.newpin("alarmon",hal.HAL_BIT,hal.HAL_OUT)
h.newpin("alarm50on",hal.HAL_BIT,hal.HAL_OUT)
h.newpin("alarm2000on",hal.HAL_BIT,hal.HAL_OUT)
h.newpin("seconds",hal.HAL_U32,hal.HAL_OUT)
h.newpin("minutes",hal.HAL_U32,hal.HAL_OUT)
h.newpin("hours",hal.HAL_U32,hal.HAL_OUT)
h.ready()
try:
f2= open(sumlog,mode="r+")
runtime=float(f2.readline())
f2.close()
except:
f2= open(sumlog,mode="w+")
runtime=0.0
f2.write(str(runtime))
#f3.flush()
f2.truncate()
f2.close()
m, s = divmod(runtime, 60)
hr, m = divmod(m, 60)
#print(hr,m,s)
h["seconds"]=s
h["minutes"]=m
h["hours"]=hr
old_start_pin_value = False
t_start = time.time()
t_begin = time.time()
msg = ("Begin %s\n" % time.ctime())
f.write(msg)
f.flush()
#2000 hr check
if hr%2000==0:
h["alarm2000"]=True
#h["alarm2000on"]=True
h["alarmon"]=True
msg = ("2000 hour check %s\n" % time.ctime())
f.write(msg)
f.flush()
##50h check
if hr%50==0:
h["alarm50"]=True
#h["alarm50on"]=True
h["alarmon"]=True
msg = ("50 hour check %s\n" % time.ctime())
f.write(msg)
f.flush()
started = False
def finaloff():
if h["active"]:
started = False
print("timer off")
t_now = time.time()
msg = ("Stop: %s Elapsed: %f\n" % (time.ctime(),t_now - t_start))
f.write(msg)
f.flush()
runtime=seconds
savetime=str(seconds)
print savetime
f2= open(sumlog,mode="w+")
f2.write(savetime)
f2.truncate()
f2.close()
msg = ("End %s\n" % time.ctime())
f.write(msg)
f.flush()
atexit.register(finaloff)
while True:
time.sleep(delta_t)
#print h["active"]
start_pin_value = h["active"]
if start_pin_value != old_start_pin_value:
print("changed")
if started:
started = False
print("timer off")
t_now = time.time()
msg = ("Stop: %s Elapsed: %f\n" % (time.ctime(),t_now - t_start))
f.write(msg)
f.flush()
runtime=seconds
savetime=str(seconds)
print savetime
f2= open(sumlog,mode="w+")
f2.write(savetime)
#f3.flush()
f2.truncate()
f2.close()
else:
started = True
print("timer on")
msg = ("Start: %s\n" %time.ctime())
f.write(msg)
f.flush()
t_start = time.time()
f2= open(sumlog,"r")
runtime=float(f2.readline())
f2.close()
print runtime
if start_pin_value:
seconds= runtime+(time.time() - t_start)
m, s = divmod(seconds, 60)
hr, m = divmod(m, 60)
h["seconds"]=s
h["minutes"]=m
h["hours"]=hr
old_start_pin_value = start_pin_value
Da ich inzwischen die Standard-RT kerne verwende gingen meine Latenzen in letzter zeit hoch, doch ich wollte eigentlich nicht wieder einen custom Kernel installieren. Es gibt aber die Boot option Einzelne Kerne für die Echtzeitanwendungen zu reservieren, das hat die Latenzen massiv verbessert, ich reservier die Kerne 2 und 3. Dazu muss in der Datei /etc/default/grub folgende Zeile angepasst werden:
GRUB_CMDLINE_LINUX_DEFAULT="quiet text isolcpus=2,3"
danach noch grub updaten:
sudo update-grub
Zum vergleich vorher:
last latency data is as follows:. 10 secs base min: -78.600 uS max: 71.900 uS sdev: 2.900 uS 10 secs servo min: -97.600 uS max: 101.800 uS sdev: 4.000 uS
Nachher:
last latency data is as follows: 724 secs base min: -34.800 uS max: 34.600 uS sdev: 0.900 uS 724 secs servo min: -22.400 uS max: 22.700 uS sdev: 1.600 uS
Immer öfter kam bei mir der Wunsch auf die Maschine auch per Handrad bewegen zu könne, was der Antasten und Auch das setzten der Nullpunkte erleichtern soll, Ich habe mich für ein Kabelloses XHC-WHB04B-6 entschieden:
Danach ging es an die Installation. Zunächst mussten dazu die sourcen von Linuxcnc gezogen werden:
cd ~
git clone https://github.com/LinuxCNC/linuxcnc dev-linuxcnc
cd dev-linuxcnc/src/
danach im Makefile unter subdirs die Zeile “hal/user_comps/xhc-whb04b-6 \” hinzufügen
./autogen.sh
./configure --with-realtime=uspace
make
sudo make setuid
sudo cp ../bin/xhc-whb04b-6 /usr/bin/
Damit sind die Treiber übersetzt, jetzt müssen noch die Udev Regel erstellt werden. Dazu brauchen wir die Informationen vom USB Dongel
lsusb
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 007: ID 8087:0a2a Intel Corp.
Bus 001 Device 006: ID 0bda:0153 Realtek Semiconductor Corp. 3-in-1 (SD/SDHC/SDXC) Card Reader
Bus 001 Device 005: ID 1c4f:0016 SiGma Micro
Bus 001 Device 004: ID 2575:0401
Bus 001 Device 003: ID 046d:c408 Logitech, Inc. Marble Mouse (4-button)
Bus 001 Device 002: ID 10ce:eb93 Silicon Labs
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Der SIlicon Labs Chip ist der, den wir suchen (10ce:eb93 / VendirID:ProductID) wir jetzt legen wir die Udevregel an:
mcedit /etc/udev/rules.d/99-xhc-whb04b-6.rules und dort tragen wir folgende Zeile ein: ATTR{idProduct}==”eb93″, ATTR{idVendor}==”10ce”, MODE=”0666″, OWNER=”root”, GROUP=”plugdev”
Dann Udev neu laden: sudo udevadm trigger xhc-whb04b-6
Wenn man jetzt das Handrad bewegt oder eine taste drückt sollte es fleißig Daten regnen.
jetzt muss da ganze noch mit Linuxcnc verheiratet werden. Ich habe dafür eine eigene Haldatei gewählt:
loadusr -W xhc-whb04b-6 -H
loadrt ilowpass names=ilowpass.jog.x,ilowpass.jog.y,ilowpass.jog.z,ilowpass.jog.a
addf ilowpass.jog.x servo-thread
addf ilowpass.jog.y servo-thread
addf ilowpass.jog.z servo-thread
addf ilowpass.jog.a servo-thread
setp ilowpass.jog.x.scale 100
setp ilowpass.jog.y.scale 100
setp ilowpass.jog.z.scale 100
setp ilowpass.jog.a.scale 100
setp ilowpass.jog.x.gain 0.01
setp ilowpass.jog.y.gain 0.01
setp ilowpass.jog.z.gain 0.01
setp ilowpass.jog.a.gain 0.01
loadrt scale names=scale.axis.x,scale.axis.y,scale.axis.z,scale.axis.a
addf scale.axis.x servo-thread
addf scale.axis.y servo-thread
addf scale.axis.z servo-thread
addf scale.axis.a servo-thread
setp scale.axis.x.gain 0.01
setp scale.axis.y.gain 0.01
setp scale.axis.z.gain 0.01
setp scale.axis.a.gain 0.01
setp scale.axis.x.offset 0
setp scale.axis.y.offset 0
setp scale.axis.z.offset 0
setp scale.axis.a.offset 0
# Estop
net pdnt.machine.is-on halui.machine.is-on whb.halui.machine.is-on
net pdnt.machine.on whb.halui.machine.on halui.machine.on
net pdnt.machine.off whb.halui.machine.off halui.machine.off
# program
net pdnt.program.is-idle whb.halui.program.is-idle halui.program.is-idle
net pdnt.program.is-paused whb.halui.program.is-paused halui.program.is-paused
net pdnt.program.is-running whb.halui.program.is-running halui.program.is-running
net pdnt.program.resume whb.halui.program.resume halui.program.resume
net pdnt.program.pause whb.halui.program.pause halui.program.pause
net pdnt.program.run whb.halui.program.run halui.program.run
net pdnt.program.stop whb.halui.program.stop halui.program.stop
# axis
net pdnt.joint.X.select whb.halui.joint.x.select halui.joint.0.select
net pdnt.joint.Y.select whb.halui.joint.y.select halui.joint.1.select
net pdnt.joint.Z.select whb.halui.joint.z.select halui.joint.2.select
net pdnt.axis.0.jog-scale whb.axis.0.jog-scale scale.axis.x.in
net pdnt.axis.1.jog-scale whb.axis.1.jog-scale scale.axis.y.in
net pdnt.axis.2.jog-scale whb.axis.2.jog-scale scale.axis.z.in
net scale.axis.0.jog-scale scale.axis.x.out axis.x.jog-scale
net scale.axis.1.jog-scale scale.axis.y.out axis.y.jog-scale
net scale.axis.2.jog-scale scale.axis.z.out axis.z.jog-scale
net pdnt.axis.0.jog-counts whb.axis.0.jog-counts ilowpass.jog.x.in
net pdnt.axis.1.jog-counts whb.axis.1.jog-counts ilowpass.jog.y.in
net pdnt.axis.2.jog-counts whb.axis.2.jog-counts ilowpass.jog.z.in
net pdnt.ilowpass.jog.0.jog-counts ilowpass.jog.x.out axis.x.jog-counts
net pdnt.ilowpass.jog.1.jog-counts ilowpass.jog.y.out axis.y.jog-counts
net pdnt.ilowpass.jog.2.jog-counts ilowpass.jog.z.out axis.z.jog-counts
net pdnt.axis.0.jog-enable whb.axis.0.jog-enable axis.x.jog-enable
net pdnt.axis.1.jog-enable whb.axis.1.jog-enable axis.y.jog-enable
net pdnt.axis.2.jog-enable whb.axis.2.jog-enable axis.z.jog-enable
net pdnt.axis.0.jog-vel-mode whb.axis.0.jog-vel-mode axis.x.jog-vel-mode
net pdnt.axis.1.jog-vel-mode whb.axis.1.jog-vel-mode axis.y.jog-vel-mode
net pdnt.axis.2.jog-vel-mode whb.axis.2.jog-vel-mode axis.z.jog-vel-mode
# macro buttons
net pdnt.macro.1 whb.button.macro-1 halui.mdi-command-01
net pdnt.macro.2 whb.button.macro-2 halui.mdi-command-02
net pdnt.macro.3 whb.button.macro-3 halui.mdi-command-03
net pdnt.macro.4 whb.button.macro-4 halui.mdi-command-04
net pdnt.button.m-home whb.button.m-home halui.mdi-command-05
net pdnt.macro.6 whb.button.macro-6 halui.mdi-command-06
net pdnt.button.w-home whb.button.w-home halui.mdi-command-07
net pdnt.macro.8 whb.button.macro-8 halui.mdi-command-08
net pdnt.macro.9 whb.button.macro-9 halui.mdi-command-09
net pdnt.macro.10 whb.button.macro-10 halui.mdi-command-10
net pdnt.macro.11 whb.button.macro-11 halui.mdi-command-11
net pdnt.macro.12 whb.button.macro-12 halui.mdi-command-12
net pdnt.macro.13 whb.button.macro-13 halui.mdi-command-13
net pdnt.macro.14 whb.button.macro-14 halui.home-all
net pdnt.macro.15 whb.button.macro-15 halui.mdi-command-15
net pdnt.macro.16 whb.button.macro-16 halui.mdi-command-16
net pdnt.button.safe-z whb.button.safe-z halui.mdi-command-17
net pdnt.button.s-on-off whb.button.s-on-off halui.mdi-command-18
net pdnt.button.probe-z whb.button.probe-z halui.mdi-command-19
#net pdnt.macro.20 whb.button.macro-20 halui.mdi-command-20
# already connected to halui.estop.{activate, reset} via whb.halui.estop.{activate, reset}
net pdnt.button.reset whb.button.reset
# already linked to halui.program.stop via whb.program.stop
net pdnt.button.stop whb.button.stop# already connected to halui.program.{run, pause, resume} via whb.halui.program.{run, pause, resume}
net pdnt.button.start-pause whb.button.start-pause
# unused
net pdnt.button.fn whb.button.fn
net pdnt.button.mode-continuous whb.button.mode-continuous
net pdnt.button.mode-step whb.button.mode-step
# spindle
net spindle.is-on whb.halui.spindle.is-on
net spindle.stop whb.halui.spindle.stop
net spindle.forward whb.halui.spindle.forward
net spindle.reverse whb.halui.spindle.reverse
net spindle.spindle-override.value whb.halui.spindle-override.value halui.spindle.0.override.value
net spindle.spindle-override.increase whb.halui.spindle-override.increase halui.spindle.0.override.increase
net spindle.spindle-override.decrease whb.halui.spindle-override.decrease halui.spindle.0.override.decrease
net spindle.velocity.abs-rpm whb.motion.spindle-speed-abs
# mode
net pdnt.halui.mode.auto whb.halui.mode.auto halui.mode.auto
net pdnt.halui.mode.joint whb.halui.mode.joint halui.mode.joint
net pdnt.halui.mode.manual whb.halui.mode.manual halui.mode.manual
net pdnt.halui.mode.mdi whb.halui.mode.mdi halui.mode.mdi
net pdnt.halui.mode.is-auto halui.mode.is-auto whb.halui.mode.is-auto
net pdnt.halui.mode.is-joint halui.mode.is-joint whb.halui.mode.is-joint
net pdnt.halui.mode.is-manual halui.mode.is-manual whb.halui.mode.is-manual
#net pdnt.halui.mode.is-mdi halui.mode.is-mdi whb.halui.mode.is-mdi
# feed
net pdnt.halui.feed-override.scale whb.halui.feed-override.scale halui.feed-override.scale halui.rapid-override.scale
net pdnt.halui.feed-override.direct-val whb.halui.feed-override.direct-val halui.feed-override.direct-value halui.rapid-override.direct-value
net pdnt.halui.feed-override.counts whb.halui.feed-override.counts halui.feed-override.counts halui.rapid-override.counts
net pdnt.halui.feed-override.count-enable whb.halui.feed-override.count-enable halui.feed-override.count-enable
net pdnt.halui.feed-override.value halui.feed-override.value whb.halui.feed-override.value
setp whb.halui.feed-override.min-value [DISPLAY]MIN_FEED_OVERRIDE
setp whb.halui.feed-override.max-value [DISPLAY]MAX_FEED_OVERRIDE
net pdnt.halui.feed-override.increase whb.halui.feed-override.increase halui.feed-override.increase halui.rapid-override.increase
net pdnt.halui.feed-override.decrease whb.halui.feed-override.decrease halui.feed-override.decrease halui.rapid-override.decrease
net pdnt.button.feed-plus whb.button.feed-plus
net pdnt.button.feed-minus whb.button.feed-minus
# axis
net pdnt.halui.axis.0.pos-feedback halui.axis.x.pos-feedback whb.halui.axis.0.pos-feedback
net pdnt.halui.axis.1.pos-feedback halui.axis.y.pos-feedback whb.halui.axis.1.pos-feedback
net pdnt.halui.axis.2.pos-feedback halui.axis.z.pos-feedback whb.halui.axis.2.pos-feedback
net pdnt.halui.axis.0.pos-relative halui.axis.x.pos-relative whb.halui.axis.0.pos-relative
net pdnt.halui.axis.1.pos-relative halui.axis.y.pos-relative whb.halui.axis.1.pos-relative
net pdnt.halui.axis.2.pos-relative halui.axis.z.pos-relative whb.halui.axis.2.pos-relative
Macros und Hal sind bereits passend in der INI hinterlegt:
O<probe_z_half> sub
;check for active axis
o100 if [#<_hal[whb.axis.0.jog-enable]> eq 1] ;If x-axis active
G10 L20 P0 X[#<_x>/2] ;zero X
o100 endif
o110 if [#<_hal[whb.axis.1.jog-enable]> eq 1] ;If Y-axis active
G10 L20 P0 Y[#<_y>/2] ;zero Y
o110 endif
o120 if [#<_hal[whb.axis.2.jog-enable]> eq 1] ;If Z-axis active
G10 L20 P0 Z[#<_z>/2] ;zero Z
o120 endif
O<probe_z_half> endsub
M2
O<go_to_zhome> sub
G53 G0 Z0
O<go_to_zhome> endsub
M2
O<probe_z> sub
;check for active axis
o100 if [#<_hal[whb.axis.0.jog-enable]> eq 1] ;If x-axis active
G10 L20 P0 X0 ;zero X
o100 endif
o110 if [#<_hal[whb.axis.1.jog-enable]> eq 1] ;If Y-axis active
G10 L20 P0 Y0 ;zero Y
o110 endif
o120 if [#<_hal[whb.axis.2.jog-enable]> eq 1] ;If Z-axis active
G10 L20 P0 Z0 ;zero Z
o120 endif
O<probe_z> endsub
M2
Damit ist er Retrofit mehr oder weniger abgeschlossen. Es wird nach und nach immer mal wieder Änderungen oder Erweiterungen geben.
Es waren ja noch genug IO’s frei und um einem das Einrichten der Werkzeuge zu erleichtern habe ich mir einen einfachen Werkzeuglängensensor beschafft und in Igor verbaut. Das ist die erste Maßnahme, die über den Retrofit hinaus geht. Daher mussten hier erst mal neue Leitungen gezogen werden und ich habe die 7i77 in der Steuerkonsole dafür ausgesucht um die Wege kurz zu halten:
Jetzt musste noch die Software vorbereitet werden und der Ort hinterlegte werden. Das macht man im Offsets Tab, hier hinterlegt man auch ie Wege und Geschwindigkeiten für das Antasten
Die Steuerung erfolgt über den Tool Tab, auch hier habe ich mir wieder ein paar Sachen angepasst. Und jetzt kommt auch der Zeitpunkt wo ich auf mein Werkzeugwechsel-Script eingehen werde. Nicht alle meine Werkzeughalter sind für den Wechsler geeignet, daher unterscheide ich in allen Skripten zwischen Werkzeugen im Wechsler und welchen die Manuell gewechselt werden müssen. Doch später dazu mehr.
Zunächst gehen wir hier das Toolchange Panel durch:
M6 - MDI Command remapped to - toolchang2.ngc
o<toolchange2> sub
(M108 P#<_current_tool> Q#<_selected_tool> )
;assign the tool numbers held in parameters to the pocket numbers
#1 = #5190
#2 = #5191
#3 = #5192
#4 = #5193
#5 = #5194
#6 = #5195
#7 = #5196
#8 = #5197
#9 = #5198
#10 = #5199
#11 = #5200
#12 = #5201
;assign the variables passed by M6 to some parameters
#100 = #<_selected_tool>
#110 = #<_current_tool>
(#120 = #<selected_pocket>)
O10 if [#100 EQ #110] ; checks if tool in the spindle is same as requested
o<toolchange> endsub [1]
M2
O10 endif
#<next_pocket> = 0 ; assigns 0 to the next pocket for a later check if the tool is found in the basket
#<loaded_pocket> = 0 ; assigns 0 to the next pocket for a later check if the tool is found in the basket and loaded
#15 = 12 ;assign test parameter the number of pockets in the carousel
O100 do
O110 if [#[5189 + #15] EQ #100] ; checks all pockets to see if it contains tool number requested as the new tool
#<next_pocket> = #15 ; if tool is found in pocket, assigns the next pocket
O110 endif
O115 if [#[5189 + #15] EQ #110] ; checks if the pocket is loaded in spindle
#<loaded_pocket> = #15
O115 endif
#15= [#15 - 1]
O100 while [#15 GT 0]
;now we know which pocket the next tool is sitting in
;and we know inwhich pocket the current tool is
;we need to know if we need to put a tool away
;or if there is no tool in the spindle
O180 IF [#110 GT 0] ; checks if there is a valid tool in the spindle
O190 if [#<loaded_pocket> EQ 0] ;If there is a tool in the spindle, checks if it is an pocket
; Go for manual Tool removal
G53 G0 Z0 ;raise spindle
G53 G0 X0 Y0 ;move to door
M125 ; remove tool
O190 endif
O195 if [#<loaded_pocket> GT 0] ;If there is a tool in the spindle, checks if it is an pocket
; Go for atc Tool removal
G0 G53 Z0 ; raise spindle
M110 ; draw bar loose
M112 ; lower basket
M116 ; raise pockets
O195 endif
O180 ENDIF
O200 IF [#100 GT 0] ; selected tool is not tool0
O210 if [#<next_pocket> EQ 0] ;if new tool is not in a pocket
; Go for manual Tool load
M113 ; Raise basket
G53 G0 Z0 ; Raise spindle
G53 G0 X0 Y0 ; move to door
M110 ; draw bar loose
M126 ; manual tool load
O210 endif
O215 if [#<next_pocket> GT 0] ;If new tool is in a pocket
; Go for atc Tool Load
G0 G53 Z0 ; raise sindle
M110 ; draw bar loose
M112 ; Lower basket
M131 P#<next_pocket> ; load pocket
M114 ; air blast
S150 M3 ; rotate spindle
M113 ; raise basket
M115 ; stop air blast
M111 ; clamp tool
M5 ; stop spindle
O215 endif
O200 Else
;new tool is 0 raise basket and clamp drawbar
M113 ;raise basket
M111 ;clamp drawbar
O200 ENDIF
M61 Q#100
o<toolchang2> endsub [1]
M2
Damit konnte Igor das erste mal mit neuer Steuerung bewegt werden. Wie gesagt es war nicht alles so linear wir hier dargestellt. Das ganze hier dient mir mehr oder weniger als Dokumentation, Falls ich sowas nochmal machen muss, auch welchem Grund auch immer. Aber mit all den Voran gegangen Schritten ließ sich das ganze Starten und Homen:
Mit dem Schritt können wir uns nun dem Werkzeugwechsel und dem Wechseltisch widmen. Probe Basic arbeitet normalerweise mit einem Karussell-Wechsler, der sich doch etwas anders Verhält als der Korbwechsler von Igor. Daher habe ich die Seite für den Werkzeugwechsel an meine Bedürfnisse angepasst und mich dabei an den Funktionen orientiert, die auch in der Sinumerik zur Verfügung standen
Die einzelnen Knöpfe mit den dazugehörigen Programmen werde ich hier durch gehen. Doch zuvor kommen noch zwei kleine Programme, die helfen Fehler zu vermeiden weil bestimmte Parameter nicht erreicht wurden waitfor liegt im $USER/bin/ Ordner:
#!/bin/bash
n=0
if [ $# != 2 ]; then
echo usage: $0 SignalName DesiredValue
exit 1
fi
signal=$1
value=$2
while :; do
set -- $(halcmd -s show sig $signal)
if [ x"$2" == x"$value" ]; then
exit 0
fi
sleep 0.25
if [ $n -gt 20 ]; then
zenity --info --text "$signal hat nach $n Zyklen den Wert $value nicht erreicht"
fi
let "n++"
done
Fangen wir dem dem “ATC Manual Control Panel” hier haben wir mehr oder weniger die Komplette Steuerung der einzelnen Teilschritte, die für den Tisch und Werkzeugwechsel notwendig sind Jeweils der Knopf und das dazugehörige Programm dazu:
Lock table - MDI Button - M121
#!/bin/bash
#Tisch verriegeln M121
while :; do
set -- $(halcmd -s show sig i-table-is-1)
seite1=$2
set -- $(halcmd -s show sig i-table-is-2)
seite2=$2
echo $seite1
echo $seite2
if [ "$seite1" == "TRUE" ] || [ "$seite2" == "TRUE" ] ; then
halcmd sets o-table-up FALSE
halcmd sets o-table-lock TRUE
waitfor i-table-is-up FALSE
waitfor o-table-lock TRUE
exit 0
fi
sleep 2
done
exit 0
Change Table - MDI Button - M124
#!/bin/bash
#Tisch wechseln M124
set -- $(halcmd -s show sig i-table-is-1)
seite1=$2
set -- $(halcmd -s show sig i-table-is-2)
seite2=$2
if [ "$seite1" == "TRUE" ] ; then
~/linuxcnc/configs/IgorProbe/nc_files/M123
fi
if [ "$seite2" == "TRUE" ] ; then
~/linuxcnc/configs/IgorProbe/nc_files/M122
fi
exit 0
1 - MDI Button - M122
#!/bin/bash
#Tisch Seite 1 M122
set -- $(halcmd -s show sig i-table-is-1)
seite1=$2
if [ "$seite1" == "TRUE" ] ; then
exit 0
else
~/linuxcnc/configs/IgorProbe/nc_files/M120
waitfor i-table-is-up TRUE
halcmd sets o-table-1 TRUE
waitfor i-table-is-1 TRUE
# sleep 3
~/linuxcnc/configs/IgorProbe/nc_files/M121
halcmd sets o-table-1 FALSE
fi
exit 0
2 - MDI Button - M123
#!/bin/bash
#Tisch Seite 2 M123
set -- $(halcmd -s show sig i-table-is-2)
seite2=$2
if [ "$seite2" == "TRUE" ] ; then
exit 0
else
~/linuxcnc/configs/IgorProbe/nc_files/M120
waitfor i-table-is-up TRUE
halcmd sets o-table-2 TRUE
waitfor i-table-is-2 TRUE
# sleep 3
~/linuxcnc/configs/IgorProbe/nc_files/M121
halcmd sets o-table-2 FALSE
fi
exit 0
Dann wäre da noch die Rechte Seite, bei der geht es um das Eigentliche Laden von Werkzeugen in den Wechsler:
Begin Load Basket - subcall Button - beginloadtoolchanger.ngc
o<beginloadtoolchanger> sub
(print, o<beginloadtoolchanger>)
O10 if [#<_current_tool> gt 0] ; checks if spindle empty
(MSG, Spindle not epmty)
o<toolchange> endsub [1]
M2
O10 endif
M110
M112
M116
o<beginloadtoolchanger> endsub [1]
M2
Load Toolchanger - subcall Button - loadtoolchanger.ngc
(author: PL)
(version: 0.1)
(date: 7.3.2020)
(Bring ATC Arm down for loading)
o<loadtoolchanger> sub
O10 if [#<_current_tool> gt 0] ; checks if spindle empty
(MSG, Spindle not epmty)
o<toolchange> endsub [1]
M2
O10 endif
O20 if [#<_hal[i-tool-basket-is-down]> eq 0 ] ; checks if basket is ready
(MSG, basket not ready)
o<toolchange> endsub [1]
M2
O20 endif
;assign the variables from UI to some parameters
#<loadarmnr_atc_page> = #1
#<tool_number_entry_atc_page> = #12
;M108 P#<tool_number_entry_atc_page> Q#<loadarmnr_atc_page>
M131 P#<loadarmnr_atc_page>
M132 P#<tool_number_entry_atc_page>
(DEBUG, EVAL[vcp.getWidget{"dynatc"}.store_tool{#<loadarmnr_atc_page>, #<tool_number_entry_atc_page>}])
#[5189 + #<loadarmnr_atc_page>] = #<tool_number_entry_atc_page>
;M108 P[5189 + #<loadarmnr_atc_page>] Q#[5189 + #<loadarmnr_atc_page>]
M116
;assign the tool numbers in the pockets to the parameters
o<loadtoolchanger> endsub
M2
Hier war ich Anfangs sehr überfordert und habe eine erst mal alles im pncconf Wizzard mit einer anderen Mesakarte (5i25 und der 7i77) ans laufen bringen. Vielleicht wird die 7i92 inzwischen unterstützt. Was wir brauchen sind Encoder, Beschleunigungen usw. dann hat man eine 1. Konfiguration bei der man dann alles der 5i25 durch die 7I92 ersetzt. Das ist eigentlich nur eine Zeile:
Ich habe bei mir die Logik das alle Achsen negativ Laufen von der Ursprünglichen Konfiguration der Sinumerik übernommen, daher sind bei mir die Encoder negiert. Die Hal ist recht umfangreich und wie man hier sieht ist auch inzwischen ein Handrad verbaut. Dazu wird es noch einen eigenen Beitrag geben. Kommen wir jetzt zu den Einzelnen Hal Dateien:
# first load all the RT modules that will be needed
# kinematics
loadrt [KINS]KINEMATICS
# motion controller, get name and thread periods from ini file
loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS num_spindles=[TRAJ]SPINDLES
loadrt hostmot2
loadrt hm2_eth board_ip="192.168.1.121" config=" num_encoders=6 num_pwmgens=0 num_stepgens=0 sserial_port_0=000xxx sserial_port_1=000xxx"
setp hm2_7i92.0.watchdog.timeout_ns 5000000
loadrt pid names=pid.x,pid.y,pid.z,pid.s
# classic ladder
loadrt classicladder_rt #numBits=40 numWords=30 numArithmExpr=100
addf classicladder.0.refresh servo-thread
# Load the ladder
#loadusr classicladder powerup.clp
loadusr classicladder --nogui powerup.clp
# estop
loadrt estop_latch count=3
addf estop-latch.0 servo-thread
addf estop-latch.1 servo-thread
addf estop-latch.2 servo-thread
#Spindle ramp
loadrt limit2 names=spindle-ramp
loadrt near names=spindle-atspeed
# add the Spindele functions to a thread
addf spindle-ramp servo-thread
addf spindle-atspeed servo-thread
#and2
loadrt or2 count=1
addf or2.0 servo-thread
# set the parameter for max rate-of-change
# (max spindle accel/decel in units per second)
setp spindle-ramp.maxv 1000
# add motion controller functions to servo thread
addf hm2_7i92.0.read servo-thread
addf motion-command-handler servo-thread
addf motion-controller servo-thread
addf pid.x.do-pid-calcs servo-thread
addf pid.y.do-pid-calcs servo-thread
addf pid.z.do-pid-calcs servo-thread
addf pid.s.do-pid-calcs servo-thread
addf hm2_7i92.0.write servo-thread
# external output signals
# 7i71
net o-tool-clean hm2_7i92.0.7i71.1.1.output-00
net o-tool-01-down hm2_7i92.0.7i71.1.1.output-01
net o-tool-02-down hm2_7i92.0.7i71.1.1.output-02
net o-tool-03-down hm2_7i92.0.7i71.1.1.output-03
net o-tool-04-down hm2_7i92.0.7i71.1.1.output-04
net o-tool-05-down hm2_7i92.0.7i71.1.1.output-05
net o-tool-06-down hm2_7i92.0.7i71.1.1.output-06
net o-tool-07-down hm2_7i92.0.7i71.1.1.output-07
net o-tool-08-down hm2_7i92.0.7i71.1.1.output-08
net o-tool-09-down hm2_7i92.0.7i71.1.1.output-09
net o-tool-10-down hm2_7i92.0.7i71.1.1.output-10
net o-tool-11-down hm2_7i92.0.7i71.1.1.output-11
net o-tool-12-down hm2_7i92.0.7i71.1.1.output-12
net o-tool-basket-down hm2_7i92.0.7i71.1.1.output-13
net o-tool-basket-up hm2_7i92.0.7i71.1.1.output-14
net o-tool-open hm2_7i92.0.7i71.1.1.output-15
net o-tool-all-up hm2_7i92.0.7i71.1.1.output-16
net o-steuerung-1 hm2_7i92.0.7i71.1.1.output-18
net o-impulsfreigabe hm2_7i92.0.7i71.1.1.output-17
net o-pump-1 hm2_7i92.0.7i71.1.1.output-19
net o-airpressure-1 hm2_7i92.0.7i71.1.1.output-20
net o-chiptransport hm2_7i92.0.7i71.1.1.output-21
net o-pump-2 hm2_7i92.0.7i71.1.1.output-22
net o-power-drives hm2_7i92.0.7i71.1.1.output-23
net o-power-drives-delay hm2_7i92.0.7i71.1.1.output-24
#bei Transport auskommentieren
net o-brake-z hm2_7i92.0.7i71.1.1.output-25
#/bei Transport auskommentieren
net o-pump-3 hm2_7i92.0.7i71.1.1.output-27
# --- SPINDLE-ENABLE ---
#net spindle-enable hm2_7i92.0.7i71.1.1.output-26
net o-impulsfreigabe hm2_7i92.0.7i71.1.1.output-26
net spindle-enable hm2_7i92.0.7i77.0.0.output-01
# --- Table-Out ---
net o-table-up hm2_7i92.0.7i71.1.1.output-28
net o-table-lock hm2_7i92.0.7i71.1.1.output-29
net o-table-2 hm2_7i92.0.7i71.1.1.output-30
net o-table-1 hm2_7i92.0.7i71.1.1.output-31
net error1 hm2_7i92.0.7i71.1.1.output-32
net enable1 hm2_7i92.0.7i71.1.1.output-33
# --- COOLANT-FLOOD ---
net coolant-flood hm2_7i92.0.7i71.1.1.output-34
net o-dummy35 hm2_7i92.0.7i71.1.1.output-35
net o-dummy36 hm2_7i92.0.7i71.1.1.output-36
#---clean-probe
net o-probe-clean hm2_7i92.0.7i71.1.1.output-37
# --- COOLANT-MIST ---
net coolant-mist hm2_7i92.0.7i71.1.1.output-38
#---- NOT CONNECTED ----
net o-dummy39 hm2_7i92.0.7i71.1.1.output-39
net o-dummy40 hm2_7i92.0.7i71.1.1.output-40
net o-dummy41 hm2_7i92.0.7i71.1.1.output-41
net o-dummy42 hm2_7i92.0.7i71.1.1.output-42
net o-dummy43 hm2_7i92.0.7i71.1.1.output-43
#net o-dummy44 hm2_7i92.0.7i71.1.1.output-44
#bei Transport auskommentieren
net z-enable hm2_7i92.0.7i71.1.1.output-45
net y-enable hm2_7i92.0.7i71.1.1.output-46
net x-enable hm2_7i92.0.7i71.1.1.output-47
#/bei Transport auskommentieren
#7i77
# --- SPINDLE-BRAKE ---
#net spindle-brake hm2_7i92.0.7i77.0.0.output-05
net o-power-drives-delay hm2_7i92.0.7i77.0.0.output-00
#---- NOT CONNECTED ----
net o-2dummy02 hm2_7i92.0.7i77.0.0.output-02
net o-2dummy03 hm2_7i92.0.7i77.0.0.output-03
net o-2dummy04 hm2_7i92.0.7i77.0.0.output-04
net o-2dummy05 hm2_7i92.0.7i77.0.0.output-05
net o-2dummy06 hm2_7i92.0.7i77.0.0.output-06
net o-2dummy07 hm2_7i92.0.7i77.0.0.output-07
net o-2dummy08 hm2_7i92.0.7i77.0.0.output-08
net o-2dummy09 hm2_7i92.0.7i77.0.0.output-09
net o-2dummy10 hm2_7i92.0.7i77.0.0.output-10
net o-2dummy11 hm2_7i92.0.7i77.0.0.output-11
net o-2dummy12 hm2_7i92.0.7i77.0.0.output-12
net o-2dummy13 hm2_7i92.0.7i77.0.0.output-13
net o-2dummy14 hm2_7i92.0.7i77.0.0.output-14
net o-2dummy15 hm2_7i92.0.7i77.0.0.output-15
# external input signals
# 7i70
net i-tool-03-is-up hm2_7i92.0.7i70.1.0.input-00
net i-tool-03-is-down hm2_7i92.0.7i70.1.0.input-01
net i-tool-02-is-up hm2_7i92.0.7i70.1.0.input-02
net i-tool-02-is-down hm2_7i92.0.7i70.1.0.input-03
net i-tool-01-is-up hm2_7i92.0.7i70.1.0.input-04
net i-tool-01-is-down hm2_7i92.0.7i70.1.0.input-05
net i-tool-12-is-up hm2_7i92.0.7i70.1.0.input-06
net i-tool-12-is-down hm2_7i92.0.7i70.1.0.input-07
net i-tool-05-is-down hm2_7i92.0.7i70.1.0.input-08
net i-tool-05-is-up hm2_7i92.0.7i70.1.0.input-09
net i-tool-04-is-up hm2_7i92.0.7i70.1.0.input-10
net i-tool-10-is-down hm2_7i92.0.7i70.1.0.input-12
net i-tool-is-open hm2_7i92.0.7i70.1.0.input-11
net i-tool-10-is-up hm2_7i92.0.7i70.1.0.input-13
net i-tool-11-is-down hm2_7i92.0.7i70.1.0.input-14
net i-tool-11-is-up hm2_7i92.0.7i70.1.0.input-15
net i-tool-09-is-down hm2_7i92.0.7i70.1.0.input-16
net i-tool-09-is-up hm2_7i92.0.7i70.1.0.input-17
net i-tool-08-is-down hm2_7i92.0.7i70.1.0.input-18
net i-tool-08-is-up hm2_7i92.0.7i70.1.0.input-19
net i-tool-07-is-down hm2_7i92.0.7i70.1.0.input-20
net i-tool-07-is-up hm2_7i92.0.7i70.1.0.input-21
net i-tool-06-is-down hm2_7i92.0.7i70.1.0.input-22
net i-tool-06-is-up hm2_7i92.0.7i70.1.0.input-23
net i-door-1-open hm2_7i92.0.7i70.1.0.input-24
net i-steuerung-ein hm2_7i92.0.7i70.1.0.input-25
net i-power-io hm2_7i92.0.7i70.1.0.input-26
net i-tool-04-is-down hm2_7i92.0.7i70.1.0.input-27
net i-tool-basket-is-down hm2_7i92.0.7i70.1.0.input-30
net i-tool-basket-is-up hm2_7i92.0.7i70.1.0.input-31
net i-door-1-closed hm2_7i92.0.7i70.1.0.input-32
net i-door-2-open hm2_7i92.0.7i70.1.0.input-33
net i-door-2-closed hm2_7i92.0.7i70.1.0.input-34
net i-door-3 hm2_7i92.0.7i70.1.0.input-35
net i-table-is-lock hm2_7i92.0.7i70.1.0.input-36
net i-table-is-up hm2_7i92.0.7i70.1.0.input-37
net i-table-is-1 hm2_7i92.0.7i70.1.0.input-38
net i-table-is-2 hm2_7i92.0.7i70.1.0.input-39
# --- HOME-Z ---
net home-x hm2_7i92.0.7i70.1.0.input-40
net home-y hm2_7i92.0.7i70.1.0.input-29
net home-z hm2_7i92.0.7i70.1.0.input-28
# --- A Axis ---- NOT CONNECTED ----
net home-a hm2_7i92.0.7i70.1.0.input-41
net i-setup-a hm2_7i92.0.7i70.1.0.input-42
#---- NOT CONNECTED ----
net i-dummy43 hm2_7i92.0.7i70.1.0.input-43
net i-dummy44 hm2_7i92.0.7i70.1.0.input-44
net i-dummy45 hm2_7i92.0.7i70.1.0.input-45
net i-dummy46 hm2_7i92.0.7i70.1.0.input-46
net i-dummy47 hm2_7i92.0.7i70.1.0.input-47
#7i77
net i-brake-z-is-on hm2_7i92.0.7i77.0.0.input-00
net i-machine-ready hm2_7i92.0.7i77.0.0.input-01
# --- MAX-X ---
net max-x <= hm2_7i92.0.7i77.0.0.input-02
net max-x-n <= hm2_7i92.0.7i77.0.0.input-02-not
# --- MAX-Y ---
net max-y <= hm2_7i92.0.7i77.0.0.input-03
net max-y-n <= hm2_7i92.0.7i77.0.0.input-03-not
# --- MAX-Z ---
net max-z <= hm2_7i92.0.7i77.0.0.input-04
net max-z-n-1 <= hm2_7i92.0.7i77.0.0.input-04-not
# --- E-Stop input---
net estop-button hm2_7i92.0.7i77.0.0.input-06-not
net i-pressure-ok hm2_7i92.0.7i77.0.0.input-05-not
net i-temp-bimetall hm2_7i92.0.7i77.0.0.input-07-not
net i-temp hm2_7i92.0.7i77.0.0.input-08-not
# --- E-STOP CHAIN STARTS ---
net latch-ok-in iocontrol.0.user-enable-out
net latch-ok-in => estop-latch.0.ok-in
net latch0-out <= estop-latch.0.ok-out
net latch0-out => estop-latch.1.ok-in
net latch1-out <= estop-latch.1.ok-out
net latch1-out => estop-latch.2.ok-in
net reset => estop-latch.0.reset
net reset => estop-latch.1.reset
net reset => estop-latch.2.reset
net latch-out iocontrol.0.emc-enable-in <= estop-latch.2.ok-out
net estop-out estop-latch.2.fault-out
# --- EXTERNAL ESTOP SWITCH ---
net estop-button => estop-latch.0.fault-in
# --- Airpressure low E-Stop ---
net i-pressure-ok => estop-latch.1.fault-in
# --- Overheating E-STOP ---
net i-temp-bimetall => estop-latch.2.fault-in
# --- ESTOP CHAIN ENDS ---
#Ladder
# --- MACHINE-IS-ENABLED ---
net machine-is-enabled classicladder.0.in-00
net i-steuerung-ein classicladder.0.in-01
# --- ladder-out
net o-impulsfreigabe <= classicladder.0.out-02
net o-steuerung-1 <= classicladder.0.out-01
net o-power-drives <= classicladder.0.out-04
net o-power-drives-delay <= classicladder.0.out-05
net o-brake-z <= classicladder.0.out-06
net i-unknown1 hm2_7i92.0.7i77.0.0.input-09
net i-unkown2 hm2_7i92.0.7i77.0.0.input-10
net i-servo hm2_7i92.0.7i77.0.0.input-11
net i-spindle hm2_7i92.0.7i77.0.0.input-12
net i-2dummy13 hm2_7i92.0.7i77.0.0.input-13
net i-2dummy14 hm2_7i92.0.7i77.0.0.input-14
net i-2dummy15 hm2_7i92.0.7i77.0.0.input-15
#********************
#Iputs in Ganty START
#********************
net i-toolsensor-1 hm2_7i92.0.7i77.0.0.input-16
net i-toolsensor-2 hm2_7i92.0.7i77.0.0.input-17
net max-z-n-2 hm2_7i92.0.7i77.0.0.input-17-not
net i-toolsensor hm2_7i92.0.7i77.0.0.input-16-not
net i-toolsensor motion.probe-input
net i-2dummy18 hm2_7i92.0.7i77.0.0.input-18
net i-2dummy19 hm2_7i92.0.7i77.0.0.input-19
net i-2dummy20 hm2_7i92.0.7i77.0.0.input-20
net i-2dummy21 hm2_7i92.0.7i77.0.0.input-21
net i-2dummy22 hm2_7i92.0.7i77.0.0.input-22
net i-ganty-powergood hm2_7i92.0.7i77.0.0.input-23
#********************
#Iputs in Ganty END
#********************
net i-2dummy24 hm2_7i92.0.7i77.0.0.input-24
net i-2dummy25 hm2_7i92.0.7i77.0.0.input-25
net i-2dummy26 hm2_7i92.0.7i77.0.0.input-26
net i-2dummy27 hm2_7i92.0.7i77.0.0.input-27
net i-2dummy28 hm2_7i92.0.7i77.0.0.input-28
net i-2dummy29 hm2_7i92.0.7i77.0.0.input-29
net i-2dummy30 hm2_7i92.0.7i77.0.0.input-30
net i-2dummy31 hm2_7i92.0.7i77.0.0.input-31
#********************
#Z-Limit logic
#********************
net max-y-n-1 or2.0.in0
net max-z-n-2 or2.0.in1
net max-z-n or2.0.out
#*******************
# JOINT X
#*******************
setp pid.x.Pgain [JOINT_0]P
setp pid.x.Igain [JOINT_0]I
setp pid.x.Dgain [JOINT_0]D
setp pid.x.bias [JOINT_0]BIAS
setp pid.x.FF0 [JOINT_0]FF0
setp pid.x.FF1 [JOINT_0]FF1
setp pid.x.FF2 [JOINT_0]FF2
setp pid.x.deadband [JOINT_0]DEADBAND
setp pid.x.maxoutput [JOINT_0]MAX_OUTPUT
setp pid.x.error-previous-target true
net x-index-enable <=> pid.x.index-enable
net x-enable => pid.x.enable
net x-pos-cmd => pid.x.command
#net x-vel-cmd => pid.x.command-deriv
net x-pos-fb => pid.x.feedback
net x-output => pid.x.output
# ---PWM Generator signals/setup---
setp hm2_7i92.0.7i77.0.1.analogout0-scalemax [JOINT_0]OUTPUT_SCALE
setp hm2_7i92.0.7i77.0.1.analogout0-minlim [JOINT_0]OUTPUT_MIN_LIMIT
setp hm2_7i92.0.7i77.0.1.analogout0-maxlim [JOINT_0]OUTPUT_MAX_LIMIT
net x-output => hm2_7i92.0.7i77.0.1.analogout0
net x-pos-cmd joint.0.motor-pos-cmd
net x-enable joint.0.amp-enable-out
# enable _all_ sserial pwmgens
net x-enable hm2_7i92.0.7i77.0.1.analogena
# ---Encoder feedback signals/setup---
setp hm2_7i92.0.encoder.00.counter-mode 0
setp hm2_7i92.0.encoder.00.filter 1
setp hm2_7i92.0.encoder.00.index-invert 0
setp hm2_7i92.0.encoder.00.index-mask 0
setp hm2_7i92.0.encoder.00.index-mask-invert 0
setp hm2_7i92.0.encoder.00.scale [JOINT_0]ENCODER_SCALE
net x-pos-fb <= hm2_7i92.0.encoder.00.position
net x-vel-fb <= hm2_7i92.0.encoder.00.velocity
net x-pos-fb => joint.0.motor-pos-fb
net x-index-enable joint.0.index-enable <=> hm2_7i92.0.encoder.00.index-enable
net x-pos-rawcounts <= hm2_7i92.0.encoder.00.rawcounts
# ---setup home / limit switch signals---
net home-x => joint.0.home-sw-in
net max-x-n => joint.0.neg-lim-sw-in
net max-x-n => joint.0.pos-lim-sw-in
#*******************
# JOINT Y
#*******************
setp pid.y.Pgain [JOINT_1]P
setp pid.y.Igain [JOINT_1]I
setp pid.y.Dgain [JOINT_1]D
setp pid.y.bias [JOINT_1]BIAS
setp pid.y.FF0 [JOINT_1]FF0
setp pid.y.FF1 [JOINT_1]FF1
setp pid.y.FF2 [JOINT_1]FF2
setp pid.y.deadband [JOINT_1]DEADBAND
setp pid.y.maxoutput [JOINT_1]MAX_OUTPUT
setp pid.y.error-previous-target true
net y-index-enable <=> pid.y.index-enable
net y-enable => pid.y.enable
net y-pos-cmd => pid.y.command
#net y-vel-cmd => pid.y.command-deriv
net y-pos-fb => pid.y.feedback
net y-output => pid.y.output
# ---PWM Generator signals/setup---
setp hm2_7i92.0.7i77.0.1.analogout1-scalemax [JOINT_1]OUTPUT_SCALE
setp hm2_7i92.0.7i77.0.1.analogout1-minlim [JOINT_1]OUTPUT_MIN_LIMIT
setp hm2_7i92.0.7i77.0.1.analogout1-maxlim [JOINT_1]OUTPUT_MAX_LIMIT
net y-output => hm2_7i92.0.7i77.0.1.analogout1
net y-pos-cmd joint.1.motor-pos-cmd
net y-enable joint.1.amp-enable-out
# ---Encoder feedback signals/setup---
setp hm2_7i92.0.encoder.01.counter-mode 0
setp hm2_7i92.0.encoder.01.filter 1
setp hm2_7i92.0.encoder.01.index-invert 0
setp hm2_7i92.0.encoder.01.index-mask 0
setp hm2_7i92.0.encoder.01.index-mask-invert 0
setp hm2_7i92.0.encoder.01.scale [JOINT_1]ENCODER_SCALE
net y-pos-fb <= hm2_7i92.0.encoder.01.position
net y-vel-fb <= hm2_7i92.0.encoder.01.velocity
net y-pos-fb => joint.1.motor-pos-fb
net y-index-enable joint.1.index-enable <=> hm2_7i92.0.encoder.01.index-enable
net y-pos-rawcounts <= hm2_7i92.0.encoder.01.rawcounts
# ---setup home / limit switch signals---
net home-y => joint.1.home-sw-in
net max-y-n => joint.1.neg-lim-sw-in
net max-y-n => joint.1.pos-lim-sw-in
#*******************
# JOINT Z
#*******************
setp pid.z.Pgain [JOINT_2]P
setp pid.z.Igain [JOINT_2]I
setp pid.z.Dgain [JOINT_2]D
setp pid.z.bias [JOINT_2]BIAS
setp pid.z.FF0 [JOINT_2]FF0
setp pid.z.FF1 [JOINT_2]FF1
setp pid.z.FF2 [JOINT_2]FF2
setp pid.z.deadband [JOINT_2]DEADBAND
setp pid.z.maxoutput [JOINT_2]MAX_OUTPUT
setp pid.z.error-previous-target true
net z-index-enable <=> pid.z.index-enable
net z-enable => pid.z.enable
net z-pos-cmd => pid.z.command
#net z-vel-cmd => pid.z.command-deriv
net z-pos-fb => pid.z.feedback
net z-output => pid.z.output
# ---PWM Generator signals/setup---
setp hm2_7i92.0.7i77.0.1.analogout2-scalemax [JOINT_2]OUTPUT_SCALE
setp hm2_7i92.0.7i77.0.1.analogout2-minlim [JOINT_2]OUTPUT_MIN_LIMIT
setp hm2_7i92.0.7i77.0.1.analogout2-maxlim [JOINT_2]OUTPUT_MAX_LIMIT
net z-output => hm2_7i92.0.7i77.0.1.analogout2
net z-pos-cmd joint.2.motor-pos-cmd
net z-enable joint.2.amp-enable-out
# ---Encoder feedback signals/setup---
setp hm2_7i92.0.encoder.02.counter-mode 0
setp hm2_7i92.0.encoder.02.filter 1
setp hm2_7i92.0.encoder.02.index-invert 0
setp hm2_7i92.0.encoder.02.index-mask 0
setp hm2_7i92.0.encoder.02.index-mask-invert 0
setp hm2_7i92.0.encoder.02.scale [JOINT_2]ENCODER_SCALE
net z-pos-fb <= hm2_7i92.0.encoder.02.position
net z-vel-fb <= hm2_7i92.0.encoder.02.velocity
net z-pos-fb => joint.2.motor-pos-fb
net z-index-enable joint.2.index-enable <=> hm2_7i92.0.encoder.02.index-enable
net z-pos-rawcounts <= hm2_7i92.0.encoder.02.rawcounts
# ---setup home / limit switch signals---
net home-z => joint.2.home-sw-in
net max-z-n => joint.2.neg-lim-sw-in
net max-z-n => joint.2.pos-lim-sw-in
#*******************
# SPINDLE S
#*******************
setp pid.s.Pgain [SPINDLE_9]P
setp pid.s.Igain [SPINDLE_9]I
setp pid.s.Dgain [SPINDLE_9]D
setp pid.s.bias [SPINDLE_9]BIAS
setp pid.s.FF0 [SPINDLE_9]FF0
setp pid.s.FF1 [SPINDLE_9]FF1
setp pid.s.FF2 [SPINDLE_9]FF2
setp pid.s.deadband [SPINDLE_9]DEADBAND
setp pid.s.maxoutput [SPINDLE_9]MAX_OUTPUT
setp pid.s.error-previous-target true
net spindle-index-enable <=> pid.s.index-enable
net spindle-enable => pid.s.enable
#net spindle-vel-cmd-rpm => pid.s.command
# the output of spindle ramp is sent to the scale in
net spindle-ramped <= spindle-ramp.out => => pid.s.command
net spindle-vel-fb-rpm => pid.s.feedback
net spindle-output <= pid.s.output
# ---PWM Generator signals/setup---
setp hm2_7i92.0.7i77.0.1.analogout4-scalemax [SPINDLE_9]OUTPUT_SCALE
setp hm2_7i92.0.7i77.0.1.analogout4-minlim [SPINDLE_9]OUTPUT_MIN_LIMIT
setp hm2_7i92.0.7i77.0.1.analogout4-maxlim [SPINDLE_9]OUTPUT_MAX_LIMIT
net spindle-output => hm2_7i92.0.7i77.0.1.analogout4
# ---Encoder feedback signals/setup---
setp hm2_7i92.0.encoder.05.counter-mode 0
setp hm2_7i92.0.encoder.05.filter 1
setp hm2_7i92.0.encoder.05.index-invert 0
setp hm2_7i92.0.encoder.05.index-mask 0
setp hm2_7i92.0.encoder.05.index-mask-invert 0
setp hm2_7i92.0.encoder.05.scale [SPINDLE_9]ENCODER_SCALE
net spindle-revs <= hm2_7i92.0.encoder.05.position
net spindle-vel-fb-rps <= hm2_7i92.0.encoder.05.velocity
net spindle-index-enable <=> hm2_7i92.0.encoder.05.index-enable
# ---setup spindle control signals---
net spindle-vel-cmd-rps <= spindle.0.speed-out-rps
net spindle-vel-cmd-rps-abs <= spindle.0.speed-out-rps-abs
net spindle-vel-cmd-rpm <= spindle.0.speed-out
net spindle-vel-cmd-rpm-abs <= spindle.0.speed-out-abs
net spindle-enable <= spindle.0.on
net spindle-cw <= spindle.0.forward
net spindle-ccw <= spindle.0.reverse
net spindle-brake <= spindle.0.brake
net spindle-revs => spindle.0.revs
#net spindle-at-speed => spindle.0.at-speed
net spindle-vel-fb-rps => spindle.0.speed-in
net spindle-index-enable <=> spindle.0.index-enable
# hijack the spindle speed out and send it to spindle ramp in
net spindle-vel-cmd-rpm => spindle-ramp.in
# to know when to start the motion we send the near component
# (named spindle-at-speed) to the spindle commanded speed from
# the signal spindle-cmd and the actual spindle speed
# provided your spindle can accelerate at the maxv setting.
net spindle-vel-cmd-rpm => spindle-atspeed.in1
net spindle-ramped => spindle-atspeed.in2
#net spindle-vel-fb-rpm => spindle-atspeed.in2
# ---Setup spindle at speed signals---
# the output from spindle-at-speed is sent to motion.spindle-at-speed
# and when this is true motion will start
net spindle-at-speed <= spindle-atspeed.out => spindle.0.at-speed
#sets spindle-at-speed true
#******************************
# connect miscellaneous signals
#******************************
# ---HALUI signals---
net axis-select-x halui.axis.x.select
net jog-x-pos halui.axis.x.plus
net jog-x-neg halui.axis.x.minus
net jog-x-analog halui.axis.x.analog
net x-is-homed halui.joint.0.is-homed
net axis-select-y halui.axis.y.select
net jog-y-pos halui.axis.y.plus
net jog-y-neg halui.axis.y.minus
net jog-y-analog halui.axis.y.analog
net y-is-homed halui.joint.1.is-homed
net axis-select-z halui.axis.z.select
net jog-z-pos halui.axis.z.plus
net jog-z-neg halui.axis.z.minus
net jog-z-analog halui.axis.z.analog
net z-is-homed halui.joint.2.is-homed
net jog-selected-pos halui.axis.selected.plus
net jog-selected-neg halui.axis.selected.minus
#aenderungen
net spindle-manual-cw halui.spindle.0.forward
net spindle-manual-ccw halui.spindle.0.reverse
net spindle-manual-stop halui.spindle.0.stop
#net machine-is-on halui.machine.is-on
#Probe
#net spindle-fwd spindle.0.forward
#net spindle-rev spindle.0.reverse
#net spindle-speed spindle.0.speed-out
net jog-speed halui.axis.jog-speed
net MDI-mode halui.mode.is-mdi
# ---coolant signals---
net coolant-mist <= iocontrol.0.coolant-mist
net coolant-flood <= iocontrol.0.coolant-flood
#probe
#net lube iocontrol.0.lube
#net flood iocontrol.0.coolant-flood
#net mist iocontrol.0.coolant-mist
# ---motion control signals---
net in-position <= motion.in-position
net machine-is-enabled <= motion.motion-enabled
# ---tool change signals---
net tool-change-confirmed iocontrol.0.tool-changed <= iocontrol.0.tool-change
net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
Postgui Hal:
#E-stop
net reset <= qtpyvcp.hb1.out
net reset => qtpyvcp.led4.on
net estop-button => qtpyvcp.led1.on
net i-pressure-ok => qtpyvcp.led2.on
net i-temp-bimetall => qtpyvcp.led3.on
net latch-out => qtpyvcp.led5.on
Was noch Fehlt ist die Startsequenz der Servotreiber und der Spindel das habe ich über eine Ladder gelöst:
Damit ist alles umgesetzt, das benötigt wird die Maschine in Bewegung zu setzten. Es Fehlen noch diverse Programme zum Steuern der einzelnen Komponenten. Doch dazu kommen wir später.
Es gab hier diverse Ansätze und auch immer wieder Sackgassen oder Projekte, die ich angefangen und über Bord geworfen habe. Angefangen habe ich mit gmocappy als VCP bin inzwischen aber bei qtpyvcp bzw. Probe Basic angekommen, das auf qtpyvcp basiert.
Fangen wir an mit der Installation von linuxcnc. Hier die Version, die am schnellsten funktioniert hat:
Passende Iso aus suchen, runter laden und auf einen USB Stick flashen. Nach der Installation geht es dann weiter. Ich habe linuxcnc auf version 2.8 gehoben:
Damit müsste eigentlich alles installiert sein, was benötigt wird um Linuxcnc mit Probe Basic ans laufen zu bekommen und noch etwas mehr. Was folgt ist die Installation von qtpyvcp und ein Neustart
git clone https://github.com/kcjengr/qtpyvcp qtpyvcp
cd qtpyvcp
pip install --editable .
cd ~/qtpyvcp/pyqt5designer/Qt5.7.1-64bit/
sudo ./install.sh
cp ~/qtpyvcp/scripts/.xsessionrc ~/
sudo reboot
Damit sind die ersten Installationen abgeschlossen. Wir haben ein Linux mit Echtzeit-Kernel und Linuxcnc. Den ganzen Latenzkram hatte ich schon lit nem live system getestet und das ist eigentlich recht gut beschreiben, daher machen wir mit den Mesa Karten weiter. Meine Mesakarte wird per Ethernet angesprochen also musste zunächst eine Netzwerk Karte dafür reserviert werden. Ich verwende die Standard-IP der 7i92 (192.168.1.121) die Netzwerkschnittstelle wurde manuell konfiguriert und auf RT umbenannt, IPv4 manual, 192.168.1.100 mit netmask 255.255.255.2 und gateway 192.168.1.100 eingestellt. IPv6 wird auf ignore gestellt. Wenn alle Kabel und Jumper überprüft sind, kann man die Stromversorgung einschalten. Danach sollte sich Lunux schon mal melden, dass RT verbunden wurde.
ping 192.168.1.121 PING 192.168.1.121 (192.168.1.121) 56(84) bytes of data. 64 bytes from 192.168.1.121: icmp_seq=1 ttl=64 time=0.577 ms 64 bytes from 192.168.1.121: icmp_seq=2 ttl=64 time=0.338 ms 64 bytes from 192.168.1.121: icmp_seq=3 ttl=64 time=0.313 ms 64 bytes from 192.168.1.121: icmp_seq=4 ttl=64 time=0.361 ms
Damit ist die erste Kontaktaufnahme geglückt. Jetzt muss die Mesa 7I92 noch geflashed werden. Die passenden Software gibt es von Mesa:
Das ganze auspacken und dann die passende Firmware raus suchen in meinem Fall mit der Default IP und 7i77 und 7i72 Bords die Firmware 7i92_7i77_7i74D.bit
Nachdem das grundlegende Konzept fest steht geht es an die Umsetzung. Dazu werden zunächst die I/O’s und Encoder um zu legen. Dazu wurden zunächst Schnittstellen und neue Zuordnungen lokalisiert und in Tabellen eingetragen.
Damit waren die Vorbereitungen der Hardware außerhalb der Maschine abgeschlossen. Die nächsten Schritte waren das ziehen von Netzwerkkabeln um die Seriellen Schnittstellen im Schaltschrank mit der Konsole zu verbinden und um ggf. einen Netzwerkanschluss für den Steuerrechner bereit stellen zu können. Außerdem bekam die Konsole eine eigne 220V Stromkreis für den Steuerrechner, Monitor, 5V Netzteil und Servicesteckdose.
Kabel durch die Maschine verlegen
IO Karten und Adapter sind in der Seitenwand des Schaltschrankes verbaut
Karten und Adapter wurden in die Seitenwand der Konsole untergebracht
Netzteile und Schalter sind verdrahtet
Danach war es an der Zeit die vorläufige Frontplatte zu machen und den Steuerrechner ein zu bauen. Außerdem wurden ein Notaus-Knopf und ein Schalter für die 5V Stromversorgung der FPGA Karten eingebaut.
Damit waren die Vorbereitungen der Hardware abgeschlossen. Als nächstes kommt dann die Software.
Ok ganz so linear war es nicht zwischen beginn des Umbaus und dem Abschluss des Umbaus lag immerhin ein Umzug und auch zwischendurch wurde an der Software gearbeitet aber so lässt es sich besser aufteilen. Aber Überraschenderweise lieft der Umbau der Hardware deutlich glatter als gedacht, die akribische Vorarbeit und Dokumentation haben dazu geführt, dass bis auf Kleinigkeiten, die den undokumentierten umbauten der Maschine Geschuldet waren alles rech schnell lief. Auch die Videos der Relais während des Einschaltprozesses haben sich später bei der Umsetzung der Software bewährt. Doch dazu mehr in Teil 3
Es war ja sehr lange still hier im Blog. Der Grund dafür liegt in der Tatsache, das ich umgezogen bin und damit viel Zeit für die Renovierung der Neuen Heimat drauf geht. Der 2. während der Zeit habe ich auch meiner Chiron FZ12W eine neue Steuerung verpasst habe. Die alte Sinumerik 810M durfte gehen und als “neues Hirn” für Igor kamen Mesa Karten und ein kleiner PC mit Linuxcnc als Betriebssystem.
Das ganze vorhaben ist dem Wunsch nach mehr Speicher geschuldet. Anfangs war das Projekt so geplant es möglichst minimal zu machen um, falls es nicht klappt schnell wieder zurück bauen zu können. Das habe ich aber dann Teilweise über Bord geworfen. Doch kommen wir zunächst zur Planung. Ich hatte zum Glück die Schaltpläne der Chiron, leider gab es ein paar undokumentierte Umbauten. Aber das ließ sich alles “durchklingeln”. Die Ein- und Ausgänge lagen entweder aus Wannensteckern oder auf D-Sub Steckern. Was den Umbau erleichtert, wenn man auf Adapterplatinen setzt. Das ist zwar hinten im Schaltschrank redundant, da hier die Kabel über einen Adapter auf ein Flachbandkabel gelegt werden und dann von dem Flachbandkabel wieder auf einen Adapter, dann auf Kabel und dann in die Klemmleisten der Mesa Karten. Aber so ließe sich dann alles schnell wieder zurück bauen. Und man muss nicht alle Kabel mühsam umlegen. Aber bevor es los ging heiß es erst mal alle Ein- und Ausgänge, Dokumentieren. Um eine passende Auswahl an Karten zu machen. Meine Wahl fiel dann auf folgendes Setup: Zunächst die Karten, die in die alte Steuerkonsole eingebaut werden: 1. Mesa 7I92H Anything I/O Ethernet card. Dadurch wurde ich in der Wahl des Mainbords flexibler und es lässt sich leichter auf einen anderen Rechner wechseln. Diese FPGA Karte übernimmt nur die Kommunikation zwischen Rechner und den IO’s. 2. Mesa 7I77 Analog servo interface plus I/O daughtercard. Diese Karte verarbeitet die Encoder und übernimmt die Analoge Steuerung der Servotreiber und Spineln. Außerdem hat sie Digitale I/O’s mit der sich die I/O’s schalten lassen, die schon in der Konsole liegen. 3. Mesa 7I74 Eight Channel RS-422/485 interface/ RJ45 Breakout. Mit der Karte kann ich weitere Serielle Karten ansteuern, die hinten in den Schaltschrank kommen. Damit kommen wir zu den Karten im Schaltschrank: 4. Mesa 7I71 Isolated remote power driver card. Mit der Karte werden alle digitalen Ausgänge geschaltet. 5. Mesa 7I70 Isolated remote digital input card. Mit der Karte werden die Eingänge überwacht. so weit so gut. Zu dem Rechner habe ich noch einen touchfähigen Monitor spendiert, dadurch stört es auch nicht weiter, dass ich mit der Sinumerik auch alle Bedienelemente ausgebaut habe. Damit sind die Eckdaten schon mal fest gelegt. Im Nächten Teil beginnt dann die Umsetzung.
Doch zunächst brauchte ich noch Aufnahmen für meinen Messerkopf und die Scheibenfräser…
Die SK Aufnahmen, die ich dafür angeschafft hatte waren leider zu lang und mussten ein wenig gekürt werden. Also ab in die Drehbank damit und nen bisschen Hartdrehen, eingesaut war die Drehe so wie so schon…