System designHow-to

USB barcode scanner on a Linux controller: serial port in Node-RED

Put a USB barcode scanner into serial mode, find /dev/ttyACM0 or ttyUSB0 on Linux, and read scans in Node-RED or a PLC, with a byte-level worked example.

LumaSpec Vision9 min read Share on LinkedIn

On this page 11 sections
  1. 01What you need
  2. 02Step 1: programme the scanner to USB serial mode
  3. 03Step 2: find the port and clear permissions
  4. 04Step 3: read the port in Node-RED
  5. 05Step 4: read the port in the PLC
  6. 06Worked example: Hello World arriving as 13 bytes
  7. 07Four failures and their fixes
  8. 08When USB serial is the wrong path
  9. 09Before you hand it to production
  10. 10Where to go next
  11. 11Questions

A USB barcode scanner looks like a keyboard to most Linux systems, and that is exactly wrong when the consumer is a controller: the keystrokes go nowhere and the PLC never sees the code. Put the scanner into USB serial mode and the same device appears as a port file, /dev/ttyACM0 or /dev/ttyUSB0, that Node-RED or a PLC program can open and read one scan at a time. This guide takes you through both read paths on a Linux controller: programming the scanner, finding the port, wiring the serial in node or the PLC serial library, and proving the link with a byte-level test you can repeat after every change.

What you need

  • A scanner that can be programmed to USB serial mode (also labelled COM port emulation or CDC-ACM). Most handheld scanners ship in USB keyboard (HID) mode; the mode codes sit in the interface chapter of the scanner's user guide.
  • A Linux controller with a USB host port and either Node-RED or an IEC 61131-3 runtime: an edge box, an industrial PC, or a vision controller.
  • A test barcode: print Hello World as a Code 128 or QR symbol.
  • Ten minutes.

If you are also choosing the scanner itself, these two read USB out of the box:

Fixed code readersCompact fixed industrial barcode reader, 1.2 MP, USB 2.0, 60-120 mm reading distance (LS-CRD-0047)LS-CRD-0047
Resolution
Up to 3 MP
Shutter
Global
$559.00View part
Handheld code readersHandheld industrial barcode reader, 1.0 MP, USB 2.0 (LS-HCR-0001)LS-HCR-0001
Resolution
Up to 3 MP
Shutter
Global
$539.00View part

The LS-CRD-0047 is a fixed reader with a 60-120 mm reading distance and a 1.2 MP sensor; the LS-HCR-0001 is a 1.0 MP handheld, and both speak USB 2.0.

Step 1: programme the scanner to USB serial mode

  1. In the scanner's user guide, find the interface chapter and scan the configuration code for USB serial mode.
  2. Scan the suffix code that adds CR and LF if the guide offers one. The terminator is what lets a receiver tell one scan from the next; the framing choices are covered in the prefix and suffix framing guide.
  3. Unplug and replug the scanner so Linux re-enumerates it. A port a program already holds keeps the old identity until you do.

Step 2: find the port and clear permissions

Plug the scanner into the controller's USB host port and read the kernel log:

dmesg | tail

A scanner that speaks CDC-ACM registers as /dev/ttyACM0. A scanner or adapter that bridges through a USB-to-serial chip registers as /dev/ttyUSB0. If both names exist, unplug the scanner, run the command again, and the name that disappears is yours. On a single-board controller the port may need host or OTG mode first; the USB host OTG guide covers that case.

Then check permissions and prove the stream:

ls -l /dev/ttyACM0
cat /dev/ttyACM0

Substitute your port name. Scan the test barcode: the raw text should print, followed by an invisible carriage return and line feed. Ctrl+C stops the read. If cat answers Permission denied, the port belongs to the dialout group; add yourself to it with sudo usermod -aG dialout $USER, log out, and log in again.

Step 3: read the port in Node-RED

  1. From the palette manager, add the serialport palette so the serial in node exists, then drop a serial in node and a debug node onto the sheet and wire them together.
  2. Double-click the serial in node, name it Scanner, set the serial port to /dev/ttyACM0, and leave the line settings at 9600 8N1: the field needs a value, but a CDC-ACM port moves data at USB speed and ignores the baud number.
  3. Set splitting to the character \n so each scan arrives as one message ending at the line feed.
  4. Press Deploy. The node's status turns to connected, and from then on one scan produces one debug message carrying Hello World.

A few scanner families stream a binary TLV protocol instead of plain ASCII. Search the palette manager for a scanner-specific community node: the Node-RED library lists nodes that handle that framing for you, and the node's own documentation tells you which scanner families it covers.

Step 4: read the port in the PLC

Linux-based PLC runtimes reach a serial port through a COM library; where SysCom is that library, add SysCom and the settings library CmpSettings in the library manager, then:

  1. Write a three-state program. State 0 opens and configures the port with the same 9600 8N1 line settings as in Step 3. State 1 reads bytes into a BYTE buffer every cycle and watches for the terminator, byte 13 or 10. A third state copies the bytes into a STRING and clears the buffer.
  2. Download and start the program, then write the run flag online: SysCom example programs drive the loop with a flag such as iState, set from 0 to 1 with the online-write command (Ctrl+F7 in the IDEs that use it).
  3. Restart the controller once after any change to the port settings; the new settings apply only on the restart.
  4. Scan the test barcode. The STRING variable shows Hello World and the byte buffer holds the decimal values decoded in the worked example below.

