179 lines
7.2 KiB
HTML
179 lines
7.2 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Vision Alignment</title>
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<header class="header">
|
|
<h1>Vision Alignment</h1>
|
|
<p class="subtitle">
|
|
Three-point fiducial registration · camera offset · software skew compensation
|
|
</p>
|
|
</header>
|
|
|
|
<section class="controls">
|
|
<label class="field">
|
|
<span>Camera</span>
|
|
<select id="camera-select">
|
|
<option value="">— select after starting —</option>
|
|
</select>
|
|
</label>
|
|
<div class="btn-row">
|
|
<button type="button" id="btn-start" class="btn primary">Start camera</button>
|
|
<button type="button" id="btn-stop" class="btn" disabled>Stop</button>
|
|
</div>
|
|
<p id="status" class="status" role="status">Camera idle</p>
|
|
</section>
|
|
|
|
<section class="viewport-wrap">
|
|
<div class="camera-viewport" id="viewport">
|
|
<video id="cam" autoplay playsinline muted></video>
|
|
<div class="crosshair" aria-hidden="true"><span class="ring"></span></div>
|
|
<div class="placeholder" id="placeholder">
|
|
Start the camera, jog so the cross-hair is on a fiducial, then mark points.
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="controls jog-section">
|
|
<h2 class="section-title">Jog</h2>
|
|
<div class="jog-layout">
|
|
<div class="jog-xy" aria-label="XY jog">
|
|
<button type="button" class="btn jog-btn" data-jog="y+" title="Y+">Y+</button>
|
|
<button type="button" class="btn jog-btn" data-jog="x-" title="X-">X-</button>
|
|
<button type="button" class="btn jog-btn jog-stop" data-jog="stop" title="Stop jog">⏹</button>
|
|
<button type="button" class="btn jog-btn" data-jog="x+" title="X+">X+</button>
|
|
<button type="button" class="btn jog-btn" data-jog="y-" title="Y-">Y-</button>
|
|
</div>
|
|
<div class="jog-z" aria-label="Z jog">
|
|
<button type="button" class="btn jog-btn" data-jog="z+" title="Z+">Z+</button>
|
|
<button type="button" class="btn jog-btn" data-jog="z-" title="Z-">Z-</button>
|
|
</div>
|
|
<div class="jog-settings">
|
|
<div class="jog-dro">
|
|
<div class="dro-row"><span>MPos</span> <code id="jog-mpos">X — Y — Z —</code></div>
|
|
<div class="dro-row"><span>WPos</span> <code id="jog-wpos">X — Y — Z —</code></div>
|
|
</div>
|
|
<div class="jog-selects">
|
|
<label class="field compact">
|
|
<span>Step</span>
|
|
<select id="jog-step">
|
|
<option value="0.1">0.1</option>
|
|
<option value="1" selected>1</option>
|
|
<option value="5">5</option>
|
|
<option value="10">10</option>
|
|
<option value="25">25</option>
|
|
<option value="50">50</option>
|
|
</select>
|
|
</label>
|
|
<label class="field compact">
|
|
<span>Feed</span>
|
|
<select id="jog-feed">
|
|
<option value="100">100</option>
|
|
<option value="500" selected>500</option>
|
|
<option value="1000">1000</option>
|
|
<option value="2000">2000</option>
|
|
<option value="3000">3000</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<label class="field checkbox">
|
|
<input type="checkbox" id="jog-continuous" />
|
|
<span>Hold = continuous</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<p class="hint">Uses Grbl <code>$J=</code> jogging. Hold buttons for continuous when enabled; release or ⏹ to cancel.</p>
|
|
</section>
|
|
|
|
<section class="controls">
|
|
<h2 class="section-title">Camera-to-spindle offset</h2>
|
|
<p class="hint">
|
|
Distance from <strong>camera centre</strong> to <strong>spindle centre</strong>
|
|
(positive X = spindle is to the +X of the camera).
|
|
</p>
|
|
<div class="row-2">
|
|
<label class="field">
|
|
<span>Offset X</span>
|
|
<input type="number" id="offset-x" step="0.001" value="0" />
|
|
</label>
|
|
<label class="field">
|
|
<span>Offset Y</span>
|
|
<input type="number" id="offset-y" step="0.001" value="0" />
|
|
</label>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="controls">
|
|
<h2 class="section-title">Fiducial points</h2>
|
|
<p class="pos-line">
|
|
Live: <code id="live-pos">X — Y —</code>
|
|
<span id="conn-badge" class="badge">…</span>
|
|
</p>
|
|
<div class="points-grid">
|
|
<div class="point-card">
|
|
<strong>Point 1 · Origin</strong>
|
|
<code id="pt1-display">not set</code>
|
|
<button type="button" id="btn-mark-1" class="btn primary small-btn">Mark Point 1</button>
|
|
</div>
|
|
<div class="point-card">
|
|
<strong>Point 2 · Axis</strong>
|
|
<code id="pt2-display">not set</code>
|
|
<button type="button" id="btn-mark-2" class="btn primary small-btn">Mark Point 2</button>
|
|
</div>
|
|
<div class="point-card">
|
|
<strong>Point 3 · Verify</strong>
|
|
<code id="pt3-display">not set</code>
|
|
<button type="button" id="btn-mark-3" class="btn primary small-btn">Mark Point 3</button>
|
|
</div>
|
|
</div>
|
|
<div class="btn-row">
|
|
<button type="button" id="btn-clear-points" class="btn">Clear points</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="controls">
|
|
<h2 class="section-title">Alignment result</h2>
|
|
<pre id="align-result" class="result-box">Mark points 1 and 2 (3 optional) then Align.</pre>
|
|
<div class="btn-row">
|
|
<button type="button" id="btn-align" class="btn primary" disabled>
|
|
Align & Zero Workspace
|
|
</button>
|
|
<button type="button" id="btn-rotate-gcode" class="btn" disabled>
|
|
Rotate loaded G-code
|
|
</button>
|
|
</div>
|
|
<p class="hint">
|
|
<strong>Align & Zero</strong> computes θ from points 1→2, applies camera offset,
|
|
and issues <code>G10 L20</code> so spindle WCS origin matches fiducial 1.
|
|
<strong>Rotate loaded G-code</strong> rewrites X/Y/I/J by −θ and reloads the job
|
|
(FluidNC has no G68).
|
|
</p>
|
|
</section>
|
|
|
|
<section class="options">
|
|
<label class="field inline">
|
|
<span>Cross-hair colour</span>
|
|
<input type="color" id="crosshair-color" value="#00ff66" />
|
|
</label>
|
|
<label class="field inline">
|
|
<span>Thickness</span>
|
|
<input type="range" id="crosshair-thickness" min="1" max="4" step="1" value="2" />
|
|
</label>
|
|
</section>
|
|
|
|
<section class="debug-panel">
|
|
<div class="debug-header">
|
|
<strong>Debug log</strong>
|
|
<button type="button" id="btn-clear-log" class="btn small">Clear</button>
|
|
</div>
|
|
<pre id="debug-log" class="debug-log" aria-live="polite"></pre>
|
|
</section>
|
|
</div>
|
|
<script type="module" src="/src/main.js"></script>
|
|
</body>
|
|
</html>
|