Skip to content

compas_cnc.postprocessor.Postprocessor ¤

Postprocessor(tool=None, tool_number=1, feed=200.0, plunge_feed=None, first_cut_feed_factor=None, spindle_speed=12000, coolant='mist', rapid_z=None, rapid_plane=None, home_z=None, material='Aluminum', stock_size=(300.0, 200.0, 20.0), program='2D Contour', precision=4, travel=CARVERA_AIR_TRAVEL, margin=0.0, on_exceed='raise')

Convert tool-path polylines into Carvera Air G-code and write a .nc file.

The Carvera / Carvera Air desktop CNC (Makera) runs a Smoothieware-derived controller that reads ordinary RS-274 G-code. This post-processor turns the tool-CENTRE polylines produced by the toolpath_2d_* generators (or any merged path from :func:toolpath_merge) into the dialect the machine expects: a % start marker, a commented header (units, tool change, coolant/air, spindle), a body of G1 linear moves, and a shutdown footer.

The path already encodes its own safe-Z approach, plunge, cut and retract. Moves at the safe plane -- and, when rapid_plane is set, EVERY move that stays in the air above it -- are emitted as rapid G0; everything that cuts goes out as G1 at the programmed feed. Every motion line writes X, Y and Z explicitly, so each line can be checked on its own against the machine envelope (no modal-coordinate guessing when reading a program).

Before any G-code is written the path is checked against the machine travel envelope (:data:CARVERA_AIR_TRAVEL, the factory soft-endstop spans -- the practical hard limit, since the far end of each axis has no switch). A job whose bounding-box span overruns the reach raises by default (see :attr:on_exceed), so an out-of-bounds program is caught here instead of as a soft-limit halt mid-cut.

The output reproduces this shape::

%
; 3-Axis
; Material: Aluminum
; Stock Size: 300(X) * 200(Y) * 20(Z) mm
; Tool List
; T1-3.175*19mm Flat End
; Path List
; [T1]2D Contour
G90 G21              ; Absolute positioning, units in millimeters
T1 M6                ; Tool change to Tool 1
M7                   ; Coolant ON (mist)
S12000 M3            ; Spindle ON clockwise at 12000 RPM
G0 Z50
G1 F200
G1 X-149.8351 Y36.0727
G1 Z20
G1 X-149.8351 Y36.0727 Z-18.8
...
M9        ; Turn off coolant
M05       ; Stop the spindle
G28       ; Goto the machine clearance position
M30       ; End of program

