Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
503 lines (331 sloc) 13.4 KB

Future embellishments

  • Specify preamble (set G64P, G40, etc, like gcoder.init()).

  • Pockets with islands. Counter-clockwise paths are the outside walls of the pocket, clockwise paths are the islands.

  • Chain drilling. Offset the path, walk along it in steps of (drill diameter - overlap), g81 or g83.

  • Plunge mill roughing. Rough a pocket by plunging a twist drill (or center-cutting endmill).

  • Some way to deal with open paths - sometimes you want to machine one side of a part, not the whole perimeter. You could include free space return path in the drawing, but you would need to know the size of the cutter so there’s room for it. "Entry" and "exit" moves (or maybe "approach" and "departure" moves?) would be important here.

  • GUI (optional, the program must still be scriptable). The GUI displays the input SVG and the computed tool path, and lets you export the toolpath as g-code. Something like cambam. Maybe start with dxf2gcode, add the features that are missing (svg input, offset paths, pocketing, what else?).

  • Better pocketing algorithm. It currently makes the longest possible slotting cut…​ Instead, maybe first slot the innermost path, then shoulder mill out? That doesn’t deal smartly when the current "start outside, move inwards" algorithm generates multiple "remaining islands". There must be literature on this topic. Anders' Wallin’s opencamlib does something smarter.

  • Add support for SVG group transforms. The "scaled" test needs this. truss gcode is upside down vs svg, house is not. This probably requires support in svgpathtools for "<g transform>". The Inkscape "ApplyTransformations" extension seems pretty close, but doesn’t handle circle elements. Until then, this seems like a possible workaround (requires inkscape GUI though):

    inkscape ${SVG_FILE} --verb=EditSelectAll --verb=SelectionUnGroup --verb=FileSave --verb=FileClose  --verb=FileQuit
  • Add user units handling. Currently all numbers the user specifies are SI (mm for offsets, doc, etc; mm/min for feeds). Accept units with numbers, like "0.375inch" or "5mm/min"(?). Some default applies to numbers without specific units, and the default can be specified (imperial/metric).

  • Let work-holding tabs span the path end.

  • Make tabs that apply to multiple jobs…​ A typical use case is to machine a part by cutting an 'offset' with a distance larger than the cutter radius (roughing it out), then a second operation operation finishes the part at the proper offset distance. (Then manually cutting the tabs.) Getting the two sets of tabs to line up is pretty fiddly. Maybe specify them as percentages along the path, rather than millimeter distances?

  • "Rest machining": Machine the initial part of the pocket with a large-diameter cutter, then do cleanup/finishing with a small-diameter cutter. It would have to keep track of the 'remaining material contour' and not cut too deep.

  • Make it faster

    • Profile & optimize.

      • Generate a profile: python -m cProfile -o out.prof /home/seb/svg2gcode/svg2gcode --debug $(cat test.args) test.s2g test.svg >| result.ngc 2>| stderr

      • Analyze the profile: runsnake out.prof

    • Make the runtests script parallelize the tests.

    • Make s2g parallelize the work. Run handle_operation() calls in parallel maybe?

  • Let 'engrave' jobs have work-holding tabs. This will be easy to do, just add it to the jobfile schema and pass it through in do_engrave().

  • Add a property to the items in the jobs array specifying whether to do all ops on each path in turn, or each op on all paths?

  • Just like we have plunge, slot, and shoulder feeds, we need different speeds for each.

  • offset_paths() takes an optional steps argument, let user choose.

  • Add peck drilling via optional arguments to the drill op.

  • Per-operation speeds, feeds, and adoc (like there’s currently per-op rdoc for pocketing).

  • A typical use case is to mill around the outline of a part, freeing it from the raw material. To get the best surface finish you’d make two cuts: first a slot offset out from the outline by the cutter radius plus a small finishing allowance, followed by a finishing pass offset out from the outline by just the cutter radius. The retract move at the end of the finishing pass should not happen with the tool in contact with the part, it leaves a blemish. Instead add an optional "departure move" or "exit move" or "pre-retract move" after finishing the path, before retracting, pulling away from the material contour path by a small amount, maybe half the finishing allowance. Linear (perpendicular to the path) or arc departure moves work, but arcs might be harder to get right? Approach moves might benefit similarly.

  • The pocket operation only applies the ramp to the first (slotting) cut. Subsequent cuts (shrinking the left-behind islands) use plunge entry. They should probably ramp too, though maybe at a steeper angle since they’re not slotting.

