Path Scripting documentation.

Here's the place for discussion related to CAM/CNC and the development of the Path module.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
spanner888
Posts: 327
Joined: Tue May 28, 2019 10:51 am

Re: Path Scripting documentation.

Post by spanner888 »

thanks, looking forward to it.
User avatar
onekk
Veteran
Posts: 6205
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Path Scripting documentation.

Post by onekk »

Sometimes Between 0.19 and 0.20 there where some change in Tool management and reference in the code so in the code above:

Code: Select all

tc0 = job.ToolController[0]
Should be changed to:

Code: Select all

tc0 = job.Tools.Group[0]
to make thing working again.


There where some other problems, as changes are affecting many places of source code.

Maybe if someone is interested, I could put together some other example, with the actual state of code, but as Path is evolving, there are chances that the code is working for a short time.


Regards


Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
spanner888
Posts: 327
Joined: Tue May 28, 2019 10:51 am

Re: Path Scripting documentation.

Post by spanner888 »

Hi Carlo

thanks for the update and keep them coming please.

Some code I wrote (copied) in May and similar that dubstar-04 wrote in early June for FeedsandSpeeds path addon both work with FC 0.19 (just re-confirmed).

Code: Select all

for idx, tc in enumerate(job.Tools.Group):
My stumbling around FreeCAD git repo seems to show change came as part of new ToolBits system, for example this commit on Jan 1 2021 Use job.ToolTable.Group instead of job.ToolController

So the

Code: Select all

tc0 = job.ToolController[0]
seems to be old style Tools code?
User avatar
onekk
Veteran
Posts: 6205
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Path Scripting documentation.

Post by onekk »

Thanks I've not noted that, I was busy with other things.

EDIT:

Done some experimenting, and put together a more complex code, that modify ToolController data and even EndMill data to suit different needs:

Code: Select all

"""test_path.py

   This code was written as an sample code 
   for "FreeCAD Forum" 
     
   Author: Carlo Dormeletti
   Copyright: 2021
   Licence: CC BY-NC-ND 4.0 IT 
"""

import FreeCAD
from FreeCAD import Base, Rotation, Vector
import Part
import Path
import Draft

from PathScripts import PathJob
from PathScripts import PathJobGui

from PathScripts import PathProfile

import PathScripts.PathDressupDogbone as PathDressupDogbone

import PathScripts.PathDressupHoldingTags as PathDressupHoldingTags

from PathScripts import PathGeom
from PathScripts import PathPostProcessor
from PathScripts import PathUtil

import numpy as np

DOC_NAME = "Pippo"
gcodePath = '/tmp/engrave.ngc'

DOC = FreeCAD.activeDocument()

def clear_doc():
    """
    Clear the active document deleting all the objects
    """
    for obj in DOC.Objects:
        DOC.removeObject(obj.Name)

if DOC is None:
    FreeCAD.newDocument(DOC_NAME)
    FreeCAD.setActiveDocument(DOC_NAME)
    DOC = FreeCAD.activeDocument()
    VIEW = FreeCAD.Gui.ActiveDocument.ActiveView
else:
    clear_doc()
    VIEW = FreeCAD.Gui.ActiveDocument.ActiveView

def setview():
    """Rearrange View"""
    DOC.recompute()
    VIEW.viewAxometric()
    VIEW.setAxisCross(True)
    VIEW.fitAll()

EPS = 0.10
EPS_C = EPS * -0.5

VZOR = Vector(0,0,0)
RZO = Rotation(0, 0, 0)

box0 = DOC.addObject('Part::Box', 'Box')
box0.Width = 100
box0.Length = 100
box0.Height = 10

box1 = DOC.addObject('Part::Box', 'Box')
box1.Width = 50
box1.Length = 50
box1.Height = 20
box1.Placement = FreeCAD.Placement(FreeCAD.Vector(25,25,-5), FreeCAD.Rotation(FreeCAD.Vector(0,0,1), 0))

DOC.recompute()

cut = DOC.addObject('Part::Cut', 'Cut')
cut.Base = box0
cut.Tool = box1

DOC.recompute()

# get the upper face?
for i in range(11):
    face = "Face%d" % (i+1)
    f = cut.Shape.getElement(face)
    if f.Surface.Axis == FreeCAD.Vector(0,0,1) and f.Orientation == 'Forward':
        break


job = PathJob.Create('Job', [cut], None)
job.ViewObject.Proxy = PathJobGui.ViewProvider(job.ViewObject)