Parameters:

  • tool (:class:`compas_cnc.tools.Tool`, default: None ) –

    The cutting tool. Its name, diameter and height fill the tool-list comment (T{n}-{diameter}*{height}mm {name}). If omitted a generic description is written.

  • tool_number (int, default: 1 ) –

    Carvera tool-changer slot, used in the T{n} M6 tool change and the header comments. Defaults to 1.

  • feed (float, default: 200.0 ) –

    Cutting feed rate (mm/min) set once with G1 F{feed}. Defaults to 200.

  • plunge_feed (float, default: None ) –

    Feed rate for a straight Z-DOWN plunge (a move that keeps X/Y and only lowers Z). None (default) plunges at feed.

  • first_cut_feed_factor (float, default: None ) –

    Scale (in (0, 1]) applied to feed for the FIRST cutting move of EVERY tool-path -- the initial engagement, which bites the deepest as it enters full-thickness stock. Each sub-path in a merged program begins from the safe plane, so the first G1 that leaves the rapid height is slowed to feed * factor; the rest of that path resumes at feed. None (default) keeps every cut at feed. 0.5 = first cut at half feed.

  • spindle_speed (int, default: 12000 ) –

    Spindle RPM for S{rpm} M3. Defaults to 12000.

  • coolant (str | None, default: 'mist' ) –

    "mist" / "air" -> M7, "flood" -> M8, None (or False) turns coolant off entirely (no M7/M9). Defaults to "mist".

  • rapid_z (float, default: None ) –

    World-Z for the opening G0 lift to the travel plane. Defaults to the highest Z in the path (the tool-path's own safe traverse height), so the first cutting move starts from a known clearance height.

  • rapid_plane (float, default: None ) –

    World-Z just above the stock top. A straight Z-DOWN plunge from above this plane drops at rapid G0 down to it (pure air travel), then feeds only the remainder into the material -- so a tall safe clearance no longer costs a slow full-depth plunge. Must sit ABOVE all material. None (default) feeds the whole descent as before.

  • home_z (float, default: None ) –

    A high absolute Z reached ONLY at the very START (the opening lift) and the very END (a final retract before homing) -- a load/unload or tool-change safety height. The between-pass retracts still use the tool-path's own (lower) safe plane. None (default) opens and closes at that same safe plane.

  • material (str, default: 'Aluminum' ) –

    Stock material, written into the header comment. Defaults to "Aluminum".

  • stock_size (tuple(float, float, float) | None, default: (300.0, 200.0, 20.0) ) –

    (X, Y, Z) stock dimensions in mm for the header comment. None omits the line. Defaults to (300, 200, 20).

  • program (str, default: '2D Contour' ) –

    Path-list label in the header (; [T{n}]{program}). Defaults to "2D Contour".

  • precision (int, default: 4 ) –

    Decimal places for coordinates; trailing zeros are stripped. Defaults to 4.

  • travel (tuple(float, float, float) | None, default: CARVERA_AIR_TRAVEL ) –

    Per-axis (X, Y, Z) machine reach in mm the job must fit within. A None entry skips that axis; travel=None disables the check entirely. Defaults to :data:CARVERA_AIR_TRAVEL (302, 212, 121). Pass your own jogged values (Makera advise verifying per machine) or :data:CARVERA_AIR_WORKAREA for the conservative rated area.

  • margin (float, default: 0.0 ) –

    Safety margin in mm subtracted from every travel axis before checking, so the job must fit with this much to spare. Defaults to 0.0.

  • on_exceed (str, default: 'raise' ) –

    What to do when the path overruns the envelope: "raise" (default) a :class:ValueError, "warn" a :class:UserWarning, or "ignore".

Attributes:

  • tool, tool_number, feed, spindle_speed, coolant, rapid_z, material,
  • stock_size, program, precision, travel, margin, on_exceed

    The configured options above.

body ¤

body(points)

Motion block printing X, Y and Z on EVERY line, so the height is explicit.

Moves that reach the safe plane (rapid_z) are non-cutting retracts / repositions and go out as rapid G0; everything below it cuts and goes out as G1 at feed (or plunge_feed for a straight Z-down plunge).

When rapid_plane is set, EVERY move that stays at or above that plane is pure air and also goes out as rapid -- this covers the three shapes a path in air can take:

  • a LATERAL link at any safe height (e.g. a merged sub-path whose own safe-Z sits below the program's rapid_z) -- both endpoints in air, so the whole straight move is air;
  • a straight-DOWN plunge from above the plane: G0 down to the plane, then feed only the remainder into the stock -- a tall safe clearance no longer costs a slow full-depth plunge;
  • a straight-UP retract from below the plane: feed out of the material up to the plane, then G0 the rest of the lift.

In-material moves are never rapided: a diagonal move with one endpoint below the plane feeds the whole way. The FIRST cutting move after ANY rapid is slowed to feed * first_cut_feed_factor when that is set, so each fresh engagement bites gently before the rest resumes at feed. The feed word is modal, emitted only when it changes.

check_limits ¤

check_limits(*toolpaths)

Travel-envelope violations for toolpaths -- one dict per axis whose path SPAN exceeds the machine reach.

Returns a list with an entry {"axis", "min", "max", "span", "limit", "over"} for every axis where the bounding-box span is larger than :attr:travel (shrunk by :attr:margin); an empty list means the job fits. The SPAN (not the absolute coordinate) is checked because the work origin is set on the machine at setup, so what matters at post time is whether the part fits the reachable travel -- the firmware soft-endstop span, which on the Carvera Air is the practical hard limit (the far end of each axis has no switch, only a crash beyond it).

footer ¤

footer()

Shutdown block (final safety retract, coolant off, spindle stop, home, end).

header ¤

header(points)

Header block (% marker, comments, units, tool change, coolant, spindle).

to_gcode ¤

to_gcode(*toolpaths)

Full .nc program text for one or more tool-paths / polylines.

Each argument may be a toolpath_2d_* object (anything with a .path) or a raw :class:compas.geometry.Polyline; they are concatenated in order. The path is checked against the machine travel envelope first (see :attr:on_exceed).

to_gcode_program ¤

to_gcode_program(sections, tool_change_note='tool change + automatic tool-length touch-off', calibrate=None)

Full .nc for SEVERAL tools run as one Carvera job.

On the Carvera Air every .nc you load needs its own load-probe-cut cycle, so a two-tool part (e.g. engrave then profile-cut) otherwise means loading, probing and running twice. This packs the operations into ONE program instead: a single header and footer, and between them, for EACH section, a T{n} M6 tool change, the spindle start, that section's motion, and a spindle stop before the next change. So the machine runs: (probe the STOCK once, set in the Controller) -> change to tool 1, cut section 1 -> change to tool 2, cut section 2.

Tool-length calibration is part of the Carvera's M6 routine: the change touches off the newly loaded tool on the setter, and the firmware halts the job if a valid TLO has not been measured -- so no separate calibration line is needed and every (including manually fed) tool is re-measured at its M6. calibrate can emit an EXTRA explicit probe after each M6 for setups that need it, but it is off by default to avoid a redundant second touch-off.

Parameters:

  • sections (list[tuple]) –

    Ordered (tool, tool_number, label, toolpaths) -- one milling operation per physical tool, machined in this order. tool/tool_number fill that section's tool-change and header comments; label is its path-list line.

  • tool_change_note (str, default: 'tool change + automatic tool-length touch-off' ) –

    Comment appended to each T{n} M6 line.

  • calibrate (str | None, default: None ) –

    Extra tool-length calibration command emitted after each M6 (spindle off) -- e.g. "M491" (the Carvera TLO probe). None (default) relies on the M6 routine's own touch-off; set it only if your firmware does NOT calibrate in M6.

  • Every
  • the
  • single
  • the

write ¤

write(filepath, *toolpaths)

Write the .nc program for toolpaths to filepath (.nc added if missing). Returns the resolved :class:pathlib.Path.

write_program ¤

write_program(filepath, sections, **kwargs)

Write :meth:to_gcode_program for sections to filepath (.nc added if missing). Returns the resolved :class:pathlib.Path.