Plating

Allow an operation to make multiple copies of a single part, or combinations of parts.

A typical use case: "This thing I want to build is an assembly of 3 copies of part A (machined slightly differently) and 2 copies of part B (machined slightly differently)."

Define a job file that specifies the following information:

  • There are five models:

    1. A.svg

    2. A.svg translated by X=15

    3. A.svg translated by X=30

    4. B.svg translated by Y=25

    5. B.svg translated by X=20 and Y=25

  • A full-depth drill operation applies to all the 1/4" circles in models 3, 4, and 5.

  • A partial depth drill operation applies to all the 1/4" circles in model 2.

  • An offset operation applies to the outline paths of models 1-5.

Some features I think I’ll want in s2g to implement this:

  • Override pocket cut params from command line. Width of cut is a function of depth of cut.

  • Plate lots of copies of a single part. Have handle_operation() return a list of the path_to_gcode() calls it currently makes, and run them multiple times with X & Y offsets.

  • Plate different parts together. This will need support for translations, and sorting the different parts' operations by tool.

  • Expand the job file to include the command line arguments (what currently goes in test.args in the tests).

The job file schema might look something like this:

job_file = { "models": [ model ] "jobs": [ job_description ] }

model = { "file": <str> "translation":? { "x": <float> "y": <float> } }

job_description: { "paths": [ path_identifier ] "operations": [ operation_identifier ] }

path_identifier: { "model": <int> "path": [<int>] }

operation_identifier: { operation_type: operation_type_args }

operation_type is one of [ 'drill', 'engrave', 'offset', 'pocket' ]

operation_type_args is as in the current v2 schema file, except that all operations gain optional(?) args to control speeds & feeds and z-levels.

The drilling jobsfile for the use case above might looks something like this:

{
    "models": [
        {
            "file": "A.svg"
        },
        {
            "file": "A.svg",
            "translation": { "x": 15 }
        },
        {
            "file": "A.svg",
            "translation": { "x": 30 }
        },
        {
            "file": "B.svg",
            "translation": { "y": 25 }
        },
        {
            "file": "B.svg",
            "translation": { "x": 20, "y": 25 }
        }
    ],
    "jobs": [
        {
            "paths": [
                { "model": 3, "paths": [ 0, 1, 2 ] },
                { "model": 4, "paths": [ 5, 6 ] },
                { "model": 5, "paths": [ 5, 6 ] }
            ],
            "drill": {
                "speed": 3500,
                "feed": 11.0,
                "z-cut-depth": -10.0
            }
        },
        {
            "paths": [
                { "model": 2, "paths": [ 0, 1, 2 ] }
            ],
            "drill": {
                "speed": 3500,
                "feed": 11.0,
                "z-cut-depth": -5.0
            }
        }
    ]
}

And the outline milling job file:

{
    "models": [
        {
            "file": "A.svg"
        },
        {
            "file": "A.svg",
            "translation": { "x": 15 }
        },
        {
            "file": "A.svg",
            "translation": { "x": 30 }
        },
        {
            "file": "B.svg",
            "translation": { "y": 25 }
        },
        {
            "file": "B.svg",
            "translation": { "x": 20, "y": 25 }
        }
    ],
    "jobs": [
        {
            "paths": [
                { "model": 1, "paths": [ 3 ] },
                { "model": 2, "paths": [ 3 ] },
                { "model": 3, "paths": [ 3] },
                { "model": 4, "paths": [ 7 ] },
                { "model": 5, "paths": [ 7 ] }
            ],
            "offset": {
                "distance": 3.5,
                "speed": 3500,
                "feed": 11.0,
                "z-cut-depth": -10.0
            }
        }
    ]
}