job.PostProcessorOutputFile = gcodePath
job.PostProcessor = 'grbl'
job.PostProcessorArgs = '--no-show-editor'

# set some common data
job.SetupSheet.Label = "Custom SS"
job.SetupSheet.HorizRapid = '10 mm/s'
job.SetupSheet.VertRapid = '1 mm/s'

job.recompute()

# Assume we are using default tool controller 0
tc0 = job.Tools.Group[0]
#tc0 = job.ToolTable.Group[0]
tc0.HorizFeed = '25.0000 mm/s'
tc0.VertFeed = '16.0000 mm/s'

# different way if there is Expressions in fields
tc0.setExpression('HorizRapid', None)
tc0.HorizRapid = "15 mm/s"
tc0.setExpression('VertRapid', None)
tc0.VertRapid = "2 mm/s"

tc0.recompute()

# Modify default Tool data
tct1 = tc0.Tool
tct1.Label = "Tool 1 Endmill"
#tct1.CuttingEdgeHeight =
tct1.Diameter = "3.25 mm"
tct1.Length =  "45.00 mm"
tct1.ShankDiameter = "3.20 mm"

tct1.recompute()

profile = PathProfile.Create('Profile')

profile.Base = (cut, face)
profile.setExpression('StepDown', None)
profile.StepDown = 3.00
profile.setExpression('StartDepth', None)
profile.StartDepth = 10
profile.setExpression('FinalDepth', None)
profile.FinalDepth = 0
profile.processHoles = True
profile.processPerimeter = True

profile.recompute()

DOC.recompute()


postlist = []
currTool = None

for obj in job.Operations.Group:
    print( obj.Name)
    tc = PathUtil.toolControllerForOp(obj)
    if tc is not None:
        if tc.ToolNumber != currTool:
            postlist.append(tc)
            currTool = tc.ToolNumber
    postlist.append(obj)

post = PathPostProcessor.PostProcessor.load(job.PostProcessor)
gcode = post.export(postlist, gcodePath , job.PostProcessorArgs)

#ops = DOC.getObject("Operations")
#ops.Visibility = True

DOC.recompute()

print("--- done ---")
with:

Code: Select all

tc0 = job.Tools.Group[0]
Job is correctly computed (no blue marks) and toolpath (green lines) are correctly displayed.

with

Code: Select all

#tc0 = job.ToolTable.Group[0]
there are blue marks on Job and other things and toolpath are not show, and some manual actions are needed, so to have some decent interaction my code is working the ToolTable is not working.

Some more investigations are needed to guess why.


Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
spanner888
Posts: 327
Joined: Tue May 28, 2019 10:51 am

Re: Path Scripting documentation.

Post by spanner888 »

onekk wrote: Fri Nov 05, 2021 4:53 pm

Code: Select all

#tc0 = job.ToolTable.Group[0]
Thanks for that snippet, might give me a clue, or at least incentive to get back to one chunk of my code that creates ranges of ToolControllers & associated ToolBits, but I got lost trying to save to ToolTables.
User avatar
onekk
Veteran
Posts: 6205
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Path Scripting documentation.

Post by onekk »

I hooe that at some point @sliptonic will get into discussion and make some light with tooltable management.

Maybe I will ping him later.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
maxwang531
Posts: 21
Joined: Sun Sep 19, 2021 5:25 pm

Re: Path Scripting documentation.

Post by maxwang531 »

onekk wrote: Mon Jan 04, 2021 6:50 pm Somemore progress, many thanks to sliptonic

Code: Select all

import FreeCAD
from FreeCAD import Base, Rotation, Vector
import Part
import Path
import Draft

from PathScripts import PathJob
from PathScripts import PathJobGui

from PathScripts import PathProfile

import PathScripts.PathDressupDogbone as PathDressupDogbone

import PathScripts.PathDressupHoldingTags as PathDressupHoldingTags

from PathScripts import PathGeom
from PathScripts import PathPostProcessor
from PathScripts import PathUtil

import numpy as np

DOC_NAME = "Pippo"
gcodePath = '/tmp/engrave.ngc'

DOC = FreeCAD.activeDocument()

def clear_doc():
    """
    Clear the active document deleting all the objects
    """
    for obj in DOC.Objects:
        DOC.removeObject(obj.Name)

if DOC is None:
    FreeCAD.newDocument(DOC_NAME)
    FreeCAD.setActiveDocument(DOC_NAME)
    DOC = FreeCAD.activeDocument()
    VIEW = FreeCAD.Gui.ActiveDocument.ActiveView
