Fusion 360 (osVAC neo): python code für automatische parameteränderung und stl-Export

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Eigentlich einen Fall für die Frust-Ecke:
Ich freu mich wie Bolle, dass mein python-code für F360 funktiontiert und autodesk sperrt den Beitrag als spam:

Screenshot 2025-01-25 114818.png

Rest kommt, es gibt essen.
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Ich fange hier mal mit der Anwendung an, es hat ja natürlich was mit osVAC neo zu tun:

Da es verschiedene Durchmesser für male und female gibt, braucht man auch Übergänge/Reduzierstücke:
Screenshot 2025-01-25 123157.png

Davon braucht man aber einige verschiedene Varianten. Die alle von Hand zu erzeugen ist nervig. Das geht jetzt automatisiert:
1737805018798.png
 

mabermue

ww-ahorn
Registriert
15. August 2016
Beiträge
127
Ort
Mühldorf
Das interessiert mich sehr. Hatte mir schon vorgenommen, sowas zu schreiben, aber bisher reicht leider die Zeit nicht aus, um mich da reinzufuchsen.
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Hier mein gesperrter Beitrag:

I do an open-source-project called osVAC neo. For details see osvacneo.de


It is similiar to plumbing:

you have a few basic parts, like bows and T-connectors, but you need them in lots of different sizes and combinations thereof.
So, I did the designs in f360 and to get the different sizes I change parameters.

To generate the stl-files I have to:
1) change the desired parameters
2) exports part(s) als stl (and step-files)
3) repeat the above for all desired combinations of parameters


Now, I have a first decent prototype up and running. I would like to share the code and would appreciate comments. I will also attach my f360-test-design.


Brief description, how to use:

There ist a section in the code, where you place your user parameters und values:
Code:
        ###################################################################################
        # change to your personal data here
        inputData1 = (
            ("height", (10, 20)),
            ("width", (30, 40)),
            ("length", (50,60))
        )
        inputData2 = (
            ("MaleDiameterInner", (25, 32, 36, 40, 50)),
            ("FemaleDiameterInner", (25, 32, 36, 40, 50))
        )
        inputData = inputData1
        destFolder = "D:\\tmp\\F360"
        # end of personal data
        ###################################################################################
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
The program will iterate and build every possible permutation of the give values (for inputData1 there are 8 permutations, for inputData2 there are 25) and generate a properly named stil-file:
1737805271537.png

1737805292412.png
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Und noch den python-Code:

Code:
#Author-
#Description-

import adsk.core, adsk.fusion, adsk.cam, os, traceback


###########################################################################################
def get_immediate_children(component):
    # Get the child occurrences (components) directly under the specified component
    child_occurrences = component.occurrences

    # Extract the actual component objects from the occurrences
    child_components = [occ.component for occ in child_occurrences if occ.isVisible]

    return child_components


###########################################################################################
def _generateIteratedDataSet( inputDataSets, oneDataLine, iteratedData ):
    index = len(oneDataLine)

    if( index < len(inputDataSets) ):
        inputDataSet = inputDataSets[index][1]

        for data in inputDataSet:
            oneDataLine.append( data )
            _generateIteratedDataSet( inputDataSets, oneDataLine, iteratedData )
            oneDataLine.pop(index)
    else:
        tmp = oneDataLine.copy()
        iteratedData.append(tmp)


###########################################################################################
def generateIteratedDataSet( inputDataSets ):
    names = []

    for inputDataSet in inputDataSets:
        names.append( inputDataSet[0] )

    interatedData=[]
    _generateIteratedDataSet( inputDataSets, [], interatedData)
    
    return( (names, interatedData) )


###########################################################################################
def verifyUserParameters(app, design, names):
    ui = app.userInterface
    userParameters = design.userParameters

    for name in names:
        userParameter = userParameters.itemByName(name)

        if userParameter:
            dummy = 1
        else:
            ui.messageBox('User-Parameter "{}" nicht gefunden.'.format(parameterName), 'Fehler')
            return


###########################################################################################
def setUserParameters(app, design, names, data):
    ui = app.userInterface
    userParameters = design.userParameters

    length = len(names)

    for index in range(0, length, 1):
        name = names[index]
        val = data[index]
        userParameter = userParameters.itemByName(name)
        userParameter.expression = str(val)
 
    # update parametric text plugin
    app.fireCustomEvent('thomasa88_ParametricText_Ext_Update')           
    adsk.doEvents()
    adsk.doEvents()
    dummy = 1


###########################################################################################
def generateFileName( componentName, names, data ):
    length = len(names)
    text = ""

    for index in range(0, length, 1):
        name = names[index]
        val = data[index]

        if( len(text) != 0 ):
            text = text + "-"

        text = text + name + "=" + str(val)

    text = componentName + "-" + text
    
    dummy = 1
    return( text )


###########################################################################################
def exportStl( exportMgr, component, destFolder, fnBody ):
    fn = os.path.join( destFolder, fnBody + '.stl')
    
    stlOptions = exportMgr.createSTLExportOptions(component, fn)
    stlOptions.sendToPrintUtility = False # Setze auf True, wenn du die Exportdatei direkt drucken möchtest

    # Körper als STL exportieren
    exportMgr.execute(stlOptions)


