Ruida laser skill: prepare and load jobs, never run them
FreeCAD/DXF to .rd conversion, named upload to controller memory with idle check and read-back verification, read-only status/file listing, and a fake controller for dry runs. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
4e957509cc
11 files changed
+695
No files matched your search
Executable
+49
@@ -0,0 +1,49 @@
|
||||
# fc2dxf.py: export a flat FreeCAD body (sheet part) to a LINE-only DXF for dxf2rd.py.
|
||||
# Takes the largest planar face normal to the body's thinnest axis, writes its outline and holes
|
||||
# with inner loops first (so the part doesn't drop before its holes are cut), origin at the
|
||||
# bottom-left corner, mm. Curves are flattened to lines within 0.02 mm. Opens the .FCStd
|
||||
# read-only and never saves it.
|
||||
#
|
||||
# usage (FreeCAD's headless interpreter):
|
||||
# freecadcmd -c "import sys; sys.argv=['x','MODEL.FCStd','BodyLabel','OUT.dxf']; exec(open('fc2dxf.py').read())"
|
||||
# Prints the part thickness: check it matches your stock. A blind pocket (not through) can't be
|
||||
# cut, only engraved, so the script refuses bodies with planar faces between the two sides.
|
||||
import FreeCAD, sys
|
||||
MODEL, NAME, OUT = sys.argv[-3], sys.argv[-2], sys.argv[-1]
|
||||
d = FreeCAD.openDocument(MODEL)
|
||||
objs = d.getObjectsByLabel(NAME)
|
||||
assert objs, f"no object labelled {NAME!r}"
|
||||
s = objs[0].Shape; b = s.BoundBox
|
||||
dims = [b.XLength, b.YLength, b.ZLength]; t = dims.index(min(dims))
|
||||
ax = [i for i in range(3) if i != t]
|
||||
mn = [b.XMin, b.YMin, b.ZMin]
|
||||
flat = [f for f in s.Faces if f.Surface.__class__.__name__ == 'Plane'
|
||||
and abs(abs(f.normalAt(0, 0)[t]) - 1) < 1e-6]
|
||||
levels = sorted({round(f.CenterOfMass[t], 3) for f in flat})
|
||||
assert len(levels) == 2, f"faces at {levels}: blind pocket or step, not a through-cut sheet part"
|
||||
f = max(flat, key=lambda f: f.Area)
|
||||
loops = []
|
||||
for w in f.Wires:
|
||||
segs = []
|
||||
for e in w.OrderedEdges:
|
||||
pts = ([e.Vertexes[0].Point, e.Vertexes[-1].Point] if e.Curve.__class__.__name__ == 'Line'
|
||||
else e.discretize(Deflection=0.02))
|
||||
pts = [(p[ax[0]] - mn[ax[0]], p[ax[1]] - mn[ax[1]]) for p in pts]
|
||||
segs += list(zip(pts, pts[1:]))
|
||||
xs = [p[0] for sg in segs for p in sg]; ys = [p[1] for sg in segs for p in sg]
|
||||
loops.append(((max(xs) - min(xs)) * (max(ys) - min(ys)), segs))
|
||||
loops.sort(key=lambda l: l[0]) # inner cuts first, outline last
|
||||
out = ["0", "SECTION", "2", "HEADER", "9", "$INSUNITS", "70", "4", "0", "ENDSEC",
|
||||
"0", "SECTION", "2", "ENTITIES"]
|
||||
n = 0
|
||||
for _, segs in loops:
|
||||
for (x1, y1), (x2, y2) in segs:
|
||||
if abs(x1 - x2) + abs(y1 - y2) < 1e-6:
|
||||
continue
|
||||
out += ["0", "LINE", "8", "CUT", "10", "%.4f" % x1, "20", "%.4f" % y1, "30", "0",
|
||||
"11", "%.4f" % x2, "21", "%.4f" % y2, "31", "0"]; n += 1
|
||||
out += ["0", "ENDSEC", "0", "EOF"]
|
||||
open(OUT, 'w').write("\n".join(out) + "\n")
|
||||
print(f"{NAME} -> {OUT}: {n} lines, {len(loops)} loops, {dims[ax[0]]:.2f} x {dims[ax[1]]:.2f} mm, "
|
||||
f"thickness {dims[t]:.2f} mm")
|
||||
FreeCAD.closeDocument(d.Name)
|
||||
Reference in new issue
Block a user