else:
    clear_doc()
    VIEW = FreeCAD.Gui.ActiveDocument.ActiveView

def setview():
    """Rearrange View"""
    DOC.recompute()
    VIEW.viewAxometric()
    VIEW.setAxisCross(True)
    VIEW.fitAll()

EPS = 0.10
EPS_C = EPS * -0.5

VZOR = Vector(0,0,0)
RZO = Rotation(0, 0, 0)

box0 = DOC.addObject('Part::Box', 'Box')
box0.Width = 100
box0.Length = 100
box0.Height = 10

box1 = DOC.addObject('Part::Box', 'Box')
box1.Width = 50
box1.Length = 50
box1.Height = 20
box1.Placement = FreeCAD.Placement(FreeCAD.Vector(25,25,-5), FreeCAD.Rotation(FreeCAD.Vector(0,0,1), 0))

DOC.recompute()

cut = DOC.addObject('Part::Cut', 'Cut')
cut.Base = box0
cut.Tool = box1

DOC.recompute()

# get the upper face?
for i in range(11):
    face = "Face%d" % (i+1)
    f = cut.Shape.getElement(face)
    if f.Surface.Axis == FreeCAD.Vector(0,0,1) and f.Orientation == 'Forward':
        break

job = PathJob.Create('Job', [cut], None)
job.ViewObject.Proxy = PathJobGui.ViewProvider(job.ViewObject)

profile = PathProfile.Create('Profile')

profile.Base = (cut, face)
profile.setExpression('StepDown', None)
profile.StepDown = 3.00
profile.setExpression('StartDepth', None)
profile.StartDepth = 10
profile.setExpression('FinalDepth', None)
profile.FinalDepth = 0
profile.processHoles = True
profile.processPerimeter = True

profile.recompute()

DOC.recompute()

job.PostProcessorOutputFile = gcodePath
job.PostProcessor = 'grbl'
job.PostProcessorArgs = '--no-show-editor'

postlist = []
currTool = None

for obj in job.Operations.Group:
    print( obj.Name)
    tc = PathUtil.toolControllerForOp(obj)
    if tc is not None:
        if tc.ToolNumber != currTool:
            postlist.append(tc)
            currTool = tc.ToolNumber
    postlist.append(obj)

post = PathPostProcessor.PostProcessor.load(job.PostProcessor)
gcode = post.export(postlist, gcodePath , job.PostProcessorArgs)

#ops = DOC.getObject("Operations")
#ops.Visibility = True

DOC.recompute()

print("--- done ---")



Some little quirks to fix but at least path are shown and seems that gcode is useable, more to come

Regards

Carlo D.
Hi, thank you for your progress on the path script. I am currently experiencing a path problem. Have you encountered the following information when generating the path? Does this represent an error in the model or is there a problem with the path itself?

Code: Select all

18:39:34  <Path.Area> Area.cpp(1432): hit bottom -0,0,1e-06
18:39:34  <Path.Area> Area.cpp(1432): hit bottom -4.44089e-16,-3.61823e-16,1e-06
18:39:34  <Path.Area> Area.cpp(1432): hit bottom -0,0,1e-06
18:39:34  <Path.Area> Area.cpp(1432): hit bottom -4.44089e-16,-3.61823e-16,1e-06
18:39:34  PathSetupSheet.INFO: SetupSheet has no support for ADA
18:39:34  *** Adaptive toolpath processing started...
18:39:34  *** Done. Elapsed time: 0.140644 sec

18:39:34  *** Adaptive toolpath processing started...
18:39:35  *** Done. Elapsed time: 0.006981 sec
18:39:40  Tasks are finished
18:39:40  Abnormal program termination...
18:39:40  Unhandled Base::Exception caught in GUIApplication::notify.
The error message is: Break signal occurred
The reminder of Path.Area occurs during the path generation process, and the Unhandled Base occurs during the simulator call phase.
User avatar
onekk
Veteran
Posts: 6205
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Path Scripting documentation.

Post by onekk »

I suppose that these info:

Code: Select all

PathSetupSheet.INFO: SetupSheet has no support for ADA
Is the relevant one.

I've not followed in deep the discussion, but it seems that there are some work on Adaptive Path.

I suppose also that you are using FreeCAD development version. (pleas in case of errors, specify version number you are using, even in 0.20.2606 or similar to have a decent idea where problem occurs).

There is some work that has to be done already on Path, and just yesterday some discussion are started (or at least I've started a new thread about it, following some other advice.).

Sorry to not to be more helpful.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
Post Reply