Skip to content

Cookbook: SICK Inspector Results over TCP ​

Last updated

A SICK Inspector (or any vision sensor that sends a text result per part) decides pass or fail itself. This recipe brings those results into Scada.Ink: running counts, pass rate, a consecutive-failure alarm, a log table and a station dashboard.

Example result string, one line per inspected part:

text
PASS;12.48;25.01;0.02
FAIL;12.58;24.93;0.08

Fields: result, measurement 1 (mm), measurement 2 (mm), deviation (mm). Adapt the parsing to whatever your camera sends.

How it fits together ​

PartScada.Ink featureJob
ReceiveA Raw TCP deviceKeeps a TCP connection to the camera and puts the latest result line into a tag
ProcessA script with a Tag Change trigger, using a libraryParses the line, updates counters, writes a log row
StoreLocal tags and a data tableCounters survive restarts; every result is kept
AlertAn alarm rule on a local tagThree failures in a row raises a critical alarm
ShowA dashboardResult, pass rate, measurements, trend, log, reset button

Read this first: what the pieces can and can't do ​

  • The workflow Send TCP node only sends. It never reads a reply and sets no variable, and it sends \r\n as four literal characters. It can't be used to trigger the camera and collect the result.
  • Scripts have no TCP client. They can't open a socket to the camera.
  • The Raw TCP driver is what can read a TCP device. It polls: on every poll it reads whatever the camera has sent (or sends a request and reads the reply). It does not act on data the moment it arrives, so a result appears in Scada.Ink up to one poll cycle later.
  • The camera must be the TCP server (Scada.Ink connects to it). If your camera can only connect out to a server, this recipe won't work.
  • The Raw TCP driver doesn't notice a dropped connection. After the camera restarts, click Disconnect then Connect on the device page.

Step 1: Set up the camera ​

In SICK's configuration software for your model:

  1. Configure the camera to output a result string over Ethernet after each inspection, with the camera acting as TCP server. Note the port.
  2. Set the output format to the fields you need, separated by ;, ending with a line break.
  3. If the output can include a running inspection counter, add it. It makes two identical results in a row distinguishable (see "Fast lines" below).
  4. Trigger inspections the way the line needs — usually a photo-eye wired to the camera's trigger input.
  5. Note the camera's IP address, e.g. 192.168.10.50.

Menu names, the result-output port and command syntax differ between SICK models and firmware; follow SICK's manual for these settings.

Step 2: Add the camera as a Raw TCP device ​

  1. Devices → Add Device → under HTTP / Custom choose Raw TCP.
  2. Device Name Inspector 1, IP Address 192.168.10.50, Port the camera's result port (e.g. 2006), Polling Rate (ms) 200. Click Next twice (the machine details are optional), then Create Device.
  3. Note the device id from the address bar of its page, e.g. /devices/9.
  4. Set its driver configuration through the API (there is no form for it — see Advanced Driver Settings for signing in and getting $TOKEN):
bash
curl -s -X PUT "$APPLIANCE/api/devices/9" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"driverConfig":{"encoding":"ascii","read_timeout":1,"tags":[{"path":"Inspector/Result","data_type":"string"}]}}'
  1. On the device page click Disconnect, then Connect.
  2. Manage Tags → Add Tag: Tag Path Inspector/Result, Data Type string, Display Name Result line → Subscribe.

The tag has no request, so on each poll the driver waits up to read_timeout seconds for data from the camera:

On a pollTag becomes
A result line arrivedThe line, e.g. PASS;12.48;25.01;0.02, quality good
Nothing arrived within read_timeoutEmpty, quality Bad
Several results arrived since the last pollAll of them in one value, separated by line breaks (up to 1,024 bytes)

So between parts the tag flips to empty/Bad. That's expected, and it's what lets the next result fire the script even when it is identical to the previous one. Don't tick History on this tag.

Fast lines ​

The script fires when the tag's value or quality changes. If two identical results arrive with no empty poll between them, the second is missed. Keep read_timeout well under the time between parts (here 1 s for parts every 2 s or more), or include a counter in the result string so consecutive lines always differ.

Step 3: Create the local tags ​

