Chuyển đến nội dung chính

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.

Bước Judgment: pass/fail được quyết định bởi các rule hoặc recipe script, với sơ đồ về những gì chạy trên mỗi inspection

Ở đầ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.

Trình chỉnh sửa Recipe script

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ườngNó là gì
toolsKết quả của từng tool, theo thứ tự các tool đã chạy
tools_by_nameCùng các kết quả, theo tên tool
rulesKết quả của các rule: judgment, pass, not_inspected
varsVariables của bạn theo tên. Một biến không có giá trị là null
vars_infoCho mỗi biến: received_at, age_ms và source
recipeid, uuid và name
triggerid, 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ĩaGiớ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
reasonVă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_resultsCá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
metadataCá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/false32 khóa, giá trị văn bản lên đến 256 ký tự
tagsNhãn hiển thị dưới dạng chip trong Library, nơi bạn có thể lọc theo chúng16 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.

Chi tiết mẫu
OK/NG được quyết định bởi
Fieldbus

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.

Kết quả kiểm tra đến thời điểm này
Các quy tắc cho biết: Không đạt
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"
      }
    }
  }
}
Script của recipe

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ạiSố byte
u8, i8, bool1
u16le, u16be, i16le, i16be2
u32le, u32be, i32le, i32be, f32le, f32be4
u64le, u64be, i64le, i64be, f64le, f64be8
bits với countMột bit cho mỗi giá trị, giá trị đầu tiên ở bit thấp nhất
ascii hoặc utf8 với lengthVăn bản, được đệm hoặc (với truncate: true) cắt theo độ dài
bytes với lengthCác byte thô
pad với lengthCá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 }) };
}
Khớp thứ tự byte của fieldbus

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
  • pack ném ra RangeError khi 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ưu
  • unpack(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
Giữ state trong camera script

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, import hoặc eval, và inspect khô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 input và 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.

Thư viện Templates của Recipe script

NhómTemplates
Quyết định pass hoặc failPass 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 inspectBỏ 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 PLCGử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 captureThê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
Bắt đầu ở chế độ Rules

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​