Automation / Serialization

All projects

Laser Etcher Modernization

I replaced a deprecated, network-dependent etching package with an in-house Ignition system that marks glass from the production schedule.

$143K+ per implementation11 lines / 5 plants (rollout target)5,000 records/batch
Ignition PerspectivePython/JythonSQLTCP / DynamarkPLC

01

Problem

PPS, a deprecated Java-based etching package, depended on the network. When PPS or the network went down, lasers stopped etching to schedule: during one outage about 60,000 units shipped unetched, Venice went months unable to etch, and Stayton's etcher was beyond repair. Stayton was the only site without etching on a standard production line. The permanent etch identifies who made a unit, what it is, and where it was built, and traces back to its order and line. When labels are missing, it is the last ID left; it also supports warranty and customer care, IG certification, and brand.

02

Approach

I built a full-stack Python/Ignition replacement in house, deployed and supported on a local Ignition server. Titan ERP exports the production schedule as CSV to a network path; Ignition watches for new files and loads them into SQL. A Perspective HMI presents the batch. As each glass lite rides the float table, the DL05 PLC detects its position and triggers the Domino laser with the current record's data; the exit sensor advances the record. The gateway owns the Dynamark TCP conversation and waits for each response before sending the next command, preventing replies from getting scrambled. Etching runs locally without an internet dependency.

Operator HMI and diagnostics

Laser Etcher operator HMI showing the schedule, sequence search, rework controls, record paging, live etch preview, and record values. Select the image to inspect it at a larger size.
Laser Etcher operator HMI showing the schedule, sequence search, rework controls, record paging, live etch preview, and record values
Dynamark state-machine diagnostics view with machine states, transition legend, and live etcherAI_P.writeToEtcher log. Select the image to inspect it at a larger size.
Dynamark state-machine diagnostics view with machine states, transition legend, and live etcherAI_P.writeToEtcher log
Laser etcher and operator HMI installed beside the glass production table. Select the image to inspect it at a larger size.
Laser etcher and operator HMI installed beside the glass production table

03

Architecture

Titan ERP schedules arrive as CSV and load into SQL. Perspective presents the batch; the DL05 detects glass position and advances records, while the local Ignition gateway serializes Dynamark commands to the Domino laser and waits for each response.

Laser Etcher Modernization architectureSanitized block diagram of data flow for Laser Etcher Modernization.Titan ERPCSV scheduleIgnition / SQLCSV ingestPerspective HMIOperatorGatewayetcherAI_PDynamark TCPOne commandDomino laserEtch markDL05 PLCGlass present / advance
Laser Etcher overhaul
Supporting production workflow
Laser Etcher functional test

04

Implementation

I built the Ignition and Python software; controls and mechanical partners handled the laser and float-table integration. Dynamark is a text protocol over TCP port 20000, terminated by CR/LF; replies are OK, RESULT, or ERROR n. On startup, the gateway loads the label and subscribes to SETMSG 1–5, 12, and 26. Its state machine covers DISCONNECTED, INITIALIZING, IDLE/READY, TX IN FLIGHT, WAITING MSG 26, PRINTING (MSG 2 to MSG 3), NOT READY (MSG 4/12), and FAULT (ERROR, TCP loss, or MSG 5). The CommandQueue, EtcherBusy, EtcherFaulted, and isConnected tags support this flow. A diagnostics view shows the state diagram and live etcherAI_P.writeToEtcher log for multi-session debugging. The operator HMI includes schedule selection, Start/Stop, Cycle-Start/Send-to-Print, Mark-Done and Mark-Reject, Show Rework, a live etch preview with record values, and paging through batches of about 5,000 records (about 500 pages). I added Sequence Search after operators requested it on the floor. Etch content is standardized, including the JW prefix and AAMA certification information, so it can replace the separate AAMA Gold sticker.

etcherAI_P.pySanitized Jython excerpt. Tag paths and label name are placeholders.
TCP_WRITE_TAG = "[provider]PLACEHOLDER/Etcher/Write"
COMMAND_QUEUE_TAG = "[provider]PLACEHOLDER/Etcher/CommandQueue"
ETCHER_BUSY_TAG = "[provider]PLACEHOLDER/Etcher/EtcherBusy"
ETCHER_FAULTED_TAG = "[provider]PLACEHOLDER/Etcher/EtcherFaulted"

def writeToEtcher(command):
    system.tag.writeBlocking([TCP_WRITE_TAG], [command + "\r\n"])

def setMsgsTrue(message_types):
    return ["SETMSG %d 1" % message_type for message_type in message_types]

def startUp():
    commands = ['LOADPROJECT "<label-name>"']
    commands.extend(setMsgsTrue([1, 2, 3, 4, 5, 12, 26]))
    system.tag.writeBlocking([COMMAND_QUEUE_TAG], [commands])
    sendNextCommand()

def sendNextCommand():
    busy = system.tag.readBlocking([ETCHER_BUSY_TAG])[0].value
    if busy:
        return
    queue = system.tag.readBlocking([COMMAND_QUEUE_TAG])[0].value or []
    if not queue:
        return
    command = queue.pop(0)
    system.tag.writeBlocking(
        [COMMAND_QUEUE_TAG, ETCHER_BUSY_TAG], [queue, True])
    writeToEtcher(command)

def onResponse(response):
    response = response.strip()
    if response.startswith("ERROR") or response == "MSG 5":
        system.tag.writeBlocking(
            [ETCHER_BUSY_TAG, ETCHER_FAULTED_TAG], [False, True])
        return
    if response == "OK" or response in ("MSG 3", "MSG 4", "MSG 12"):
        system.tag.writeBlocking([ETCHER_BUSY_TAG], [False])
        sendNextCommand()

05

Results

$143K+Projected 3-year net avoidance per in-house build: vendor build/licensing avoided plus about $25K/year support/licensing. Reuse adds no vendor fee per line.
Outage-proofEtches locally from the loaded schedule without a live network, PPS, or internet dependency
5,000 / batchRecords per batch; sequence search added from operator feedback

Conservative. Excludes label elimination and service-trip savings, and scales with each line deployed.

06

Reflection

What I’d do next

Next, I would complete the rollout pattern with a dedicated Ignition server per glass plant, so no site depends on another site's connection, and parameterize site and line IDs so I can deploy the project to the remaining lines without hand-copying tags.