###########################################################################################
def run(context):
    ui = None
    try:
        # Zugriff auf Fusion 360 UI
        app = adsk.core.Application.get()
        ui = app.userInterface

        # Dokument und Design erhalten
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)

        if not design:
            ui.messageBox('Kein aktives Fusion 360 Design.', 'Fehler')
            return
        
        # Get the root component
        root_component = design.rootComponent
        
        # Get the immediate child components under the root component
        immediate_children = get_immediate_children(root_component)

        ###################################################################################
        # change to your personal data here
        inputData1 = (
            ("height", (10, 20)),
            ("width", (30, 40)),
            ("length", (50,60))
        )
        inputData2 = (
            ("MaleDiameterInner", (25, 32, 36, 40, 50)),
            ("FemaleDiameterInner", (25, 32, 36, 40, 50))
        )
        inputData = inputData1
        destFolder = "D:\\tmp\\F360"
        # end of personal data
        ###################################################################################


        iteratedDataSet = generateIteratedDataSet( inputData )
        names = iteratedDataSet[0]
        iteratedData = iteratedDataSet[1]

        verifyUserParameters( app, design, names )

        for data in iteratedData:
            setUserParameters( app, design, names, data )

            exportMgr = design.exportManager

            for component in immediate_children:
                fnBody = generateFileName( component.name, names, data )
                exportStl( exportMgr, component, destFolder, fnBody )
                dummy = 0

        dummy=1
        return

        # dead old code below
        # User-Parameter ändern
        parameterName = 'HoseDiameterInner'  # Name des zu ändernden Parameters
        parameterObj = ui.inputBox("Bitte geben Sie den Namen des Parameters ein:", "Parameter Name", "HoseDiameterInner")
        parameterName = parameterObj[0]

        # Überprüfen, ob der Benutzer einen Namen eingegeben hat
        if not parameterName:
            ui.messageBox("Es wurde kein Parametername eingegeben.")
            return

        for parameterValue in [25, 32, 36]:
            set_parameter(app, design, parameterName, parameterValue)
            
            # Export
            exportMgr = design.exportManager       
            for component in immediate_children:
                export_stl(exportMgr, component, parameterValue)

        ui.messageBox('Export erfolgreich abgeschlossen.')

    except:
        if ui:
            ui.messageBox('Fehler aufgetreten:\n{}'.format(traceback.format_exc()))
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Noch ein Beispiel für eine Anwendung:

Ich habe gerade so eine Bohrerschablone/lehre gemacht:
1737808050899.png

Jetzt müssen die Löcher ein bischen größer sein als der Bohrer - aber auch nicht zuviel. Die Löcher habe ich mit einem parametrierten Zuschlag versehen. Jetzt kann mal eine Handvoll stl-Dateien mit leicht variierenden Lochgrößen erzeugen, damit man die passende für seinen Bohrer hat.
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Übrigens:
Die Bohrschablonen passen auch in dieses Raster und liegen so schon in der Schublade (Bild folgt).
 

Dale_B_Cooper

ww-robinie
Registriert
17. November 2020
Beiträge
902
Ort
HH
Lustig, dass gerade Autodesk Spam im Forum markiert, vermutlich deutsche IP, das ist so ähnlich wie Russland oder China, das ist bestimmt Spam. :emoji_slight_smile:
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
So, erster praktischer Einsatz des Skripts:

https://www.thingiverse.com/thing:6928006
1738008485770.png

Natürlich hat das wieder was mit osVAC neo zu tun. Da es da verschiedenen Durchmesser gibt, braucht man gelegentlich Reduzierstücker. Jetzt habe ich mit dem Script auf einen Schlag 50 Varianten erzeugt und alle auf thingiverse hochgeladen. Das würde man händisch nie in dem Umfang machen. Ist etwas oversized. Aber da ist dann hoffentlich alles erschlagen.
 

mabermue

ww-ahorn
Registriert
15. August 2016
Beiträge
127
Ort
Mühldorf
Hallo,
zuerst mal ein großes Danke an @odul für das Bereitstellen seines Python-Scripts zum Parameterändern in Fusion360.

Ich hatte schon versucht, selber so etwas hinzubekommen, aber als absoluter Python-Anfänger habe ich da
nicht wirklich etwas Sinnvolles zustande gebracht.

Mit seiner Vorarbeit ging es dann viel leichter, auch wenn ich noch über einige Hürden gestolpert bin.
Als ich dann kapiert hatte, dass das Script (mindestens) eine Komponente voraussetzt, habe ich meine Konstruktion angepasst und schon lief es (fast).

Das Prägen von Text (per Parametric Tex) funktionierte nur teilweise, bei manchen generierten Dateien zuerst schon, bei folgenden dann nicht mehr.
Schließlich kam ich drauf, dass ich von Parametric Text die Version 2.2 hatte, mittlerweile ist aber V2.4 aktuell. Mit der aktuellen klappt es reibungslos.