Hm, maybe the models should move out to a separate file, to be specified on the command line along with the job file (or named in the job file). Wouldn’t want the translations to get out fo sync.

Pocket: smarter pass-to-pass transitions

I want better transitions from a finished pass to the start of the next pass.

It currently does "raise, traverse, plunge", which is simple, safe, slow, and plungy.

Sometimes one pass ends near the start of the next pass, with no remaining material in between. In this case it’d be better to feed there directly, along the floor of the pocket (or maybe just above, to avoid rubbing).

However sometimes there’s a long way from one pass end to the next pass start, and obstacles can intervene: other islands, and the walls of the pocket itself. In this case revert to the current safe behavior.

To select which of "raise, traverse, plunge" and "feed" to use:

  • The proposed feed move is a g1 from the current (X, Y) to the start of the next pass.

  • If the proposed feed intersects the original slotting toolpath we’ll gouge the wall of the pocket, so choose RTP (FIXME: or follow along the slotting path until the second intersection?

  • If the proposed feed comes within tool_radius of any island other than the one we’re on, it gouges that island, so choose RTP (FIXME: or do that island instead?)

  • If the proposed feed intersects the next pass, except at the start point, then it gouges the island we’re going to, so choose RTP (FIXME: or choose a different starting point in the next pass?)

  • If we get here there’s no gouge, so choose that feed move.

computational geometry

Look into replacing svgpathtools with something else

I currently use svgpathtools to do two things:

  • Read and parse the paths from an SVG file.

  • Provide some of the low-level computational geometry primitives for path offsetting (the rest i do by hand in gcoder.offset_paths() and friends).

I like svgpathtools.svg2paths(), and i like that svgpathtools supports arcs.

Possible options

libpolyclipping

aka clipper

No arcs, we’d have to approximate using linear splines.

FreeCAD 0.17’s Path workbench uses clipper.

There’s python3-pyclipper in buster and sid, a python3 wrapper around Clipper.

pythonocc/liboce

pythonocc isn’t packaged, liboce doesn’t have python bindings in stretch

occmodel

A python front-end to the OpenCASCADE modelling kernel. Jeff used it for CAD in python.

Not packaged in Stretch (though liboce is).

libarea

Written in C++, builds a python module.

Not actively maintained any more. Not in Debian. No docs, minimal comments.

Contains an old copy of clipper aka libpolyclipping.

openvoronoi/opencamlib

Anders Wallin’s project. Not in debian.

openvoronoi doesn’t handle arcs, and Anders claims for 3d you should tesselate anyway, so maybe i should just abandon my quest for arcs.

cgal

Has Circles but not Arcs? Weird. But there’s a Circular_Arc in the "2D Circular Geometry Kernel", whatever that is?

wykobi

MIT license.

Not in debian, not actively maintained.

Does circles but not arcs.

DGtal

LGPL3

Considered and discarded

svg.path + shapely

Shapely doesn’t do arcs or bezier curves, only linear splines. Which is maybe fine. Shapely has parallel_offset(), left and right…​ FlatCAM uses Shapely.

libclippoly http://clippoly.sourceforge.net/

Lines only, no arcs, no bezier curves.

Doesn’t do offsetting.

boost.geometry

Doesn’t have Arcs or Bezier Splines.

boost.polygon

No arcs.

gpc

Not libre.

SVG reading libraries

svg.path

API is similar to svgpathutils, but svg.path doesn’t have svg2paths().

python-rsvg

Uses gobject introspection.

cairosvg

svglib

Not in Stretch.

svgutils

Not in Stretch.

You can’t perform that action at this time.