TÀI LIỆU ĐƯỢC HỖ TRỢ BỞI AI
Bạn muốn biết điều gì?
Recipe Script
Recipe script là một đoạn mã JavaScript ngắn chạy sau các tool trên mỗi lần inspection của một recipe. Nó có thể:
- quyết định pass hoặc fail bằng logic của riêng bạn, và nêu lý do
- ghi các byte của riêng bạn cho User Results của PLC
- lưu metadata và tags cùng với capture, để bạn có thể tìm thấy chúng trong Library
Mỗi recipe có nhiều nhất một script, và nó được export cùng với recipe.
Mở trình chỉnh sửa
Tại bước Judgment của recipe, cuộn đến Recipe script và nhấp Open script editor.

Ở đầu bước Judgment, bạn chọn thứ quyết định kết quả: các rule hoặc recipe script. Các rule luôn chạy, và script nhìn thấy kết quả của chúng. Nếu bạn để thiết lập ở các rule, script không thể thay đổi pass hoặc fail, nhưng lý do, metadata, tags và các byte PLC của nó vẫn được áp dụng. Đó là cách bắt đầu an toàn: thêm một script cho lý do và các byte, và giữ các rule phụ trách.

Cách nó chạy
Trigger → Capture and tools → Pass/fail rules → inspect(input) → Verdict, PLC User Results, Library, MQTT
Script export một hàm duy nhất, inspect(input). Camera gọi nó trên mỗi inspection của recipe, sau các tool và các rule. Dây chuyền chờ nó, vì vậy nó phải đồng bộ và nhanh: nó có 25 ms theo mặc định, lên đến 200 ms trong Settings của script, và thời gian của nó cộng vào thời gian chu kỳ.
input chứa mọi thứ cho đến thời điểm này. Nó chỉ đọc:
| Trường | Nó là gì |
|---|---|
tools | Kết quả của từng tool, theo thứ tự các tool đã chạy |
tools_by_name | Cùng các kết quả, theo tên tool |
rules | Kết quả của các rule: judgment, pass, not_inspected |
vars | Variables của bạn theo tên. Một biến không có giá trị là null |
vars_info | Cho mỗi biến: received_at, age_ms và source |
recipe | id, uuid và name |
trigger | id, source (ví dụ plc, gpio, http, manual) và metadata |
Mỗi kết quả tool có name, type, judgment, pass, score, plc_slot, execute_ms, error, skipped_by, và một đối tượng detail có hình dạng phụ thuộc vào tool. Hãy kiểm tra type trước khi bạn đọc detail, ví dụ ai_fast_classifier (với detail.regions), ai_ocr (với detail.fields), ai_counting (với detail.count) hoặc classical.barcode (với detail.data).
Nó trả về gì
Mọi trường đều tùy chọn. Trường bạn bỏ đi sẽ giữ hành vi bình thường của camera, vì vậy một script có thể chỉ đặt lý do và để verdict cho các rule. Trả về không có gì để không thay đổi gì cả.
| Trường | Ý nghĩa | Giới hạn |
|---|---|---|
judgment | "pass", "fail" hoặc "not_inspected" (true, false và null có cùng ý nghĩa). Chỉ được sử dụng khi bước Judgment được đặt thành recipe script | |
reason | Văn bản hiển thị trong Library và gửi trong các thông báo kết quả (MQTT, HTTP API, camera script) | 64 ký tự |
plc_user_results | Các byte cho User Results của PLC, thường được xây dựng bằng pack() | Kích thước User Results đã cấu hình |
metadata | Các cặp khóa-giá trị được lưu cùng capture và hiển thị trong chi tiết Library của nó. Các khóa là chữ cái, chữ số và dấu gạch dưới, bắt đầu bằng một chữ cái; giá trị là văn bản, số hoặc true/false | 32 khóa, giá trị văn bản lên đến 256 ký tự |
tags | Nhãn hiển thị dưới dạng chip trong Library, nơi bạn có thể lọc theo chúng | 16 tags, mỗi tag 32 ký tự |
export function inspect({ tools_by_name, vars }) {
const ocr = tools_by_name["Serial"];
if (ocr?.type !== "ai_ocr" || !ocr.detail) {
return { judgment: false, reason: "no OCR result" };
}
const expected = vars["serial"];
if (typeof expected !== "string") {
return { judgment: null, reason: "serial not received" };
}
const read = ocr.detail.fields.map((f) => f.text_judged).join("");
const match = read === expected;
return { judgment: match, reason: match ? "serial matches" : "serial differs" };
}
Hãy thử
Khu thử nghiệm script của recipe
Thay đổi chi tiết, chỉnh sửa script, nhấn Run. Script nhận cùng đầu vào mà camera truyền cho inspect() và chạy theo cùng các quy tắc.
Một công cụ AI Classification với 10 vùng, mỗi vùng cho một chân. Nhấp vào một chân để đảo trạng thái.
Hiển thị đối tượng đầu vào
{
"recipe": {
"id": 3,
"uuid": "01a15a44-9a3c-72bb-ab4f-5481cce20093",
"name": "Sample recipe"
},
"trigger": {
"id": 4182,
"source": "plc",
"metadata": {}
},
"rules": {
"judgment": "fail",
"pass": false,
"not_inspected": false
},
"vars": {},
"vars_info": {},
"tools": [
{
"type": "ai_fast_classifier",
"id": "01a1-pins",
"name": "Pins",
"plc_slot": 1,
"judgment": "fail",
"pass": false,
"score": 0.9,
"execute_ms": 6,
"error": "none",
"skipped_by": "",
"detail": {
"regions": [
{
"label": "Pin 1",
"class_label": "seated",
"confidence": 0.97,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 2",
"class_label": "seated",
"confidence": 0.93,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 3",
"class_label": "seated",
"confidence": 0.95,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 4",
"class_label": "bent",
"confidence": 0.81,
"verdict": "fail",
"threshold": 0.5,
"pass": false
},
{
"label": "Pin 5",
"class_label": "seated",
"confidence": 0.91,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 6",
"class_label": "seated",
"confidence": 0.96,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 7",
"class_label": "seated",
"confidence": 0.94,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 8",
"class_label": "seated",
"confidence": 0.89,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 9",
"class_label": "seated",
"confidence": 0.98,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 10",
"class_label": "seated",
"confidence": 0.92,
"verdict": "pass",
"threshold": 0.5,
"pass": true
}
],
"overall": "fail"
}
}
],
"tools_by_name": {
"Pins": {
"type": "ai_fast_classifier",
"id": "01a1-pins",
"name": "Pins",
"plc_slot": 1,
"judgment": "fail",
"pass": false,
"score": 0.9,
"execute_ms": 6,
"error": "none",
"skipped_by": "",
"detail": {
"regions": [
{
"label": "Pin 1",
"class_label": "seated",
"confidence": 0.97,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 2",
"class_label": "seated",
"confidence": 0.93,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 3",
"class_label": "seated",
"confidence": 0.95,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 4",
"class_label": "bent",
"confidence": 0.81,
"verdict": "fail",
"threshold": 0.5,
"pass": false
},
{
"label": "Pin 5",
"class_label": "seated",
"confidence": 0.91,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 6",
"class_label": "seated",
"confidence": 0.96,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 7",
"class_label": "seated",
"confidence": 0.94,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 8",
"class_label": "seated",
"confidence": 0.89,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 9",
"class_label": "seated",
"confidence": 0.98,
"verdict": "pass",
"threshold": 0.5,
"pass": true
},
{
"label": "Pin 10",
"class_label": "seated",
"confidence": 0.92,
"verdict": "pass",
"threshold": 0.5,
"pass": true
}
],
"overall": "fail"
}
}
}
}Nhấn Run để xem kết quả mà lần inspection này sẽ cho ra.
Mô phỏng trong trình duyệt của bạn. Trên camera, hãy dùng Test trong trình soạn thảo script để chạy bản nháp trên các ảnh chụp thực tế trước khi lưu.
Ghi byte cho PLC
Trả về plc_user_results, được xây dựng bằng pack(layout, values). PLC đọc nó cùng với kết quả, trước cạnh Inspection Completed.
Mô tả các byte một lần dưới dạng layout: một danh sách có thứ tự các trường { name, type }.
| Loại | Số byte |
|---|---|
u8, i8, bool | 1 |
u16le, u16be, i16le, i16be | 2 |
u32le, u32be, i32le, i32be, f32le, f32be | 4 |
u64le, u64be, i64le, i64be, f64le, f64be | 8 |
bits với count | Một bit cho mỗi giá trị, giá trị đầu tiên ở bit thấp nhất |
ascii hoặc utf8 với length | Văn bản, được đệm hoặc (với truncate: true) cắt theo độ dài |
bytes với length | Các byte thô |
pad với length | Các byte zero, để bỏ qua một khoảng trống |
const OUT = [
{ name: "regionOk", type: "bits", count: 80 },
{ name: "count", type: "u16le" },
];
export function inspect({ tools_by_name }) {
const classifier = tools_by_name["Classifier"];
if (classifier?.type !== "ai_fast_classifier" || !classifier.detail) return;
const regionOk = classifier.detail.regions.map((r) => r.pass).slice(0, 80);
return { plc_user_results: pack(OUT, { regionOk, count: regionOk.length }) };
}
Mỗi loại nhiều byte đặt tên cho thứ tự byte của riêng nó, và camera không bao giờ hoán đổi byte cho bạn. Sử dụng các loại le trên EtherNet/IP và các loại be trên PROFINET. Việc kiểm tra script cảnh báo khi một loại không khớp với fieldbus của camera.
- Byte 0 nằm ở byte 288 của input assembly trên EtherNet/IP, và ở byte 0 của module User Results trên PROFINET. Phần còn lại của vùng được đặt về zero
packném raRangeErrorkhi một giá trị không khớp với trường của nó. Hãy kiểm tra với một part fail trước khi lưuunpack(layout, bytes)đọc lại các byte, vàcrc(bytes, "crc16-modbus" | "crc32")tính toán checksum
Khi có điều gì đó sai
Nếu inspect ném lỗi, hết thời gian, hết bộ nhớ (8 MiB), hoặc trả về thứ gì đó mà camera không thể chấp nhận (chẳng hạn như lý do dài hơn 64 ký tự hoặc judgment: "PASS"):
- part được đánh dấu là Not inspected
- User Results của PLC được đặt về zero
- không có gì nó trả về (lý do, metadata, tags) được sử dụng
- lỗi được lưu cùng capture, để bạn có thể xem nó trong Library
Các giá trị được giữ ở cấp module chỉ tồn tại cho đến khi recipe được tải lại, ví dụ sau khi lưu. Không đếm part hoặc giữ lịch sử trong recipe script. Hãy sử dụng camera script, nó giữ state giữa các sự kiện.
Những gì recipe script không thể làm
- Không có network, không có timer và không chờ đợi: không có
fetch,setTimeout,importhoặceval, vàinspectkhông thể làasync - Nó không thể nhìn thấy chính hình ảnh, chỉ thấy kết quả của các tool
- Nó đọc thế giới bên ngoài chỉ thông qua
inputvà các biến
Templates
Thư viện Templates có 14 script hoạt động, được nhóm theo công việc. Chọn một, điền vào tool hoặc biến mà nó sử dụng, và Insert template.