Decimal-to-character is a fixed mapping, and the PLC-side byte, word and string handling is covered in the guide to storing ASCII barcode strings in PLC memory.

Worked example: Hello World arriving as 13 bytes

The inputs:

  • Payload Hello World: 11 characters, 10 letters and 1 space — the test barcode.
  • Terminator CR then LF, ASCII 13 and ASCII 10 — the scanner suffix scanned in Step 1.
  • Character codes H = 72, e = 101, l = 108, o = 111, space = 32, W = 87, r = 114, d = 100 — the ASCII table.

The rule: one scan on the wire is payload bytes plus terminator bytes, and it reaches your program as one message only when the splitter fires on the last terminator character.

11 characters + 2 terminator bytes = 13 bytes per scan

The bytes on the wire:

72 101 108 108 111 32 87 111 114 108 100 13 10

The result: Node-RED delivers one message whose payload is the 11-character string Hello World, with the 13-byte buffer behind it; the PLC byte buffer holds the same decimals, and 72 101 108 108 111 spells Hello.

The decision: 13 bytes in one message means the framing is correct. Thirteen messages of one byte each mean the splitter is off, so set it to \n. Nothing at all points to permissions or the wrong port name (Step 2). Text landing in some other window means the scanner is still in HID keyboard mode, and the HID or serial decision guide covers when each mode is the right one.

Four failures and their fixes

Symptom Likely cause Test Fix
Nothing arrives Port name wrong, user outside dialout, or scanner still in HID mode Cat the port and scan; watch where keystrokes land Re-run dmesg, join dialout, rescan the USB serial mode code
One byte per message Splitter disabled or set to fixed buffers Debug pane shows 13 separate 1-byte messages Split on the character \n
Payload has a trailing CR CR left over from a CR plus LF suffix Payload length reads 12 instead of 11 Trim the trailing CR in one function node, or programme an LF-only suffix
Garbage characters Real RS232: baud or parity mismatch. CDC-ACM: a symbology identifier prefix is switched on Compare raw bytes against the ASCII table Match the serial settings; switch the prefix off in the scanner configuration

The serial-link half of that last row is covered in the garbage characters guide.

When USB serial is the wrong path

For a line-side install, an Ethernet reader removes the serial step entirely:

Fixed code readersHikrobot MV-ID3013PM-12M-WBN 12mm focal length 1.3 MP Compact Industrial Code ReaderMV-ID3013PM-12M-WBN
Interface
Fast Ethernet
Resolution
Up to 3 MP
Shutter
Global
Lens mount
M12
$1,979.00View part

Before you hand it to production

  • Mode: the scanner answers on USB serial, the CR plus LF suffix is scanned, and keystrokes are gone.
  • Port: the name recorded from dmesg is pinned in the node or program, not guessed.
  • Permissions: the account running Node-RED or the PLC runtime is in dialout.
  • Framing: the splitter is on \n, and one scan of the test code produces one 13-byte message.
  • PLC: the state machine opens the port before the read loop starts, and the controller was restarted after the last settings change.
  • One consumer: Node-RED or the PLC holds the port, never both.

Where to go next

Pick hardware in the code reader finder or build the whole station in the configurator; the reader accessories category covers protective covers, mounts and light boards for the install. More controller-side integration notes sit on the systems topic page, and if the scanner-to-controller choice is still open, contact us with the controller model and the symbology you need to read.

Questions

Does the baud rate matter for a USB CDC-ACM scanner port?

No. A CDC-ACM port is a USB device and moves data at USB speed, so the 9600 in the node or PLC library is ignored. Leave 9600 8N1 anyway: it is the default most scanner manuals document, and it keeps the configuration valid if the same scanner later moves to a real RS232 port, where a baud mismatch shows up as garbage characters.

Can Node-RED and the PLC read the same USB scanner at once?

No. A serial port allows a single open handle: whichever program opens /dev/ttyACM0 first keeps it, and the second open fails or the two programs steal each other's bytes. Pick one consumer. If both need the code, read it in one place and hand the string onward over the link you already run, such as MQTT or an OPC UA tag.

What terminator should I programme into the scanner?

CR plus LF is the safest pair for a Linux read: split on the LF and trim the trailing CR once. A single CR also works if you split on CR, and it saves the trim step. Avoid no terminator at all: without one, the serial node can only guess message ends from timeouts, which merges fast repeat scans into one string.

How long can the USB cable between scanner and controller be?

The USB 2.0 specification allows a 5 m cable per segment. Past that, enumeration becomes unreliable. For a longer run, put a powered hub or an active extension in the middle, or switch to an Ethernet code reader and carry the decode over TCP, which is the normal choice wherever the read point sits more than a few metres from the controller.

Why did the scanner stop typing into my HMI after I set USB serial mode?

USB serial mode replaces keyboard emulation, so the scanner now writes bytes to the port file and nothing to the focused field. That is expected, not a fault. To return to keystrokes, scan the USB keyboard configuration code from the same guide. On mixed lines, many teams keep two scanners: one HID for HMI fields and one serial for the controller.

My code reader only has an Ethernet port. What replaces the serial read?

Open a TCP socket instead. Most fixed industrial code readers push each decode as ASCII over TCP or UDP with the same CR/LF framing, so Node-RED's TCP in node or a socket library in the PLC replaces the serial node with no other change to your framing logic. Set the reader's destination IP and port in its configuration tool, then repeat the 13-byte test.