System designHow-to

Vision coordinate array to PLC over Modbus TCP: sizing the registers

Pack a vision coordinate array into 16-bit Modbus TCP holding registers: two per float32, word order agreed with the PLC, block sized so the write never fails.

LumaSpec Vision11 min read Share on LinkedIn

On this page 9 sections
  1. 01How many registers does one coordinate need?
  2. 02How do you pack a float into two 16-bit registers?
  3. 03How large should the register block be for the whole array?
  4. 04How do you send the array, step by step?
  5. 05How do you check the PLC reads the right number?
  6. 06Why does the send fail with a length error?
  7. 07When is one register per coordinate enough?
  8. 08Which hardware sends the array to the PLC?
  9. 09Questions

Your vision system has found ten positions and the PLC wants them in holding registers — not a screenshot, and not a string it has to parse blind. Modbus TCP moves everything as 16-bit registers, so the whole task is sizing the block and packing each number into it correctly. This guide gives you the register count per coordinate, the byte layout of a float32, a worked ten-point array with the arithmetic on the page, the send sequence, and the two checks that catch a length error or a scrambled number before the line does. It is written for anyone wiring a vision controller or smart camera to a PLC over Modbus TCP for the first time, or debugging a transfer that fails on send.

How many registers does one coordinate need?

Two registers per coordinate if you send an IEEE-754 float32 — the 32 bits split across two 16-bit holding registers — or one register per two characters if you send text, plus a further register whenever a terminator pushes the character count to odd.

A holding register is 16 bits wide; that is the unit the Modbus data model defines, and protocol addresses run 0 to 65,535. A float32 coordinate is 32 bits, and 32 ÷ 16 = 2, so every X and Y lands in a register pair. Every 32-bit integer (DINT) does the same. Text is different: a register holds two 8-bit characters, so the count is characters ÷ 2, rounded up.

Take the coordinate 11.123 used throughout this guide. As text it is six characters — 0x31 0x31 0x2E 0x31 0x32 0x33 — so it fills three registers: 0x3131, 0x2E31 and 0x3233. Add a semicolon and it is seven characters, which rounds up to four registers with the last byte zero-padded. The same number as a float32 needs two registers and no parsing on the PLC, which is why the float pair is the default.

registers per float32 = 2 registers per text = ceil(character count / 2) array block = 2 × points + counter + result flag

How do you pack a float into two 16-bit registers?

Split the 32-bit IEEE-754 pattern into two words and send them high-word-first or low-word-first exactly as your PLC stores its REALs — pick one order, note it on the interface drawing, and never let the two ends disagree.

11.123 as a float32 is the byte pattern 41 31 F7 D1. Sent big-endian — the usual Modbus convention, labelled ABCD — register N holds 0x4131 (16689 as an unsigned integer) and register N+1 holds 0xF7D1 (63441). Many PLC platforms store REALs low word first (CDAB) and expect 0xF7D1 at N. Send ABCD into a CDAB PLC and it reassembles 0xF7D14131, which decodes as about −1.4 × 10³⁴ instead of 11.123 — the classic "array arrives but every number is garbage" symptom.

Label Word order Register N Register N + 1
ABCD high word first 0x4131 0xF7D1
CDAB low word first 0xF7D1 0x4131
BADC bytes swapped inside each word 0x31F7 0xD141
DCBA all four bytes reversed 0xD141 0x31F7

If the PLC documentation does not state the order, send 11.123 once and read the two registers back with function 3; the row they match in the table is your order.

How large should the register block be for the whole array?

Twenty data registers for ten float32 coordinates, plus one frame counter and one result flag: a 22-register block covers the worked array below and still fits in a single Write Multiple Registers request, which carries at most 123 registers.

Worked example, five picks at two coordinates each:

  • Coordinates X1, Y1 … X5, Y5: 10 values as float32
  • Data registers: 10 × 2 = 20
  • Frame counter (uint16, +1 per new result): 1 register
  • Result flag (1 pass, 0 fail): 1 register
  • Block total: 20 + 1 + 1 = 22 registers, addresses 0–21, shown as 40001–40022 in one-based tools
  • One function 16 request: 22 ≤ 123 registers, and 22 × 2 = 44 data bytes, inside the 246-byte payload limit
