3fe919e37c
Move SKILL.md + references/ scripts/ evals/ from skills/halcon/ up to the plugin root. Per Claude Code plugins-reference, a plugin with SKILL.md at its root and no skills/ subdir is auto-loaded as a single-skill plugin (v2.1.142+), so the invocation name = frontmatter name = halcon → clean /halcon. Bump plugin.json 2.0.0 → 2.0.1 so existing installs receive the update. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
97 lines
5.6 KiB
Markdown
97 lines
5.6 KiB
Markdown
# Remote HALCON over MCP (`halcon-remote`)
|
||
|
||
A **remote** HALCON compute service exposed as an MCP server. Use it when there is
|
||
**no local HALCON** (e.g. MacOS, a plain Linux box, a colleague's machine) — it runs
|
||
HALCON 24.11 on a headless Linux server and is reachable over the public internet.
|
||
Client needs only network + a bearer token; **no HALCON, no minio creds, no VPN/tailnet.**
|
||
|
||
- Endpoint: `https://halcon-mcp.totoro.studio/mcp` (Streamable HTTP, Bearer auth)
|
||
- Token: server-side `/opt/halcon-mcp/.env` (`HALCON_MCP_TOKEN`); in configs reference `${HALCON_MCP_TOKEN}`, never hardcode.
|
||
- Source/ops: repo `halcon-mcp-remote/`; server `192.168.1.13:/opt/halcon-mcp` (systemd `halcon-mcp`). Full deploy facts: repo `halcon-tools.yaml` → `halcon_mcp_remote`.
|
||
|
||
## Register the server (client side)
|
||
|
||
```bash
|
||
# user scope (works across all projects)
|
||
claude mcp add --scope user --transport http halcon-remote \
|
||
https://halcon-mcp.totoro.studio/mcp --header "Authorization: Bearer $HALCON_MCP_TOKEN"
|
||
claude mcp list # expect: halcon-remote ... ✔ Connected
|
||
```
|
||
Or project `.mcp.json`: `{ "type":"http", "url":".../mcp", "headers":{"Authorization":"Bearer ${HALCON_MCP_TOKEN}"} }`.
|
||
|
||
## Tools (full names: `mcp__halcon-remote__<tool>`)
|
||
|
||
| Tool | Does | Key args |
|
||
|---|---|---|
|
||
| `halcon_get_env` | Self-check: version/hostid/arch | — |
|
||
| `halcon_create_upload` | Presigned PUT URL to upload one file (image or zip), no creds | `filename`, `expires_minutes` |
|
||
| `halcon_find_circles` | Subpixel find circles → list + preview | `image` or `image_b64` |
|
||
| `halcon_measure_overlay` | Bullseye overlay: Top/Bottom center deviation (µm) | `image` or `image_b64`, `apply_registration` |
|
||
| `halcon_overlay_batch` | Batch overlay over a minio prefix → CSV | `prefix`, `max_images` |
|
||
| `halcon_find_circles_zip` | Batch find circles: image zip → 4 ring-mark centers (TL/TR/BL/BR) → CSV | `zip_key`, `min/max_radius` |
|
||
| `halcon_exec_hdev` | Run an HDevelop script via hrun → stdout (destructive) | `script_text` |
|
||
|
||
## Image I/O — how images get in and results out
|
||
|
||
An `image` argument accepts one of:
|
||
- `file:/abs/path` — a file **on the server** (testing only; e.g. `file:/tmp/amm_test/2-zuoshang.bmp`).
|
||
- `<key>` — a minio object key in the default bucket `halcon` (e.g. `inbox/die.png`).
|
||
- `minio://<bucket>/<key>` — explicit bucket.
|
||
|
||
Or pass `image_b64` (inline base64, may include `data:` prefix) — best for a **single small image**, no upload step.
|
||
|
||
Results: numeric metrics come back **inline** (structuredContent). Heavy artifacts (preview jpg, CSV) are
|
||
uploaded to minio and returned as a **key + presigned URL** on the **public** host `minio-home.totoro.studio`
|
||
(openable from anywhere). Small files (preview/CSV) — just GET the URL.
|
||
|
||
## Three usage patterns (pick by size)
|
||
|
||
**1. Single small image → inline (simplest).**
|
||
```
|
||
halcon_measure_overlay(image_b64="<base64 of the bullseye image>")
|
||
→ {status:"ok", overlay_dX_um, overlay_dY_um, top/bottom centers, n_circles}
|
||
```
|
||
|
||
**2. Single/few images from an external client → presigned PUT (no creds).**
|
||
```
|
||
k = halcon_create_upload(filename="die.bmp") # → {put_url, key}
|
||
curl -T die.bmp "<put_url>" # public PUT, no creds
|
||
halcon_measure_overlay(image=k.key)
|
||
```
|
||
|
||
**3. Large batch (hundreds–thousands) → zip once, then process (recommended).**
|
||
Zip is the right move: one file = one upload = works with presigned PUT (external users too),
|
||
vs mirroring many files (needs minio creds).
|
||
```
|
||
zip -0 -q -j batch.zip *.png # store mode (PNG already compressed)
|
||
k = halcon_create_upload(filename="batch.zip")
|
||
curl -T batch.zip "<k.put_url>" # one PUT
|
||
halcon_find_circles_zip(zip_key=k.key) # server unzips + batch + CSV
|
||
→ {total, ok, seconds, per_image_ms, csv_key, csv_url}
|
||
# then GET csv_url
|
||
```
|
||
CSV columns: `file,status,n_found,TL_col,TL_row,TL_r,TR_...,BL_...,BR_...` (4 ring-mark centers per image, ordered by position).
|
||
|
||
## D2W overlay conventions (this project's domain)
|
||
|
||
- Axes: **X = image right +, Y = image up +**; pixel size **271.048 nm/px**; overlay = **Bottom − Top**.
|
||
- Mark grouping: outer thick ring = **Top Die Mark**; inner dot + mid ring = **Bottom Die Mark**.
|
||
- `apply_registration=True` adds the +13.5/+9.6 nm offset (0627-JC 2-point calibration; drop for other tools/batches).
|
||
- Sanity values (die-2 four corners, raw dev µm): TL −0.778/+0.794 · TR −0.265/+0.391 · BL −0.171/+1.022 · BR +0.230/+0.435.
|
||
|
||
## Performance (measured, single HALCON process, 16 threads)
|
||
|
||
- find_circles on 5312×4608 (24MP): **~92 ms/image** (~11 img/s). 1920 images ≈ **176 s compute**.
|
||
- 90 MB zip public PUT: ~20 s. End-to-end 1920 images ≈ **3.3 min**.
|
||
- Circle-center repeatability across 1920 shots: std **0.01–0.04 px**.
|
||
|
||
## Gotchas
|
||
|
||
- **Sync execution.** `halcon_find_circles_zip` / `halcon_overlay_batch` run synchronously. ~1920 images (~3 min)
|
||
is near the comfortable ceiling — set a **long client timeout**. For much larger jobs, chunk or use async (not yet built).
|
||
- **License `SESSIONS=1`** → cannot multi-process; rely on HALCON's internal 16-thread parallelization (already fast).
|
||
- **Preview/CSV URLs use `minio-home.totoro.studio`** (public), not the internal `192.168.1.2:9000` — openable off-LAN.
|
||
- **Big batches:** always zip (one PUT). Per-file `create_upload` for N files is N round-trips — only for a handful.
|
||
- **`file:` paths are server-side**, not the client's filesystem — only for images already on `192.168.1.13`.
|
||
- Tool errors return `isError` + an actionable message (e.g. "先用 halcon_create_upload 传图") — read it and self-correct.
|