Local Tags → New Tag for each row, then Confirm.

Tag PathData TypeDefault ValuePersist
sick/resultstring
sick/m1float0
sick/m2float0
sick/deviationfloat0
sick/totalint0ticked
sick/pass_countint0ticked
sick/fail_countint0ticked
sick/pass_ratefloat0ticked
sick/fail_streakint0ticked
sick/reset_requestint0

Note the id of the Local Tags device on the Devices page; Step 8 needs it.

Step 4: Create the log table ​

Data Tables → New → Table name inspection_log (admin only):

Column nameTypeReq
resulttextticked
m1real
m2real
deviationreal
stationtext

Step 5: Put the parser in a library ​

  1. Scripts → Libraries → New Library, name sick, Create.
  2. Paste the code, click Save.
javascript
// Library "sick": parse one result line "PASS;12.48;25.01;0.02"
exports.parseResult = function (line) {
  const parts = String(line).trim().split(';');
  if (parts.length < 4) return null;

  const result = parts[0].trim().toUpperCase();
  if (result !== 'PASS' && result !== 'FAIL') return null;

  const m1 = parseFloat(parts[1]);
  const m2 = parseFloat(parts[2]);
  const deviation = parseFloat(parts[3]);
  if (isNaN(m1) || isNaN(m2) || isNaN(deviation)) return null;

  return { result: result, m1: m1, m2: m2, deviation: deviation };
};

exports.inTolerance = function (value, nominal, tolerance) {
  return Math.abs(value - nominal) <= tolerance;
};
  1. In the Test panel type return sick.parseResult('FAIL;12.58;24.93;0.08'); and click Run Test. Returned shows the object.

A library is loaded into every script. A syntax error in it breaks every script, so test before saving, and don't declare a variable called sick in any script. See Script Libraries.

Step 6: Write the processing script ​

  1. Scripts → New Script → SICK Result Processor → Create.
  2. Trigger tab: Type Tag Change, Device ID 9 (the Raw TCP device), Tag Path Inspector/Result.
  3. Paste the code, toggle Enabled, click Save.
javascript
const raw = context.value;
if (!raw) return; // an empty poll (nothing arrived) also fires this trigger

const LOCAL = devices.localId();
function readNum(path) { return Number(tags.read(LOCAL, path) || 0); }

const lines = String(raw).split('\n');
for (const line of lines) {
  if (line.trim() === '') continue;

  const r = sick.parseResult(line);
  if (!r) {
    console.warn('Unrecognized result line: ' + line);
    continue;
  }

  const pass = r.result === 'PASS';
  const total = readNum('sick/total') + 1;
  const passes = readNum('sick/pass_count') + (pass ? 1 : 0);
  const fails = readNum('sick/fail_count') + (pass ? 0 : 1);
  const streak = pass ? 0 : readNum('sick/fail_streak') + 1;

  tags.write('sick/result', r.result);
  tags.write('sick/m1', r.m1);
  tags.write('sick/m2', r.m2);
  tags.write('sick/deviation', r.deviation);
  tags.write('sick/total', total);
  tags.write('sick/pass_count', passes);
  tags.write('sick/fail_count', fails);
  tags.write('sick/fail_streak', streak);
  tags.write('sick/pass_rate', Math.round((passes / total) * 1000) / 10);

  await db.insert('inspection_log', {
    result: r.result, m1: r.m1, m2: r.m2, deviation: r.deviation, station: 'Inspector 1',
  });
}
  • tags.write always writes a local tag, and tags.read returns text, hence the Number().
  • A script failure shows a "Script Failed" toast and the error on the script's Log tab.
  • Runs can overlap if results arrive faster than a run finishes. At normal line rates a run takes milliseconds.

Step 7: Alarm on three failures in a row ​

Alarms → Alarm Rules → New Rule:

FieldValue
NameInspector 1 fail streak
DeviceLocal Tags
Tagsick/fail_streak
ConditionGreater than
Threshold2
SeverityCritical
Message (optional)3 or more consecutive inspection failures on Inspector 1

It fires on the third failure, stays active while failures continue, and clears on the next pass (the streak goes back to 0). To text someone when it fires, attach a pipeline — see the SMS recipe.