Registers (one-based) Addresses Content
40001–40020 0–19 X1, Y1 … X5, Y5 as float32 pairs
40021 20 Frame counter, +1 per result
40022 21 Result flag: 1 pass, 0 fail

The counter is what turns a register dump into a hand-shake: the PLC acts only when it changes, which means the 44 bytes were written as one consistent frame. The conventions around that trigger — latch, acknowledge, re-trigger — are laid out in Send vision coordinates to a PLC through a register handshake.

A 100-point array does not fit one request: 200 + 2 = 202 registers breaks the 123 cap, so split the map into a 123-register and a 79-register block, each with its own counter. Keep the payload numbers, not images; the reasoning is in Vision system to PLC: send pass-fail results, not images.

How do you send the array, step by step?

Fix the map, pack the bytes, write the block in one function 16 request, then bump the counter — six steps that take an afternoon from an empty PLC to a robot calling a pick.

  1. Agree the map with the PLC programmer: base address, word order, counter and flag positions. One line: "float32 ABCD, data 0–19, counter 20, flag 21".
  2. Round each coordinate to the resolution the robot needs — 0.001 mm covers any pick — and convert to float32 bytes; 11.123 becomes 41 31 F7 D1.
  3. Write all 22 registers in one function 16 (0x10) request to the PLC's Modbus TCP server on port 502, with the unit ID the server is configured for.
  4. Read the block back with function 3 (0x03) and compare against what you sent, before the line runs.
  5. Increment the frame counter only after the write returns without an exception — the counter is the PLC's signal that these 44 bytes are new.
  6. On an exception, stop and read the code: 02 means address or quantity sits outside the declared block, 03 means a field value is illegal. Fix the map, then re-send once; do not retry in a blind loop.

How do you check the PLC reads the right number?

Send one known value, 11.123, and expect 0x4131 in the first register and 0xF7D1 in the second: swapped words mean the byte order is wrong, and 16689 with 63441 as plain integers means the PLC is reading the block as two INTs instead of one REAL.

The next trap is the address convention. One-based tools display protocol address 0 as register 40001; a tool that treats displayed numbers as protocol addresses shifts the whole map by one register, and X1 lands in Y1's slot. Write one value at address 0 and watch 40001 move — that pins the convention in ten seconds.

Then watch it live: the counter increments once per part, not once per poll; X values sit inside axis travel; Y reads as Y. A float32 carries about seven decimal digits, so 11.123 round-trips as 11.1230006 — a 0.0000006 mm difference that no pick can feel.

Why does the send fail with a length error?

The write asks for more registers than the declared block holds: a text coordinate such as "11.123;" needs four registers, and a send sized for two comes back with exception 02, illegal data address.

Both ends declare a size. The vision tool declares how many registers one send carries; the PLC server declares the map it exposes. Text grows silently: "11.123" is 3 registers, "11.123;" is 4, and a new pick added to the array turns 22 registers into 24. Any of those writes past a stale declaration, and the server rejects it.

Count before you configure: floats × 2, characters ÷ 2 rounded up. A ten-number text array such as "11.123,82.560,…;" runs about 70 characters, and 70 ÷ 2 = 35 registers — against 20 as floats, plus parsing on the PLC side. When several vision devices feed one PLC, size each block to its own payload and keep the addresses apart; the single-CPU polling pattern is in Multiple vision cameras on Modbus TCP: one PLC CPU, one poll loop.

When is one register per coordinate enough?

When a scaled integer covers the travel: 0.01 mm per bit reaches ±327.67 mm in one register, halving the block, while 0.001 mm per bit still fits a 16-bit INT out to ±32.767 mm.

The arithmetic: ±32,767 counts × 0.01 mm = ±327.67 mm, and ±32,767 × 0.001 mm = ±32.767 mm. The decision: float32 by default, because it needs no scaling agreement and never overflows; int16 when the block is tight and travel plus margin sits inside ±327.67 mm; ASCII only for a legacy consumer that expects characters.

Encoding Registers per value Example range PLC type
float32 2 ±3.4 × 10^38, no scaling REAL
int16 scaled 1 ±327.67 mm at 0.01 mm/bit INT
int32 scaled 2 ±2,147,483 mm at 0.001 mm/bit DINT
ASCII "11.123;" 4 any text width STRING

