Neues aus der Bastelbude

Kategorie: Späne

Linuxcnc Retrofit von Igor Teil 9 – Fusion 360 Post processor

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:

NrTyp1.stelle2.Stelle3.Stelle4.Stelle
0Werkzeug in Spindel0000
001temporäre werkzeuge00TypTyp
01Probes01TypTyp
02Spindle02typtyp
03T-Slot0310er1er
04Scheibenfräser04druchmesser 10erDurchmesser 1er
05Prismenfräser05Winkel 10erWinkel 1er
1Drill11010,1
2Spotdrill2TypTypTyp
3Index31010,1
4Endmill41010,1
5Roughingendmill51010,1
6Bullnose6101Radius
7Ball endmill71010,1
8Formfräser8TypTypTyp

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;
}

Linuxcnc Retrofit von Igor Teil 8 Notaus und Komfort

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.

Bildschirmfoto 2020-08-22 um 10.45.38

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.

Bildschirmfoto 2020-08-22 um 11.28.59
#!/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


Ein Kardiertier….

Ich hatte Claudia schon vor längerer Zeit versprochen, ihr eine Karde zu bauen. Irgendwann war es dann so weit…

Wie so häufig habe ich angefangen, ohne Bilder zu machen.
Also machen wir das wie in einer Kochshow: Ich habe da mal was vorbereitet… die kleine Walze:

Aber ihr Werdegang war recht analog zur großen Walze.

Weiterlesen

Ein Wolf für Claudia

Dem geneigten Leser dieser Seite dürfte auffallen, das mein Gebiet die festen Werkstoffe sind, während Claudia eher zu den Faserwerkstoffen neigt. Doch manchmal Treffen sich unsere Welten…

In diesem Fall geht es um einen Wolf oder Wool Picker. Neben Geräten für den professionellen bzw. industriellen Einsatz gibt es für den Hobbyanwender mehr oder weniger zwei Bauweisen. Eine, nennen wir es mal Schwenk- oder Schaukelbauweise, die Recht leistungsfähig ist, da man hier Schwung und Masse des Wolfs optimal nutzten kann. Aber so ein Wolf benötigt auch mehr Platz. Die zweite Variante ist eine Kastenbauweise, diese erfordert etwas mehr Kraft, aber lässt sich relativ gut verstauen. Und da ich die meisten Flächen in unserer Hütte mit meinen Maschinen belegen will, wurde es ein Wolf in Kastenbauweise.

Kernstück eines jeden Wolfes sind Zinken, die gegenläufig stehen und zwischen denen die Wolle zerpflückt und aufgelockert wird. Dadurch lässt sie sich, von grobem Schmutz befreit, später besser weiter verarbeiten. In diesem Fall sollen die Zähne im 45° Winkel zur Bewegungsachse stehen und es kommen simple Nägel zum Einsatz. Damit das Holz nicht gesprengt wird, muss vorgebohrt werden, also habe ich mir für meine Bohrfräse eine einfache Auflage aus Holz gemacht.

Weiterlesen

© 2021 Ederen Barnworks

Theme von Anders NorénHoch ↑