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.
|