Negative int16 values ride as two's complement: −1112 counts (−11.12 mm at 0.01 mm per bit) shows as 0xFBA8, and a PLC reading that word unsigned displays 64424 — another garbage pattern with an exact cause. A PLC with no Ethernet port takes the same payload as characters on a serial wire; the layout is in Send vision results to a PLC with a fixed-position RS232 telegram.

Which hardware sends the array to the PLC?

Any GigE vision device with a Modbus TCP client or server can do the job: a smart camera writes its own result registers straight to the PLC, while a vision controller runs the vision and the Modbus traffic together and keeps a dedicated port for the wire.

Plan the network first: image streams on one subnet, the PLC link on another, so a burst of frames never delays a register write. For a multi-camera station that usually means a controller with several Ethernet ports.

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$2,419.00View partBuild a system with it

The MV-VC3301H-128G66 carries 5+ LAN ports, so cameras and the PLC link sit on separate networks, with PCIe expansion if the application grows.

Some controllers give the PLC a port that never sees image traffic.

Vision controllersHikrobot MV-SVC2506-16G60-128G 4 camera GigE ports, 1 configuration GigE port, 1 communication GigE port, 6100pro encryption supportedMV-SVC2506-16G60-128G
LAN ports
5+ LAN ports
USB 3 ports
2 USB 3 ports
Light outputs
4 built-in channels
Memory
16 GB
Price on requestView and quoteBuild a system with it

The MV-SVC2506-16G60-128G names the split explicitly: 4 camera GigE ports, 1 configuration GigE port and 1 communication GigE port, so the register writes never compete with frame data.

A station that locates one part and hands over two coordinates can skip the PC entirely, provided the camera itself offers a Modbus TCP server — many smart cameras and vision sensors do, and the same map and packing rules apply on the device.

Smart cameras & vision sensorsHikrobot MV-SC3050XC-16M-ATN-H 5 MP color vision sensorMV-SC3050XC-16M-ATN-H
Interface
Fast Ethernet
Resolution
5 MP
Sensor format
1/1.45"
Shutter
Global
$1,809.00View part

The MV-SC3050XC-16M-ATN-H is that class of part: a 5 MP color sensor on Fast Ethernet that inspects at the machine and ships numbers upstream.

The controller-side set-up — IP, unit ID, register map, read and write functions — is walked through step by step in Vision controller Modbus communication: a PLC integration guide.

The decision, one line each: floats at two registers per coordinate unless the block is tight; word order agreed on the drawing and proven with 11.123; one block per vision device, sized once and changed on both ends together. When the hardware is the open question, the vision controllers and smart cameras pages narrow the field quickly, or send the register map you have in mind through the contact page and we will check it against your machine before you order.

Questions

Which Modbus function codes move a coordinate array?

Write Multiple Registers, function 16 (0x10), carries the whole array in one request — up to 123 registers and 246 data bytes. Function 6 (0x06) writes a single register, such as a trigger. Function 3 (0x03) reads holding registers back for checking. Functions 5 and 15 address coils, not holding registers, so they never appear in a coordinate transfer.

What does Modbus exception 02 mean when the array write is rejected?

Exception 0x02, illegal data address: start address plus quantity lands outside the register map the PLC exposes — usually the array grew and the declared block did not. Exception 0x03, illegal data value: a field such as the register count is zero or over 123. Enlarge the block on both ends or split the write, then resend.

How do I send negative coordinates or values above 65,535?

Float32 carries the sign in its top bit, so −11.123 mm needs no special handling. Scaled int16 uses two's complement: ±32,767 counts cover ±327.67 mm at 0.01 mm per bit. Cast a negative count to unsigned and the PLC reads about 64,000 instead of −1,112 — if that pattern appears, the data type on one end is wrong. Above 16-bit range, move to int32 across two registers.

Can one PLC connection serve several vision devices?

Give each vision device its own block — different addresses on one connection, or separate IP addresses or unit IDs — and poll them in turn from one CPU. Two devices writing the same addresses corrupt each other's arrays silently, and a shared counter cannot say whose numbers are fresh. One counter per block, one base address per device.

What is the difference between address 100 and register 40101?

Convention: protocol addresses run 0 to 65,535, and many tools prefix holding registers with a one-based 4xxxx offset, so protocol address 100 displays as 40101. A tool that treats the displayed number as the protocol address shifts the whole map by one register. Send one known value at address 0, watch 40001 move, and the convention is pinned.