Dass Fusion eine Diva ist, ist uns ja allen klar. Bei dem beigefügten Teststück hatte ich zuerst die TextBox in der Skizze anhand der Flächengrenzen kollinear ausgerichtet. Das hat Fusion dann immer wieder vergessen, so dass der Text nicht mittig landete - in dem einfachen beigefügten Beispiel habe ich dann die Textbox mit den Parametern definiert. Naja.

Und schließlich habe ich das Ausgabeformt von stl auf 3mf geändert, was für mehrteilige Konstrukte das bessere Format ist.

Das leicht geänderte Python-Script ist mit in das Zipfile gepackt.

Wen es interessiert, der kann ja das geänderte Script mit seinen Sachen mal testen.

Mit hat das jedenfalls sehr geholfen und ich werde, wenn ich demnächst wieder etwas auf meiner printables - Seite veröffentliche, mit Sicherheit mehr generierte Dateien anfügen.

mit vielen Holzwerker- und 3D-Drucker- Grüßen
Martin
 

Anhänge

  • ParChngTest v9.zip
    390,4 KB · Aufrufe: 1

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Ah, das freut mich. Wobei die Kernroutinen der beste Freund meines Sohnes zusammen mit etwas KI erstellt hat. An dieser Stelle auch großes Danke an den euch unbekannten Sascha :emoji_slight_smile:

KI habe ich für meine Erweiteren auch versucht zu benutzen. Wobei leider jeder zweite Vorschlag kompletter Unfug war. Daher habe ich die KI erst mal wieder auf die Seite gelegt.

@mabermue : hatte nicht damit gerechnet, dass du dich so darauf stürzt. Da meine Beschreibung unvollständig war, bist du dann in die gleichen Fallen getappt wie ich. Das hätte ich dir gerne erspart.
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Dass Fusion eine Diva ist, ist uns ja allen klar. Bei dem beigefügten Teststück hatte ich zuerst die TextBox in der Skizze anhand der Flächengrenzen kollinear ausgerichtet. Das hat Fusion dann immer wieder vergessen, so dass der Text nicht mittig landete - in dem einfachen beigefügten Beispiel habe ich dann die Textbox mit den Parametern definiert. Naja.
Ich verstehe das so:
Du hast die Skizze mit dem Text auf die Fläche des Körpers gesetzt und an dessen Ecken festgemacht? Ändert man dann den Körper über die Parameter, verliert die Skizze oft ihre Bezugspunkte. Ab da läuft es dann immer in die Grütze. Was ich da schon geflucht habe.
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Das geänderte Skript habe ich mal überflogen und mich gefragt, was genau du geändert hast. Als Mitmachprojekt wäre das vielleicht hier eher ein Fall für GitHub. Aber trotz dessen, dass ich subversion sehr gut kenne, bin ich bisher nicht mit Git warm geworden.

Hinzu kommt, dass Fusion sich mit seiner Cloud-Affinität Dem Gedanken einer Versionierung widersetzt es sich damit bitterlich.
 

mabermue

ww-ahorn
Registriert
15. August 2016
Beiträge
127
Ort
Mühldorf
mich gefragt, was genau du geändert hast
Ich hatte einiges geändert und wieder verworfen, weil es zu wenig universell war.... Dann natürlich den Überblick über meine Änderungen verloren. (was ich eigentlich nicht zugeben wollte :emoji_wink:).
Dann wieder von Deiner Version ausgegangen, blieb eigentlich nur die Änderung des Ausgabeformats auf 3mf.
 

mabermue

ww-ahorn
Registriert
15. August 2016
Beiträge
127
Ort
Mühldorf
Heute war ja wieder mal ein Fusion - Update ...
Bis dahin hatte alles funktioniert, jetzt geht das Anpassen von parametric-text nur bei jedem 2. generierten Teil. :emoji_rage:

Nachdem ich die Abarbeitung der events statt 2fach nun 4fach aufrufe, klappt es wieder ... :emoji_relieved:
Screenshot 2025-01-28 122321.png

Versteh' einer die (Computer-) Welt. :emoji_thinking:
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Ich habe das gleiche Problem nach dem Update :emoji_frowning2:
Mit F360 ist es echt zum Mäuse melken. Mit 4mal "adsk.doEvents" habe ich es noch nicht probiert, wirkt aber auch nicht wie eine wasserdichte Lösung und performante Lösung auf mich.

Unter:
https://forums.autodesk.com/t5/fusi...-text-broken-after-update-today/td-p/13286719
https://forums.autodesk.com/t5/fusi...-text-broken-after-update-today/td-p/13286732
habe ich mal den Fehler gepostet. Die erste Antwort ist erfolgversprechend.... :emoji_frowning2:





Nebenbei:
Was neues habe ich mit dem Script nicht erfunden. Mit etwas suchen findet man das mehrfach. Z.B. hier:
https://www.reddit.com/r/Fusion360/comments/1c9qu0e/python_script_and_parametrictext_addon_not
 

odul

ww-robinie
Registriert
5. Juni 2017
Beiträge
9.227
Ort
AZ MZ WO WI F
Oben Unten