| Nhóm | Templates |
|---|---|
| Quyết định pass hoặc fail | Pass khi đủ các ROI pass · Số serial khớp với văn bản OCR · Barcode bằng với một biến · Số lượng trong dung sai của một biến |
| Chọn thời điểm inspect | Bỏ qua các loại part khác · Bỏ qua khi một biến thiếu hoặc lỗi thời |
| Gửi dữ liệu đến PLC | Gửi số lượng dưới dạng số 16-bit · Đóng gói các cờ pass/fail của ROI · Gửi mã kết quả cho mỗi tool |
| Giải thích kết quả | Đặt tên tool đã fail · Đưa số lượng vào lý do |
| Gắn nhãn cho các capture | Thêm metadata và một tag review · Gắn tag cho các trường hợp gần miss để review · Lưu một biến với mỗi capture |
Test và History
- Test chạy bản nháp trên một Trigger trực tiếp, hoặc trên các capture đã lưu: mới nhất, N cuối cùng (lên đến 500), bộ lọc Library, hoặc số capture. Nó hiển thị nơi verdict của bản nháp khác với verdict mà mỗi capture đã ghi lại, để bạn thấy nó sẽ quyết định điều gì trước khi nó đi vào hoạt động
- History giữ 20 phiên bản đã lưu gần đây nhất của bạn
Viết script khi bước Judgment vẫn ở các rule, và sử dụng Test trên các capture đã lưu để so sánh verdict của nó với những gì đã được ghi lại. Chỉ chuyển sang recipe script khi chúng không đồng ý ở nơi bạn muốn chúng đồng ý.
Tiếp theo đi đâu
- Camera script, cho bất cứ điều gì cần network hoặc bộ nhớ qua các part
- Variables
- Bước 5: Judgment
- PLC Handshakes, cho khi PLC đọc User Results