Add portable Line-us pen-arm support to ink-signature pipeline
Adds a second machine class (small fan-shaped reach arm) alongside the CR-10/AxiDraw rectangular-bed plotters, so wet signatures can be produced while away from the home station. ink_signature_plotter.py: - PlotterConfig gains dialect (marlin|lineus) + name; new LineUsConfig (native units, pen height = per-move Z, reach annulus from shoulder pivot). - Named machine profiles (cr10 default, axidraw, lineus) via load_profile(). - bed_mm_to_lineus_units(), check_reach() (annulus for lineus, rectangle for marlin), compute_jig_offset_for_box() (solves jig from the ACTUAL fitted ink extent so a wide cell line doesn't over-constrain a small arm). - emit_gcode() dispatches to emit_marlin_gcode()/emit_lineus_gcode(). - send_lineus(): WiFi TCP 1337 (NUL-terminated, ok-acked) or USB serial, dry_run=True default (same gating as the CR-10 path). ink_signature_cli.py: --profile, --solve-jig (auto-applies jig offset), --lineus-host/--lineus-usb, reach-check that refuses to --plot out-of-reach on Line-us. Tests: 43 checks (was 30) covering profiles, reach check, jig solve, lineus emitter, dry-run sender. Docs updated with profiles + portable workflow.
This commit is contained in:
parent
aafa76df83
commit
894d989445
4 changed files with 595 additions and 19 deletions
|
|
@ -119,6 +119,53 @@ def main():
|
|||
g_big = ink.emit_gcode(ink.plan_signature(vector, big_box, cfg), cfg)
|
||||
check("over-bed plot warns", "outside the configured bed" in g_big)
|
||||
|
||||
print("profiles: cr10 / axidraw / lineus")
|
||||
cr10 = ink.load_profile("cr10")
|
||||
axi = ink.load_profile("axidraw")
|
||||
lu = ink.load_profile("lineus")
|
||||
check("cr10 is marlin Z-pen", cr10.dialect == "marlin" and not cr10.servo_pen)
|
||||
check("axidraw is marlin servo + A4 bed", axi.dialect == "marlin" and axi.servo_pen and axi.bed_max_y_mm == 297.0)
|
||||
check("lineus dialect + has LineUsConfig", lu.dialect == "lineus" and lu.lineus is not None)
|
||||
raised = False
|
||||
try:
|
||||
ink.load_profile("nope")
|
||||
except ValueError:
|
||||
raised = True
|
||||
check("unknown profile raises", raised)
|
||||
|
||||
print("Line-us reach check + jig solve")
|
||||
# With the default jig (0,0), the CMS box (PDF ~48,443 pt) maps far outside
|
||||
# the small arm's reach -> reach check should fail.
|
||||
lu_planned_raw = ink.plan_signature(vector, BOX, lu)
|
||||
rep_raw = ink.check_reach(lu_planned_raw, lu)
|
||||
check("raw lineus plot is out of reach", rep_raw["dialect"] == "lineus" and not rep_raw["ok"])
|
||||
# Solve the jig: should bring the whole cell into reach.
|
||||
solved = ink.compute_jig_offset_for_box(BOX, lu, vector=vector)
|
||||
check("solve-jig reports ok", solved["ok"] is True)
|
||||
check("solve-jig returns jig offsets", "jig_x_mm" in solved and "jig_y_mm" in solved)
|
||||
from dataclasses import replace as _replace
|
||||
lu_fixed = _replace(lu, jig_x_mm=solved["jig_x_mm"], jig_y_mm=solved["jig_y_mm"])
|
||||
lu_planned = ink.plan_signature(vector, BOX, lu_fixed)
|
||||
rep_fixed = ink.check_reach(lu_planned, lu_fixed)
|
||||
check("after solve-jig the signature is in reach", rep_fixed["ok"] is True)
|
||||
|
||||
print("Line-us G-code emission")
|
||||
glu = ink.emit_gcode(lu_planned, lu_fixed)
|
||||
check("lineus homes the arm", "G28" in glu)
|
||||
check("lineus encodes pen height as Z in G01", "G01 X" in glu and f"Z{lu.lineus.pen_up_z:d}" in glu)
|
||||
check("lineus uses pen-down Z", f"Z{lu.lineus.pen_down_z:d}" in glu)
|
||||
check("lineus has no Marlin mm header", "G21" not in glu)
|
||||
check("in-reach lineus plot has no reach warning", "fall outside the arm reach" not in glu)
|
||||
# Out-of-reach plot should carry the warning comment.
|
||||
glu_bad = ink.emit_gcode(lu_planned_raw, lu)
|
||||
check("out-of-reach lineus plot warns", "fall outside the arm reach" in glu_bad)
|
||||
|
||||
print("Line-us sender is dry-run safe")
|
||||
res_tcp = ink.send_lineus(glu, dry_run=True)
|
||||
check("lineus dry-run does not send (tcp)", res_tcp["sent"] is False and res_tcp["transport"] == "tcp")
|
||||
res_usb = ink.send_lineus(glu, serial_port="/dev/ttyACM0", dry_run=True)
|
||||
check("lineus dry-run does not send (usb)", res_usb["sent"] is False and res_usb["transport"] == "serial")
|
||||
|
||||
print("preview SVG")
|
||||
svg = ink.render_preview_svg(planned, cfg)
|
||||
check("svg has path(s)", "<path" in svg)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue