A color blob detection that only draws on the preview has told the display everything and told your program nothing. The data is already in the camera: the detection call returns a list of blob objects, and one assignment line puts that list in a variable you own. From there the job is copying, packing and writing. Pull the centroid and bounding box out of each blob, wrap them in a header-payload-checksum frame, and write the frame to the serial port once per processed frame. You will leave with the assignment line, the byte layout, the 115200 baud arithmetic, and a receiver parser for the microcontroller on the other end. Every step runs on the camera itself, so the whole chain is detection, variables, frame, UART.
Where does the camera store the color blobs it finds?
Nowhere special: the detection call returns a list of blob objects. The line blobs = find_blobs(...) already stores every colored region it found in that one variable, ready to index, loop over, and copy field by field into your own numbers.
The preview image is downstream of your code. The detection function computes the region list first, then draws its rectangles from that list, so nothing about the result lives only on the display. Assign the return value to a name and the objects are yours to index and copy.
blobs = find_blobs(img) # illustrative name: your firmware's function list has the exact spelling
n = len(blobs) # int: number of colored regions found this frame
The list lives in camera RAM for the rest of the script cycle. When the script loops and detection runs again, the new assignment replaces the old list, so copy out what you need before the next frame. n is also the value you will later write into the frame's count byte, which is why the assignment happens once per processed frame, not once per loop.
Which blob values do you copy into your own variables?
Four numbers carry almost every application: the centroid (cx, cy) for position, the bounding box (x, y, w, h) for size and cropping, and the pixel count for filtering noise. Declare one set of variables per blob and copy them out before the next frame replaces the list.
Blob analysis exposes a standard set of region properties: centroid, bounding box, pixel count or area, often perimeter and orientation as well. Copy the fields you actually use into plain variables immediately; the attribute names in the snippet are illustrative, but every embedded vision API prints these same properties for its blob object.
blobs = find_blobs(img) # list: one blob object per colored region
blobs.sort(key=pixel_count) # illustrative: sort so blobs[0] is the largest region
biggest = blobs[0] # blob object
cx = biggest.center_x # number: centroid column, pixels
cy = biggest.center_y # number: centroid row, pixels
x, y, w, h = biggest.box # ints: bounding box x, y, width, height
Test the copy before wiring anything: aim the camera at one colored patch centred in a 320 × 240 frame and expect n == 1 with cx and cy within ±2 pixels of 160 and 120. If the centroid lands half a pixel off your expectation, that is the coordinate-origin convention, covered in half-pixel offset in blob centroid: pixel coordinate origin.
How do you pack several blobs into one serial frame?
Use a fixed frame: one header byte, a fixed-size payload of little-endian integers, and one checksum byte, so a two-blob message is 19 bytes and the receiver can resync after any glitch; text lines work for debugging but cost roughly twice the bytes.
| Field | Bytes | Example |
|---|---|---|
| Header | 1 | 0xAA, marks the frame start |
| Blob count N | 1 | 2 |
| Per blob: cx, cy, w, h | 8 × N | four 16-bit little-endian integers |
| Checksum | 1 | low byte of count + values |
For N = 2 that is 1 + 1 + 16 + 1 = 19 bytes. Each UART byte carries 8 data bits, so every 16-bit value leaves as a low byte followed by a high byte; fix that order on both ends and never change it. The checksum is the low byte of the sum of the count plus all value bytes. It costs almost nothing on either side and rejects a corrupted frame.
uart = serial_port(baud=115200, bits=8, parity=None, stop=1) # illustrative name
frame = bytearray()
frame.append(0xAA) # header byte
frame.append(n) # blob count
for b in blobs[:n]: # the n largest regions
cx = int(b.center_x) # int: centroid column
cy = int(b.center_y) # int: centroid row
w = b.box[2] # int: bounding box width
h = b.box[3] # int: bounding box height
frame += cx.to_bytes(2, "little") # low byte first
frame += cy.to_bytes(2, "little")
frame += w.to_bytes(2, "little")
frame += h.to_bytes(2, "little")
frame.append(sum(frame[1:]) & 0xFF) # checksum: count + values, low byte
uart.write(frame) # once per processed frame
A text line works for bring-up: b"1,160,120,44,38\n" carries the same numbers and any terminal program shows it. The same header-payload discipline, on a PLC link instead of a microcontroller, is worked through in send vision results to a PLC with a fixed-position RS232 telegram.
How long does one frame take to send at 115200 baud?
At 115200 baud 8N1 a byte takes 86.8 µs, so the 19-byte two-blob frame finishes in 1.65 ms, about a tenth of the 16.7 ms frame period a 60 fps camera allows.
The 10 bits per byte are one start, eight data and one stop bit, the 8N1 setting, so 115200 baud moves 11520 bytes per second. The minimal heartbeat of header, one value and checksum costs about 260 µs, and the write call queues its bytes and returns at once, so the 1.65 ms drains while your script starts on the next frame.
For a concrete budget, the LS-SMC-0063 is a 1.6 MP smart camera with a 16 mm lens and a 60 fps rating.
- Interface
- GigE
- Resolution
- Up to 3 MP
How do you wire the camera's serial lines to the microcontroller?
Cross the data lines, share the ground, and match the logic levels: camera TX goes to microcontroller RX, camera RX to microcontroller TX, signal ground to signal ground, and both ends must run the same 8N1 setting.
Find TX, RX and GND in the camera's I/O pinout, then bring them out on an open-ended cable you can wire to screw terminals or a header. The cables category lists the power and I/O breakouts, and the cables finder filters them by connector and length.
The LS-CBL-0300 is an M8 8-pin power and I/O cable, male to open end with 8 cores, 7 m long and rated for drag-chain use; wire its open ends straight to the microcontroller terminals.
- Type
- Power and I/O cables
- Length
- 6-8 m
For the SC6000 series the fit is a 17-pin connector: the MV-SCA-P-M12A17pF-open-ST-7m runs the M12 A-coded 17-pin connector out to open leads over 7 m, static duty.
- Type
- Smart Camera Power and I/O Cables
Keep the run short and referenced: a metre or two inside a cabinet with a shared ground is comfortable at 115200 baud, and twisted pair with a ground conductor between the signals keeps noise down. To pick the cable and trigger extras in one pass, start the system configurator at the extras step.
What are the steps, end to end?
Six steps take a fresh camera to a working link: detect and store, sort and copy, build the frame, write it once per frame, parse on the microcontroller, and verify with a target at frame centre; each step below is the whole job in miniature.
- Run color detection once per captured frame and store the whole return value: blobs = find_blobs(img).
- Sort the list by pixel count, largest first, then copy cx, cy, w and h into plain variables.
- Build the frame: 0xAA header, count byte, little-endian value bytes, checksum byte.
- Configure the port for 115200 baud, 8N1, and write the frame once per processed frame, not once per loop.
- On the microcontroller, run the hunt-collect-checksum state machine from the next section.
- Verify end to end: hold one colored target centred in a 320 × 240 frame; the microcontroller should report n = 1 and cx ≈ 160, cy ≈ 120.
Blob objects carry more than the four fields used here; count lines per region automatically with blob analysis shows one inspection built on the same list.
What does the receiver-side parser look like?
A three-state loop: hunt for the 0xAA header, read the count byte plus 8×N payload bytes plus the checksum, and accept the values only when the checksum matches; anything else resets the state machine.
state = "hunt" # str: "hunt" until the header byte arrives
buf = [] # list of ints: bytes collected so far
n = 0 # int: blob count claimed by the frame
def on_byte(b): # b: int, one byte from the UART
global state, buf, n
if state == "hunt":
if b == 0xAA:
buf = [b]
state = "collect"
return
buf.append(b)
if len(buf) == 2:
n = buf[1] # int: blob count
if len(buf) == 2 + 8 * n + 1:
if sum(buf[1:-1]) & 0xFF == buf[-1]:
unpack_blobs(buf[2:-1], n) # your code: read 2-byte little-endian pairs
state = "hunt" # frame complete or corrupt: hunt again either way
Two details decide reliability. Bytes can be lost mid-frame, so never wait forever for a count that may never come: if the expected bytes do not arrive within one frame period, reset to hunt. And when characters arrive but mean nothing, the cause is almost always baud rate, parity or a missing ground; the symptom-by-symptom fixes are in garbage characters from a barcode scanner: fix the PLC serial link, and the failure mode is identical on any UART.
For text-based links without a header byte, the framing tricks in barcode scanner to an HMI serial port: framing data without headers transfer directly to this parser.
When is serial the wrong link for blob results?
Serial fits one small message per frame; when you push tens of blobs, images themselves, or distances beyond a few metres at high rates, move the same variables onto Ethernet, which every GigE smart camera already has.
The budget from above caps serial at about 192 bytes per 16.7 ms period, roughly 23 blobs of 8 payload bytes each. Beyond that, or when the receiver needs the image itself, put the same frame bytes into a UDP or TCP payload on the camera's Ethernet port; the receiver code barely changes and cable length stops mattering.
The MV-SC3050XC-16M-ATN-H is a 5 MP color vision sensor with a global shutter and an M12 lens mount, one of the smart cameras that inspect on the device; the camera finder filters them by interface, resolution and shutter.
- Interface
- Fast Ethernet
- Resolution
- 5 MP
- Sensor format
- 1/1.45"
- Shutter
- Global
When the microcontroller must ask and answer rather than just listen, a request-response library over the same two wires saves you writing the protocol; keep the one-way frame for fixed-rate streams. To plan camera, lens and trigger together, start the configurator at the camera step; if the chain still will not close, the contact page reaches the applications team. Serial-protocol guides beyond this one are gathered on the code-reading topic page.
Questions
Can I send the blob list as text instead of binary?
Yes. Print the same fields as one comma-separated line, for example 1,160,120,44,38, and end it with a newline; a terminal shows it directly, which makes bring-up faster. Text costs roughly twice the bytes of a binary frame and needs a parser on the receiver, so most teams debug in text, then switch to the fixed binary frame for production.
How many blobs can one frame carry at 60 fps?
About 190 bytes per frame period at 60 fps: 115200 baud moves 11520 bytes per second, and one 60 fps period lasts 16.7 ms, so 11520 × 0.0167 ≈ 192 bytes. With 8 payload bytes per blob plus 3 frame bytes, that is roughly 23 blobs per frame before the link runs out of time.
What logic levels do camera serial pins use?
Camera I/O pins usually switch at the controller's own logic level, and 3.3 V CMOS is the most common; an RS-232 port is different, swinging several volts negative and positive. Read both pinout tables before the first connection, and put an RS-232 transceiver chip between the camera and a microcontroller if either side speaks RS-232.
What happens if the two ends use different serial settings?
You get bytes that arrive but mean nothing: wrong baud rate, stop bits or parity corrupt nearly every character, and the parser never finds the 0xAA header. Set both ends to the same rate, 8 data bits, no parity, one stop bit; if characters still look wrong, the fixes are in the serial-link checklist for garbage characters.
Does a PC have to sit in the loop?
No. The detection, the variables and the UART write all run in the camera's own script, so the microcontroller is the only other device in the chain; a PC is only for editing and debugging the script. Cameras that lack a serial port can still send the same frame bytes over Ethernet instead.



