Functional PLC Structured Text Generation Using chatGPT: Yes, it Works
Below, I detail how, within a few hours of learning how to use chatGPT and refining my requests, I ended up with a totally reusable analog input control module, capable of processing an arbitrary number of inputs, including level alarms with variable time delays, out of range detection, and Process Variable simulation. With very little hand-editing. Pretty standard, but it showcases the future of automation engineering and this powerful, evolving tool.
If you are, or have met, an automation engineer, you know two things about them: they are lazy, and they are not ‘real programmers.’ I say lazy affectionately: we try to automate everything. From regression testing, to chicken coops, to your job; we just want that fully-automated luxury space-age society. With the buzz about advanced Large Language Models (LLMs) like chatGPT, and the automated coding that comes along with it, I figured it wouldn’t hurt trying to save my future-self two, maybe three, minutes.
It was from that perspective that one night, I asked if an LLM could generate IEC-61131 compliant code. Otherwise known as PLC code. Rockwell, Siemens, GE, CoDeSyS, Ladder Logic, and Structured Text are all based on this.
With that response, I fired up my Emulator VM while asking chatGPT to generate a bunch of code snippets. It was obvious that the code wouldn’t compile, but that’s something I am very used to encountering. Once everything was up and running, I just had to find a starting point.
Generating an RSLogix5000 Template
Why not start at the beginning? .L5X files are the base program files for modern Rockwell PLCs, which are generally IEC-61131 compliant, so I tried to generate a basic “MainProgram.” The first attempt was reminiscent of the correct format, but would not have worked. But as a learning model, maybe I could teach chatGPT. Nothing wrong with training your replacement.
Turns out that’s not how it works. But while it could not be taught, it could remember what I’ve told it.
Now that it remembered the structure of the base program template that I uploaded, I asked it to throw a few routines in there. It spat out an immediately importable .L5X that contained my given list of routines, with some nice comment sections in each.
At this point, under half an hour, I had an autogenerating base program with an arbitrary number and name of included routines, setup to with generic comment blocks. Reflecting on how many times I make a new PLC codebase with a known structure, this wasn’t very useful. So to make it more fun, I thought it would be trivial to add a simple Analog Input processor to the MainProgram CM_AI logic. While it did add code where it should, and the code looked like an Analog Input processor, it wasn’t quite right.
Generating an Analog Input Control Module
Here it is! Our first attempt at an analog input processor. Take only a quick glance, it’s not the functionality we want:
It looks like a control module, but it leaves a lot to be desired. The variable declaration and their types are perfect to throw into a UDT (UserDefinedType, datatype, structure, whatever you like to call it). And look at those comments: only an Intern could be so kind to future programmers revisiting the code.
But, I must have been not very clear to chatGPT. It’s not going to do what I want, and it didn’t give me alarm logic. So I iterated again, with a few conversational back and forths, being more clear and removing the request to loop. And got something that honestly, was not too bad.
I had spent about an hour and change getting to this point (mostly wasting time on the idea of generating the controller file at once, which I abandoned and started just pasting into the IDE), and as fun as it was, I wanted to get something running. So I:
- Started with one of my auto-generated MainPrograms
- Pasted the code into the IDE
- Stripped out the variable declarations
- Created New Tags based on the declarations
- Added JSR(CM_AI); (subroutine call) to MainRoutine
- Changed the PLC to an Emulator PLC
And that was it, which took all of 5 minutes. I was online and watching my inputs scale and alarms process correctly.
Not wanting to leave things half finished, I decided to expand this to an actual Analog Input Control Module. And maybe try an Analog Outputs module. I do need a new valve controller with analog position feedback for LucidBrau…
I wanted a Control Module routine that would process Analog Input data. It would allow for:
- 4 levels of alarms
- alarm enable/disables
- alarm delay timers unique to each alarm
- out of range detection
- scaling of the raw counts from the Analog to Digital converter
- Process Variable simulation mode
With that functional requirement specification in mind, I tried to be as clear as possible, define the looping functionality a bit more in text, and asked chatGPT to generate it.
The code it immediately generated was close. The scaling logic was lacking. The alarm processors were fine, but their timers were not formatted in a way that would compile. I refined my request a few times, which resolved the scaling logic. But the alarm delay timer portion of the code needed some hand massaging to work with the specific syntax of the RSLogix5000 IDE, which consisted of editing two lines and adding one TONR() function call.
Beyond the timer syntax, the main issue was that the variable declaration, so verbose in the previous examples, was overly simple in this example: it just declared a datatype: CM_AI : ARRAY [0..5] OF AnalogInputControlData;
But, chatGPT could be persuaded to define that datatype. This data structure was then immediately (albeit manually) defined as a UDT.
All this took about 10 minutes.
So from that point, I did the same thing as before to get it running:
- Make sure the UDT is defined
- Create a controller tag CM_AI, type UDT_Name
- Add JSR to MainRoutine
- Change Controller Slot for the Emulator
Sure, its not complex. There’s no HMI interactivity, no IO connectivity, and no calibration mode. These components could be coaxed out of this Language Model, as individual code snippets, or part of this larger one.
To go from a vague notion to a functional, semi-complex Control Module running in an emulator within the span of 2 hours, it’s clear that LLMs like chatGPT are an incredibly powerful concept, that will change how everyone generates code, automation engineers included. And if you are committed to Ladder Logic, there’s even hope for you here: it can generate the text that your IDE will interpret as ladder.
Consider this list of 70%-100% useable code snippets I have generated, analyzed, and (some of them, denoted by *) implemented:
- Analog Output Control Modules*
- Digital Input Control Modules*
- Digital Output Control Modules*
- Servo Motion Control
- ModbusTCP Messaging using MSG blocks and data buffers*
- Barcode Scanner data parsing
- Position tracking of scanned barcodes
- Network Switch .config files for a router with multiple VLANs and NAT functionality*
- VBA .ADO database inserts*
- VBA user idle detection handling and application logout*
- VBA dropdown menu control template (this one was for my wife, to expand an Excel sheet detailing our power tools for some reason)*
- Ladder Logic and Structured text Champagne Sort algorithms*
- SQL Stored Procedure that could be used to generated a Bioreactor Alarm report
Remember: this, right here, right now, is as bad as LLM generated PLC code will ever be.
Between the time that I wrote this and the time that you read it, the model got better. And that fact alone should make you want try it out. It’s fun! And it’s free! (for now).
As I have continued to experiment with this tool and equipment I have on hand, I’d like to note a few peculiarities of chatGPT. First, I only used the standard web interface. Each ‘chat thread’ that I opened remembered things mentioned in that thread, but could not access things discussed in other threads. Second, depending on what code, frameworks, or even abstract ideas you mention in a thread, it will impact the code that you get. One Analog Input Control Module request that is copied and pasted into another thread will generate a different snipped of code. Third, I got lucky with some specific questions on my early threads, which I could not replicate on my later threads. I’ll leave it up to you to refine your testing, but if you have any thoughts, insights, or questions, DM me!
By the way, here was that Analog Output Control Module I mentioned earlier. Map the CM_AI PV to the CM_AO feedback, and you get a decent valve controller. Could use a time delay on the FeedbackOutOfRange alarm, though. But let the front end devs worry about that one.