A robot program that asks for X, Y, rotation and score receives one long string of characters instead. The socket opened, the camera answered, and the four numbers sit inside the buffer along with delimiters and a line terminator. This is the standard failure when a vision system and a robot controller first talk over TCP, and it is a message-format problem, not a network one. Below you get the causes ranked by how often each turns out guilty, a test for each, the ASCII contract that removes the ambiguity, and the byte arithmetic that tells you exactly how long a correct line must be.
The symptom: one buffer where you expected four numbers
The read call returns everything it received as text: values, delimiters and terminator in one string. On a UR10e the call is socket_read from the URScript socket family, and it hands back the buffer as received — it never splits or assigns anything. A line such as 212.40,158.00,-45.2,99.8 arrives complete, all four numbers present, yet the script has no boundaries to assign from. Some readers wrap the numbers in a native frame first: a qualifier, a length, a checksum. The socket did its job. The two ends never agreed on where one value stops and the next begins, so the parse has nothing to hold on to.
Rank the causes, then test each
Run down the table in order; the first three explain most failed integrations.
| # | Likely cause | What you see | Test that settles it |
|---|---|---|---|
| 1 | The reader sends its native frame, not plain ASCII | Qualifier or checksum text around the numbers | Capture the raw bytes with a PC client and print <LF> and <CR> as visible markers |
| 2 | Delimiter or terminator mismatch: semicolons, CRLF, quotes | Token count off by one, or the last token refuses to convert | Count the separators in the captured line against the contract below |
| 3 | The buffer is never split, or the list lands in one variable | Token count prints as 1 | Print the token count; a correct line gives exactly 4 |
| 4 | Conversion rejects a sign or a decimal point | Fails only on targets rotated left: -45.2 breaks where 45.2 passed |
Feed a test line holding a minus sign and two decimals |
| 5 | Two results stacked in one buffer, or a stale tail | Byte count near double, or values one cycle old | Send once, read once, compare the byte count to the budget in the worked example |
The fix: one line, four fields, one terminator
Agree this contract on both ends and the ambiguity disappears. The vision side sends, per request, exactly one line of plain ASCII:
- Four fields in fixed order: X and Y in pixels, R in degrees, P in percent — the four values the application defines.
- Comma delimiter, newline terminator (
\n), no header, no checksum, no quotes. - Fixed decimals: two on X and Y, one on R and P. Fixed width keeps every line the same length to the byte.
- A sign on R where the rotation is negative, and P between 0 and 100.
The robot side then runs the same five steps every cycle:
- Open the socket once at program start and reuse the connection.
- Write the request, then read with a timeout — never without one.
- Strip the terminator and any stray carriage return, then split at every comma.
- Require exactly 4 tokens; on anything else, log the raw line, skip the cycle and re-trigger.
- Convert each token as a signed decimal, assign X, Y, R and P, and gate the move on your score threshold.
Step 3 is the same field-splitting pattern used to split barcode string data into fields for lot and part numbers, so the parsing habits from code reading carry straight over.
If reads come back empty or the send loop stalls instead, the sequencing fault sits on the robot side: robot socket communication with no response fixes the send-then-read loop.
Worked example: parsing 212.40,158.00,-45.2,99.8 from a 25-byte line
The inputs and where each comes from: X = 212.40 px and Y = 158.00 px are the target's pixel coordinates, R = -45.2 degrees its rotation, P = 99.8 % its match score — the four values the application defines. The format follows the contract above, so the line on the wire is 212.40,158.00,-45.2,99.8\n.
The rule, in words: the line length equals the sum of the field widths, plus one comma between each pair of fields, plus one byte for the terminator. The token count equals the commas plus one.
The arithmetic:
- Field widths:
212.40= 6 bytes,158.00= 6,-45.2= 5 (three digits, one dot, one sign),99.8= 4. - Separators: 4 fields need 3 commas = 3 bytes; the terminator adds 1.
- Line length = 6 + 6 + 5 + 4 + 3 + 1 = 25 bytes.
- Tokens = 3 + 1 = 4.
The same arithmetic brackets every legal line. The shortest is 0,0,0,0\n at 4 + 3 + 1 = 8 bytes. The longest keeps X and Y at 7 bytes each — four integer digits and two decimals, which covers the 2560 x 2048 pixel positions a 5 MP sensor can address — with R at -180.0 = 6 bytes and P at 100.0 = 5 bytes: 7 + 7 + 6 + 5 + 3 + 1 = 29 bytes. A read between 8 and 29 bytes that yields 4 tokens is a well-formed result; a read near 58 bytes is two results stacked; anything outside the bracket means the sender has drifted from the contract.
Result: the 25-byte read splits into exactly 4 tokens and converts to X = 212.40 px, Y = 158.00 px, R = -45.2 degrees, P = 99.8 %. Decision: accept the cycle only when the byte count sits inside 8 to 29, the token count is 4 and every token converts as a signed decimal; this cell then gates the pick at P of 95 % or better and skips and re-triggers below it.
Mistakes that survive the first test
-
A carriage return left on the score. A sender that ends lines with
\r\nleaves99.8\r, and the conversion rejects the token. Strip both characters before splitting or after. -
A decimal comma from the vision side.
99,8turns 4 tokens into 7 and shifts every mapping. Fix the decimal point at the sender; never teach the robot parser two formats. -
Rotation only ever tested positive. Targets left of the reference give
-45.2. Parse signed from the first test, not after a field failure on the line. - Slicing by byte offset instead of splitting. One extra digit shifts every later field. Split on the delimiter and check the count; offsets only survive with fixed-width frames and disciplined senders.
- Leftover bytes from the previous cycle. Without a strict request-answer rhythm the buffer holds a tail and every value arrives one cycle old. The send-then-read sequencing in the no-response fix linked above prevents it.
The same line often feeds a second consumer. A PLC reading those bytes must split them as ASCII text, not consume them as four floating-point words — parsing ASCII frames as bytes instead of float words shows that failure on the PLC side.
What the four values are worth on the robot
P is the gate. The score says how far the pattern match trusted itself, and the pick decision should hang on it: below the qualified score, skip the cycle rather than move to a shaky target. Barcode read confidence: judging whether a decode is trustworthy gives the criteria for a threshold that survives production variation.
X and Y arrive in pixels; the robot moves in millimetres. One scale-and-offset calibration bridges them: record the pixel pairs for three known robot positions, fit millimetres per pixel and the origin offset, and the pair converts from then on. R drives the gripper rotation directly once the sign convention is fixed. The full read-and-map walk-through is reading X, Y, angle and score from a vision camera over a UR socket.
The routing half — what to do with a parsed quadruple — follows the same pattern as routing a barcode reader result to robot job selection: the numbers index the next job, pallet or bin pick.
What sends the line: the vision side
Any camera-side device with an Ethernet port and a configurable ASCII output can serve this contract. A compact reader handles location results from codes; a vision controller runs full vision jobs and, with several Ethernet ports, keeps the camera network and the robot link physically apart.
The MV-ID3013PM-12M-WBN pairs a 12 mm lens with a 1.3 MP global-shutter sensor on Fast Ethernet with an M12 mount — a reader you set to emit the plain line format above.
- Interface
- Fast Ethernet
- Resolution
- Up to 3 MP
- Shutter
- Global
- Lens mount
- M12
For a cell where the robot link must not share the camera network, the MV-SVC2506-16G60-128G separates traffic by design: 4 camera GigE ports, 1 configuration GigE port and 1 communication GigE port.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 2 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 16 GB
Multi-camera cells fit the MV-VC3301H-128G66, which runs the vision software with its license included and leaves spare Ethernet ports for the robot link.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
Browse the fixed code readers and the vision controllers ranges for the rest of both classes; the robotics guides collect the surrounding integration articles.
Before you go live
-
Known-line round trip. Send
212.40,158.00,-45.2,99.8\nfrom the camera or a PC stand-in; the robot must report 25 bytes and 4 tokens. That proves the contract, not just the cable. -
Negative rotation and no-find. Run a target at
-45.2, then remove the target; the robot must convert the sign and skip cleanly. The no-find case is where unbounded reads freeze. - Byte count every cycle. Log the read length for 100 cycles; it must read 25 each time. Drift means a format change or a stacking buffer.
- Camera-dead test. Kill the camera mid-run; the read must time out, log and resume. This catches the freeze before the line does.
- Second consumer. If a PLC or MES reads the same line, check it splits text the same way — one format, two parsers, no surprises.
If the camera side is fixed and cannot emit plain ASCII, send us its frame layout through the contact page and we will match a reader or controller that speaks the line format directly.
Questions
How do I test the result string before the robot is programmed?
Put a PC in the loop in both directions. As a client, connect to the camera's IP address and port, send one trigger and print the reply with carriage return and line feed shown as visible markers, so you see the exact bytes. As a server, have the PC send the known line to the robot program and confirm it parses 4 tokens — the parser gets proven before the camera format is final.
How many bytes should one vision result line be?
For the comma-separated line format above, between 8 and 29 bytes: the shortest legal line is `0,0,0,0` plus its terminator at 8 bytes, and the longest is two 7-byte pixel fields, a 6-byte rotation and a 5-byte score plus separators. The 25-byte worked example is the budget to log each cycle; a count near double that means two results are stacked in the buffer.
How do I turn pixel X and Y into robot millimetres?
One scale-and-offset calibration. Move a target to three known robot positions, record the pixel pairs the camera reports for each, and fit the millimetres-per-pixel scale and the origin offset from the pairs; extra points expose scale error that lens distortion would otherwise hide. R then drives the gripper rotation directly once you have fixed which direction counts as positive.
What timeout should the socket read use?
Set it above the camera's worst answer time — exposure plus processing plus network, normally well under one second in a triggered cell — so a typical setting of 1 to 5 s rides out slow cycles without stalling production. Keep the timeout as a program variable: on timeout, log the state, skip the pick and re-trigger, so a dead camera costs one cycle instead of the program.
Why does my camera send a header before the numbers, and can I keep it?
The header belongs to the reader's native output frame — qualifier, length or sequence data meant for its own tools. You can keep it when the wrapper has a fixed length: strip those bytes, then split what remains. Simpler and safer is to switch the vision job's result output to plain ASCII, one comma-separated line per request, which is the four-field format parsed above.