Note: A script can also raise an alarm directly with alarms.notify('warning', 'title', 'message'), but that alarm has no rule, so it can't run a pipeline or text anyone. Use an alarm rule on a local tag when someone needs to be paged.

Step 8: A reset button operators can use ​

The reset goes through a local tag, so the script decides what a reset does and the button needs nothing but a tag write.

  1. Scripts → New Script → SICK Reset Counters. Trigger: Tag Change, Device ID = the Local Tags device id, Tag Path sick/reset_request.
javascript
if (context.value !== '1') return;

['sick/total', 'sick/pass_count', 'sick/fail_count', 'sick/fail_streak', 'sick/pass_rate']
  .forEach(function (path) { tags.write(path, 0); });

tags.write('sick/reset_request', 0); // fires this script again; it returns at the first line
log('Inspection counters reset');
  1. Toggle Enabled, Save.
  2. On the dashboard (next step) add a Button: Button Label Reset counters, Action Write Tag, Write Tag sick/reset_request, Write Value 1, Confirm before action on.

Step 9: Build the station dashboard ​

Dashboards → New Dashboard → Inspection Station 1. Bind each widget's value to the local tag shown.

WidgetTitleTagConfiguration
StatusLast resultsick/resultDelete the default rules; add = equals PASS → text PASS, green; = equals FAIL → text FAIL, red. Shape Circle
ValuePass ratesick/pass_rateUnit %, Decimals 1, Font Size Extra Large (leave Format Automatic — Percent expects a fraction)
ValueInspectedsick/totalUnit parts
ValueFail streaksick/fail_streakFlash Alert: trigger tag sick/fail_streak, ≥ at least 3, red
StatusM1 12.50 ± 0.05sick/m1One rule ↔ between 12.45 / 12.55 → IN TOL, green; Default Text OUT OF TOL, Default Color red
ValueM1sick/m1Unit mm, Decimals 3
ValueM2sick/m2Unit mm, Decimals 3
ChartM1 trendsick/m1Time Window (s) 600
Data TableLast 15 inspectionsnoneTable Name inspection_log, Max Rows 15
ButtonResetnoneAs in Step 8

A Gauge's Warning and Critical are one-sided percentages of the scale, so they can't show a ± tolerance band; the between status rule does.

The live Chart adds a point only when the value changes. For long-term trending of M1, tick History for sick/m1 under Devices → Local Tags → Manage Tags, and use a History Chart or SPC.

Variations ​

SituationWhat to do
The camera answers a trigger command with the result on the same connection, and you want it to inspect continuouslyGive the tag a request in the driver configuration, e.g. "request": "TRG\r\n" (JSON turns \r\n into a real CR/LF). Every poll then sends the command and reads one line — one inspection per poll, whether or not a part is there
The camera offers an HTTP/JSON interfaceUse the HTTP / REST API driver with json_path per value — see HTTP, JSON, XML and Raw TCP devices
You want Scada.Ink to do the inspection from the camera's imagesSee Machine Vision; SICK is one of the camera types

Troubleshooting ​

SymptomCauseFix
Inspector/Result is always empty/BadNo driverConfig, tag path doesn't match tags[].path, wrong port, or the camera isn't sendingCheck the PUT body, then Disconnect/Connect; test the port from a PC with a TCP terminal
Stopped updating after the camera rebootedRaw TCP doesn't detect a closed connectionDisconnect then Connect
Counters jump by 2 for one partThe camera sends the result twice, or two results were read in one poll and both were processed (correct)Check the camera output; compare with the camera's own counter
Identical consecutive results counted onceNo empty poll between themLower read_timeout, or add a counter to the result string
Script log: Unrecognized result lineFormat differs from RESULT;m1;m2;devChange sick.parseResult
Every script on the appliance failsError in the sick libraryFix the library; use Run Test
Script never runsWrong Device ID, not enabled, or not savedUse the Raw TCP device's numeric id; Enabled + Save
Reset button: "Local tag not found"sick/reset_request doesn't existCreate it on the Local Tags page

See also ​

Scada.Ink Help Center