Learn PLCs free
Software Reviews30 min read5,855 words

OpenPLC Tutorial: Install, Program & Run Your First PLC

A current OpenPLC v4 tutorial covering the Editor, built-in simulator, Runtime v4, a tested first program, board targets, protocols and safety limits.

PPI
PLC Programming IO Editorial Team
Sourced guidance with documented review and correction standards

OpenPLC v4 is an open-source PLC editor and runtime toolchain. Install the current desktop Editor, create a project, select the built-in Simulator, declare one input and one output, build the project, and run the logic before connecting hardware. This guide also includes a complete conveyor-reject OpenPLC project with an I/O list, runnable Structured Text, acceptance tests and a grading rubric. If you deploy to Runtime v4, connect from the Editor over HTTPS on port 8443; do not follow old v3 tutorials that expect a browser dashboard on port 8080.

Last tested against public documentation and releases: August 30, 2026. The latest published releases during this review were OpenPLC Editor v4.2.11 and Runtime v4.1.10, both released August 11, 2026. Version labels, supported boards and menus can change. Use the live download page and release notes as the final authority.

This guide distinguishes three surfaces that older OpenPLC tutorials often mix together:

Surface What it does Current boundary
OpenPLC Editor v4 Creates, builds, simulates and deploys IEC-oriented PLC projects Desktop downloads are published for Windows x64, macOS Intel/Apple Silicon and Linux x64; check the live matrix
Built-in Simulator Runs a project without a physical PLC Intended for logic learning and debugging, not plant commissioning
OpenPLC Runtime v4 Executes a built project on standard computing hardware Headless service; Editor connection uses HTTPS on port 8443
OpenPLC v4 workflow from the desktop editor to the built-in simulator, runtime target and mapped industrial inputs and outputs.
Develop and test in the Editor first. Add a runtime or embedded board only after the logic passes a written test checklist.

Independent publisher note: plcprogramming.io is not the OpenPLC project. We link to the project's current Autonomy and GitHub sources and identify our related browser simulator separately.

OpenPLC v4 Quick Start

Use this route for a first successful project:

  1. Download the current OpenPLC Editor from Autonomy's official download page.
  2. Verify the operating-system and architecture label before opening the installer.
  3. Create a new project and choose Ladder Diagram (LD) or Structured Text (ST).
  4. Leave the built-in Simulator selected for the first test.
  5. Create a cyclic task and attach the main Program POU if the project template has not already done so.
  6. Declare StartPB, StopPB, RunCmd and MotorOut as Boolean variables.
  7. Build a seal-in circuit, run it, and test start, stop and restart behavior.
  8. Save a known-good project copy.
  9. Only then select an embedded board or connect Runtime v4.
  10. Validate the final I/O map with outputs de-energized before connecting a load.

That sequence isolates editor, program, target and wiring faults. If the simulated program fails, hardware is not yet part of the problem.

Editorial three-stage OpenPLC workflow separating generic ladder editing, isolated simulation and deployment to a headless runtime with mapped I/O.
Editorial workflow, not an OpenPLC interface screenshot. Keep editing, simulator evidence and Runtime deployment as separate stages so a failure can be assigned to the correct layer.

OpenPLC Editor v4 vs Runtime v4

The Editor and Runtime are separate applications.

OpenPLC Editor v4

The Editor is the engineering environment. Current project documentation describes:

  • Structured Text, Ladder Diagram, Function Block Diagram and Instruction List editors;
  • Program, Function and Function Block POUs;
  • variable tables and direct IEC-style locations such as %IX0.0 and %QX0.0;
  • cyclic task configuration;
  • a built-in browser/desktop simulator;
  • an embedded-board selector in the desktop application; and
  • build targets for the simulator, Arduino-class boards and OpenPLC Runtime.

Sequential Function Chart support has appeared in OpenPLC generations, but do not assume every current Editor surface exposes the same language menu. Check the installed release and current documentation instead of relying on an “all five languages” claim.

OpenPLC Runtime v4

Runtime v4 is the headless execution service. The current runtime repository describes:

  • a C/C++ PLC runtime core;
  • a Python/Flask REST API;
  • an HTTPS interface on port 8443 for Editor connections;
  • Linux, Docker and multi-architecture build paths;
  • TLS and authenticated management; and
  • a plugin model for hardware and industrial protocols.

Runtime v4 does not provide the old v3 web dashboard. Opening https://runtime-host:8443 in a normal browser is not the configuration workflow. Configure and control v4 from the Editor or the documented platform surface.

OpenPLC v3 vs v4

OpenPLC Runtime v3 reached end of life and its original GitHub repository was archived on April 4, 2026. Runtime v4 is the current branch for a new deployment.

Topic Runtime v3 Runtime v4
Repository Archived and read-only Current Autonomy-Logic/openplc-runtime repository
Management Browser dashboard commonly shown on port 8080 Editor/API connection over HTTPS on port 8443
Debug transport Legacy Modbus TCP path Secure WebSocket path documented by the v4 debugger
Installation commands Old OpenPLC_v3 clone/install scripts Current Docker or v4 repository instructions
Use now Maintain only when an existing system requires it Start here for a new runtime project

Do not combine a v3 installation command, v3 screenshot and v4 connection step. That is the main reason many copied tutorials fail.

Install OpenPLC Editor v4

Windows

At the review date, the official page listed Windows 10/11 x64. Windows on ARM was marked as not yet available.

  1. Open the official OpenPLC Editor download.
  2. Select Windows x64.
  3. Record the displayed version and file name in your lab notes.
  4. Scan the downloaded file using your normal security controls.
  5. Run the installer as the current user unless the installer explicitly requests elevation.
  6. Launch the Editor and confirm its version before creating a project.

Do not disable antivirus software or install a hand-picked collection of old Python packages. Those instructions belong to earlier Editor generations and weaken the machine without proving compatibility.

macOS

The official download page listed separate builds for Apple Silicon and Intel Macs.

  1. Choose the build matching Apple Silicon or Intel.
  2. Install using the signed package supplied by the current publisher.
  3. If macOS blocks the app, inspect the publisher/signature and use the operating system's normal privacy-and-security approval flow.
  4. Launch the Editor and run a simulator project before adding a USB target.

Linux

The official page listed a universal x64 AppImage and marked Linux ARM as not yet available on the download matrix.

  1. Download the current Linux x64 AppImage.
  2. Verify the file name/version against the download page.
  3. Make the AppImage executable using your file manager or a scoped chmod +x command.
  4. Launch it as a normal user.
  5. Test the built-in Simulator.

If you build the development Editor from source, use the requirements in the current Autonomy-Logic/openplc-editor repository. At review time, the repository requested Node.js >=22 <24; this is a contributor path, not the normal desktop installation.

Generic installation decision path checking computer platform, processor architecture, release package, security verification and rollback archive before setup.
Editorial installation checklist. Match the current OpenPLC package to the operating system and architecture shown on the official download page, retain its version, and keep a clean rollback path.

Build Your First OpenPLC Program

The first program is a motor-command seal-in circuit. It deliberately controls a simulated MotorOut, not a real contactor.

1. Define the behavior

The acceptance criteria are:

  • pressing Start turns RunCmd on;
  • releasing Start leaves RunCmd on;
  • pressing Stop turns RunCmd off;
  • Stop has priority if Start and Stop are true together; and
  • MotorOut follows RunCmd.

2. Declare the variables

Use four Boolean variables:

Name Type Initial value Role
StartPB BOOL FALSE Simulated normally-open start command
StopPB BOOL FALSE Simulated stop request; TRUE means stop
RunCmd BOOL FALSE Internal latched run state
MotorOut BOOL FALSE Simulated output

Keep them unlocated in the first simulator run. Physical addresses belong to the target configuration, not the reusable control intent.

3. Ladder Diagram version

Create two branches feeding the RunCmd coil:

|----[/ StopPB ]----+----[ StartPB ]--------( RunCmd )----|
|                   |                                      |
|                   +----[ RunCmd ]-------------------------|

|----[ RunCmd ]-----------------------------( MotorOut )---|

The normally closed logical condition NOT StopPB surrounds both the start and seal-in paths. That makes Stop dominant.

4. Structured Text equivalent

If you chose ST, use:

RunCmd := (StartPB OR RunCmd) AND NOT StopPB;
MotorOut := RunCmd;

The assignment executes every scan. Because the previous RunCmd value participates in the expression, it remains true after StartPB returns false. StopPB breaks the latch.

5. Add the program to a cyclic task

A POU that is not assigned to a running task may compile but never execute. Confirm:

  • one cyclic task exists;
  • the main Program instance is attached to it;
  • the interval is appropriate for a simple lab; and
  • there are no duplicate program instances writing the same output.

Do not copy a “1 ms is always better” recommendation. Task interval, operating system, target load and timing requirements must be measured together.

6. Build and simulate

With the Simulator target selected:

  1. Build the project and resolve every compiler error.
  2. Start the simulation.
  3. Set StartPB true for one or more scans, then false.
  4. Confirm RunCmd and MotorOut remain true.
  5. Set StopPB true.
  6. Confirm both outputs become false.
  7. Set Start and Stop true together.
  8. Confirm Stop wins.
  9. Stop and restart the simulation and record the initial state.

This is a complete, reproducible first test. A screenshot of a green rung is not enough; record the expected and observed value for each test case.

Motor seal-in simulator test matrix showing start hold, stop priority, simultaneous button state and safe restart cases beside generic ladder logic.
Editorial test matrix for the first program. Record each initial state, input action, expected output and observed output instead of treating one highlighted rung as complete evidence.

Add a Timer: Delayed Motor Output

To practise a stateful function block, add:

Name Type Role
StartDelay TON On-delay timer instance
MotorReady BOOL Becomes true after the preset

Structured Text:

RunCmd := (StartPB OR RunCmd) AND NOT StopPB;

StartDelay(
    IN := RunCmd,
    PT := T#2s
);

MotorReady := StartDelay.Q;
MotorOut := RunCmd AND MotorReady;

Test at least these cases:

  1. Start for less than two seconds: MotorOut stays false.
  2. Keep Run true past two seconds: MotorOut becomes true.
  3. Press Stop: MotorOut becomes false without waiting for the timer.
  4. Restart: timing begins again according to TON behavior.

The timer instance must be declared as TON; StartDelay.Q and StartDelay.ET are outputs of that stateful instance.

Complete OpenPLC Project: Conveyor Reject and Jam Diagnosis

The first seal-in circuit proves that the editor and simulator work. A useful OpenPLC project should go further: it should translate a written process requirement into named I/O, deterministic logic, observable fault evidence and repeatable acceptance tests. The following project models a low-energy training conveyor with one inspection station, a timed reject gate and a travel watchdog.

The default target is the built-in Simulator. No physical motor, solenoid, contactor or field voltage is required. If you later map the outputs to hardware, treat ConveyorCmd and RejectCmd as software requests only; qualified personnel must design the electrical interface, isolation, protective devices, risk reduction and safe stopping system.

Project problem statement

Create an OpenPLC program that meets these requirements:

  1. Start latches a conveyor run request only when the diagnostic emergency-stop status is healthy and no fault is active.
  2. Stop always removes the run request. If Start and Stop are true in the same scan, Stop wins.
  3. A rising edge at the entry sensor starts tracking one test part.
  4. A rising edge at the inspection sensor samples PartBad. A bad part starts a 500 ms reject pulse.
  5. A rising edge at the exit sensor completes the tracked part and increments either the good or rejected count.
  6. If a tracked part does not reach the exit within five seconds of conveyor running time, the project latches a jam fault and removes both output commands.
  7. Reset clears the fault, counters and tracked-part state only while the conveyor is stopped, the diagnostic E-stop status is healthy and all three process sensors are clear.
  8. Restarting the simulator must leave the output requests false unless the operator starts the process again.

This is intentionally a bounded one-part training model. It does not queue multiple parts between sensors, calculate belt position or guarantee a physical reject. Those are extensions, not hidden assumptions.

OpenPLC project I/O list

Keep all variables unlocated for the simulator run. Add %I and %Q locations only after the logic passes, and derive those locations from the exact target configuration rather than from this generic table.

Variable Type Direction Simulator meaning Physical-project boundary
StartPB BOOL input momentary start request ordinary control input, not a safety device
StopPB BOOL input TRUE requests a stop logical convention for this project; verify field polarity separately
ResetPB BOOL input momentary reset request reset must not initiate hazardous motion
EStopHealthy BOOL input TRUE permits ordinary logic to run diagnostic status only; never replaces a certified safety circuit
EntrySensor BOOL input part reaches conveyor entry simulated rising edge
InspectSensor BOOL input part reaches inspection station simulated rising edge
PartBad BOOL input classification sampled at inspection classification source must be validated in a real machine
ExitSensor BOOL input tracked part reaches exit simulated rising edge
ConveyorCmd BOOL output conveyor run request not a contactor or drive command until engineered and interlocked
RejectCmd BOOL output reject-gate request for 500 ms not a safe pneumatic design or proof of rejection
RunLamp BOOL output mirrors a valid run request diagnostic indication
FaultLamp BOOL output mirrors the latched fault diagnostic indication
GoodCount DINT internal completed good parts resets under the controlled reset condition
RejectCount DINT internal completed rejected parts counts requested classification, not independently verified reject motion
StateCode INT internal 0 stopped, 10 running, 90 faulted compact troubleshooting surface

EStopHealthy is named carefully. It is feedback available to ordinary application logic, not the emergency-stop function itself. The actual safety function must remove or control hazardous energy through an architecture selected and validated for the risk.

Runnable Structured Text solution

Create a Structured Text Program POU named Main, attach one instance to a cyclic task, and use a 20 ms interval for this simulator exercise. The interval is a lab choice, not a universal production value. If the Editor manages declarations in its variable table, enter the variables there and paste only the executable statements between the declaration block and END_PROGRAM.

The same source is available as a plain-text download: OpenPLC conveyor reject project ST file.

PROGRAM Main
VAR
    (* Simulated operator and process inputs *)
    StartPB       : BOOL := FALSE;
    StopPB        : BOOL := FALSE;
    ResetPB       : BOOL := FALSE;
    EStopHealthy  : BOOL := TRUE;
    EntrySensor   : BOOL := FALSE;
    InspectSensor : BOOL := FALSE;
    PartBad       : BOOL := FALSE;
    ExitSensor    : BOOL := FALSE;

    (* Output requests and visible diagnostics *)
    ConveyorCmd   : BOOL := FALSE;
    RejectCmd     : BOOL := FALSE;
    RunLamp       : BOOL := FALSE;
    FaultLamp     : BOOL := FALSE;
    GoodCount     : DINT := 0;
    RejectCount   : DINT := 0;
    StateCode     : INT := 0;

    (* Internal state *)
    RunRequest    : BOOL := FALSE;
    FaultActive   : BOOL := FALSE;
    PieceActive   : BOOL := FALSE;
    PendingReject : BOOL := FALSE;
    RejectActive  : BOOL := FALSE;

    EntryRise     : R_TRIG;
    InspectRise   : R_TRIG;
    ExitRise      : R_TRIG;
    TravelWatch   : TON;
    RejectPulse   : TON;
END_VAR

(* Capture one-scan events from held simulator inputs. *)
EntryRise(CLK := EntrySensor);
InspectRise(CLK := InspectSensor);
ExitRise(CLK := ExitSensor);

(* Reset is deliberately constrained and cannot start motion. *)
IF ResetPB
   AND NOT RunRequest
   AND EStopHealthy
   AND NOT EntrySensor
   AND NOT InspectSensor
   AND NOT ExitSensor THEN
    FaultActive := FALSE;
    PieceActive := FALSE;
    PendingReject := FALSE;
    RejectActive := FALSE;
    GoodCount := 0;
    RejectCount := 0;
END_IF;

(* Stop, unhealthy safety feedback and faults dominate Start. *)
IF StopPB OR NOT EStopHealthy OR FaultActive THEN
    RunRequest := FALSE;
ELSIF StartPB THEN
    RunRequest := TRUE;
END_IF;

(* Track one part from entry to exit. *)
IF EntryRise.Q AND RunRequest AND NOT PieceActive THEN
    PieceActive := TRUE;
    PendingReject := FALSE;
END_IF;

(* Sample classification at the inspection edge. *)
IF InspectRise.Q AND RunRequest AND PieceActive AND PartBad THEN
    PendingReject := TRUE;
    RejectActive := TRUE;
END_IF;

(* End the reject request after its configured pulse time. *)
RejectPulse(IN := RejectActive, PT := T#500ms);
IF RejectPulse.Q THEN
    RejectActive := FALSE;
END_IF;

(* Count a completed tracked part once, on the exit edge. *)
IF ExitRise.Q AND RunRequest AND PieceActive THEN
    IF PendingReject THEN
        RejectCount := RejectCount + 1;
    ELSE
        GoodCount := GoodCount + 1;
    END_IF;
    PieceActive := FALSE;
    PendingReject := FALSE;
END_IF;

(* Accumulate only powered conveyor travel time for the active part. *)
TravelWatch(IN := PieceActive AND RunRequest, PT := T#5s);
IF TravelWatch.Q THEN
    FaultActive := TRUE;
    RunRequest := FALSE;
    RejectActive := FALSE;
END_IF;

(* Assign outputs after all stop and fault decisions. *)
ConveyorCmd := RunRequest AND EStopHealthy AND NOT FaultActive;
RejectCmd := RejectActive AND ConveyorCmd;
RunLamp := ConveyorCmd;
FaultLamp := FaultActive;

IF FaultActive THEN
    StateCode := 90;
ELSIF ConveyorCmd THEN
    StateCode := 10;
ELSE
    StateCode := 0;
END_IF;
END_PROGRAM

The last-writer order is deliberate. A fault discovered by TravelWatch removes RunRequest before the outputs are assigned. This prevents a one-scan period in which the fault is true while ConveyorCmd remains true. It is still ordinary control logic, not safety logic.

Build the OpenPLC simulator project

Use this reproducible path in the current Editor generation:

  1. Create a new project and record the installed Editor version with the project evidence.
  2. Select the built-in Simulator as the initial target.
  3. Add Main as a Program POU using Structured Text.
  4. Add the declarations in the variable editor, or use the complete source form if the selected editor surface accepts it.
  5. Create a cyclic task with a 20 ms interval and attach exactly one Main program instance.
  6. Build the project. Treat warnings as review items, not decoration.
  7. Run the Simulator and watch every input, output, counter, PieceActive, PendingReject, FaultActive, both timer elapsed values and StateCode.
  8. Keep each momentary test input true for at least two task scans, then return it false so the rising-edge block can detect a later event.
  9. Execute the acceptance matrix below from a clean state.
  10. Save the project, Editor version, build result and observed test record together.

If the project builds but values do not change, first confirm the POU instance is attached to the cyclic task. If an edge triggers only once, return the simulated input to false before trying the next rising edge. If the reject output never turns on, confirm PartBad is already true when InspectSensor rises and that a part is currently tracked.

Acceptance-test matrix

Run these tests in order. “Pulse” means set the input true for at least two scans and return it false. Record observed values rather than only marking pass/fail.

ID Initial condition and action Expected evidence
OT-01 fresh simulation; EStopHealthy=TRUE; pulse Start ConveyorCmd=TRUE, RunLamp=TRUE, StateCode=10
OT-02 running; hold Start and Stop true together Stop wins; both command outputs false and StateCode=0
OT-03 running; pulse Entry, then pulse Exit before 5 s GoodCount increments once; PieceActive=FALSE; no fault
OT-04 running; pulse Entry; set PartBad=TRUE; pulse Inspect RejectCmd turns true, then false after about 500 ms; PendingReject=TRUE
OT-05 continue OT-04 and pulse Exit RejectCount increments once; GoodCount does not increment
OT-06 running; pulse Entry and never pulse Exit after 5 s of running time, FaultActive=TRUE, commands false, StateCode=90
OT-07 faulted; pulse Start without Reset outputs remain false; fault remains latched
OT-08 faulted; leave a process sensor true and pulse Reset reset is refused; counter and fault values do not clear
OT-09 stopped; clear sensors; EStopHealthy=TRUE; pulse Reset fault, counters and part state clear; outputs remain false
OT-10 running; set EStopHealthy=FALSE command outputs become false; ordinary restart is prevented
OT-11 stop for 3 s while a part is active, then restart and exit before total powered time reaches 5 s stopped time is not accumulated by TravelWatch; no jam fault
OT-12 hold Exit true for several scans the relevant counter increments only once because ExitRise detects an edge
OT-13 stop and restart the simulator/application output requests initialize false and motion does not resume automatically

Timer observations can differ by approximately one task interval. For a 20 ms task, a nominal 500 ms pulse should not be graded against an oscilloscope-level tolerance. The important evidence is that the pulse is bounded, Stop/fault removes it immediately and only a qualified inspection event initiates it.

Troubleshooting from state, cause and timer evidence

The project exposes three layers of evidence:

Symptom First values to inspect Likely cause to prove Corrective direction
conveyor never starts StopPB, EStopHealthy, FaultActive, RunRequest a dominant stop condition is true correct the simulated condition; do not bypass it in code
entry sensor does not begin tracking EntrySensor, EntryRise.Q, RunRequest, PieceActive input never returned false, project stopped, or a part already active reproduce the edge and verify the one-part boundary
reject never pulses InspectRise.Q, PartBad, PieceActive, RejectActive classification was false at the inspection edge set and observe classification before the edge
reject stays on RejectPulse.ET, RejectPulse.Q, task execution timer instance not called or POU not executing cyclically prove task assignment and timer state before rewriting logic
false jam fault PieceActive, ExitRise.Q, TravelWatch.ET, RunRequest exit edge was missed or travel requirement is unrealistic fix event capture or justify a new timeout from measured travel
counters increment twice ExitSensor and ExitRise.Q raw level was used elsewhere or duplicate POU instances write the counter enforce single ownership and one program instance
fault reset fails all three process sensors, RunRequest, EStopHealthy one reset permissive is not satisfied expose the false permissive; do not delete the guard

This evidence structure is useful beyond the exercise. A troubleshooting-friendly PLC program exposes the commanded state, the dominant inhibit, sequence ownership and timer progress. It does not force a technician to infer all four from the final output bit.

OpenPLC project grading rubric

Use a 100-point rubric so “it ran once” cannot hide missing behavior:

Area Points Full-credit evidence
project setup and repeatability 10 exact Editor version, Simulator target, cyclic task and one Main instance recorded
I/O and naming 10 all variables match the list; diagnostic safety status is not mislabeled as a safety function
start/stop dominance 10 OT-01 and OT-02 pass with Stop dominant in the same scan
part tracking and counting 15 OT-03, OT-05 and OT-12 pass without duplicate counts
reject pulse 10 OT-04 passes and Stop/fault can remove the command
jam detection 15 OT-06, OT-07 and OT-11 prove timeout, latching and powered-time behavior
controlled reset 10 OT-08 and OT-09 prove permissive enforcement and no automatic start
restart behavior 10 OT-13 passes from a documented initial condition
troubleshooting evidence 5 watched values and observed timer/state evidence are saved
safety and hardware boundary 5 report explicitly separates simulator requests from physical safety and power design

A score below 80 requires correction and a complete retest. Any failure of Stop dominance, fault output removal, controlled reset or safe initialization is an automatic resubmission regardless of the numeric score.

Extensions after the base project passes

Extend one requirement at a time and add tests before changing code:

  • add a BlockedAtInspect timeout distinct from the entry-to-exit travel watchdog;
  • retain counts across an ordinary restart while still initializing commands false;
  • add a manual mode with hold-to-run behavior and explicit mode arbitration;
  • expose a first-out fault code rather than one general fault bit;
  • simulate sensor chatter and prove the chosen debounce strategy;
  • create a bounded queue for two parts rather than silently assuming only one;
  • publish read-only counts and state through a lab Modbus client; or
  • reimplement the same acceptance tests in Ladder Diagram and compare maintainability.

Do not add physical motion merely to make the exercise look more realistic. The simulator project is complete when the written behavior, observable state and evidence agree. Hardware deployment is a separate engineering stage.

Run OpenPLC Runtime v4

Use the runtime when you need execution outside the Editor's built-in simulator.

The current Runtime v4 repository publishes this Docker path:

docker pull ghcr.io/autonomy-logic/openplc-runtime:latest

docker run -d \
  --name openplc-runtime \
  -p 8443:8443 \
  --cap-add=SYS_NICE \
  --cap-add=SYS_RESOURCE \
  -v openplc-runtime-data:/var/run/runtime \
  ghcr.io/autonomy-logic/openplc-runtime:latest

For a reproducible lab or production review, pin a tested image digest/version rather than leaving latest in a permanent deployment.

Native Linux installation

The project's runtime page currently documents:

git clone https://github.com/Autonomy-Logic/openplc-runtime.git
cd openplc-runtime
sudo ./install.sh

Before running an installer with elevated privileges:

  • inspect the current repository and release;
  • use an isolated lab host or image;
  • record the commit/tag you tested;
  • review ports, created services and file locations; and
  • keep a rollback or clean rebuild path.

The current service name shown by the project is openplc-runtime.service. Check it with:

sudo systemctl status openplc-runtime.service

Connect from the Editor

  1. Confirm the runtime host is reachable on the intended management network.
  2. In the Editor, select the Runtime v4 target or device connection surface.
  3. Enter the runtime host and port 8443.
  4. Complete the documented first-user/login flow.
  5. Build before upload.
  6. Upload and start the PLC from the Editor.
  7. Confirm the uploaded build/hash matches the project you just compiled.
  8. Watch selected variables in the debugger.

Runtime v4's debugger is live inspection; the current documentation says it does not provide breakpoint/step execution. Use the Simulator for controlled logic tests.

Arduino, ESP32 and Other Board Targets

The desktop Editor's current board-selection documentation describes more than 60 supported board profiles. Arduino-compatible targets compile through arduino-cli, while Runtime v4 targets use the runtime compiler/upload path.

The correct embedded workflow is:

  1. Open Device → Configuration in the desktop Editor.
  2. Select the exact board profile.
  3. Let the Editor obtain the required core/board definitions.
  4. Map IEC variables to the board's available pins.
  5. Review voltage, current, ADC and boot-strap constraints in the board documentation.
  6. Build and upload through the configured serial port.
  7. Test with LEDs or isolated low-energy training I/O first.

When you change boards, review every pin mapping. The control logic may remain the same, but the electrical interface does not.

Electrical boundary

Arduino, ESP32 and Raspberry Pi GPIO are logic-level electronics, not 24 V industrial I/O. Never connect a field signal, relay coil, contactor or inductive load directly unless a properly engineered interface provides:

  • voltage-level conversion;
  • input protection and filtering;
  • output current amplification;
  • flyback suppression for inductive loads;
  • galvanic isolation where required;
  • a suitable power supply and grounding scheme; and
  • a fail-safe state for startup, reset and communications loss.

Use certified safety hardware for emergency stops and safety functions. Software running on a general-purpose board is not made safety-rated by drawing an E-stop contact in ladder logic.

Protected I/O interface separating logic-level controller boards from industrial pushbuttons, sensors, indicator loads and a disconnected relay coil.
Editorial electrical boundary. A supported software target does not make logic-level pins compatible with field voltage, inductive loads or safety circuits; engineer and verify the complete interface.

I/O Addressing Without Guesswork

IEC-style located variables communicate intent:

  • %IX0.0 — input, bit addressing;
  • %QX0.0 — output, bit addressing;
  • %IW0 — input word;
  • %QW0 — output word; and
  • %MW0 — internal memory word.

The physical or protocol mapping behind an address depends on the target and plugin. Do not reuse a v3 register table, Raspberry Pi GPIO table or Arduino pin map without checking the v4 target documentation.

Use an I/O worksheet:

Program variable IEC location Target channel Electrical state Safe test
StartPB %IX0.0 DI channel to verify TRUE when pressed Toggle with output disabled
StopPB %IX0.1 DI channel to verify TRUE when stop requested Confirm stop-dominant logic
MotorOut %QX0.0 DO channel to verify TRUE requests run Test with indicator before contactor

The worksheet—not a generic address screenshot—should be reviewed against the selected board/runtime configuration.

OpenPLC v4 Protocol Support

The current OpenPLC communication matrix lists these Runtime v4 states:

Protocol Runtime v4 status in current documentation Important boundary
Modbus server Supported Verify address mapping and transport
Modbus client Supported Verify polling, timeouts and failure behavior
Modbus RTU master Supported Verify serial settings and isolation
Siemens S7Comm server Supported Treat as OpenPLC's implementation, not Siemens firmware
OPC UA server Supported Configure certificates, identities and exposed variables
EtherCAT master Supported through the documented plugin Verify platform, cycle timing and slave compatibility
EtherNet/IP In development Do not plan a project around an unreleased path
DNP3 Not listed as supported for v4 Do not inherit v3 beta claims

Arduino targets have a narrower protocol surface; the current documentation lists Modbus server mode rather than the full Runtime v4 matrix.

Modbus validation checklist

Before connecting an HMI or SCADA client:

  1. Confirm whether OpenPLC is the client or server.
  2. Record TCP/serial transport and unit identifier.
  3. Map one Boolean and one word end to end.
  4. Confirm zero-based vs one-based display notation in the client.
  5. Test word byte order with a known hexadecimal pattern.
  6. Test timeout, disconnect and reconnect behavior.
  7. Prevent unintended writes to safety- or motion-related variables.
  8. Restrict protocol access to the intended network zone.
Protocol validation bench testing mapped Boolean and word values, byte order, disconnect, reconnect and blocked writes across a generic industrial network.
Editorial protocol test bench, not a packet capture or product UI. Prove mapping, representation, failure handling and write restrictions with known values before connecting a larger client project.

OpenPLC Security and Production Limits

Runtime v4 adds modern management controls such as TLS and authenticated access, but those features do not make an arbitrary host, plugin or control panel production-ready.

For a serious deployment, document:

  • the exact Editor and Runtime commit/version;
  • operating-system image and patch process;
  • user and credential ownership;
  • network zones, firewall rules and permitted peers;
  • plugin versions and protocol exposure;
  • startup and watchdog behavior;
  • I/O state during boot, stop, fault and communications loss;
  • backup/restore and rollback;
  • measured scan-time distribution under load;
  • electrical/environmental ratings of the hardware; and
  • an independent safety risk assessment.

Open source also does not mean “no obligations.” At review time, the current Editor repository displays GPL-3.0 and the Runtime v4 repository displays MIT. Review the exact repository licences and bundled dependencies for your intended distribution and commercial use.

Troubleshooting OpenPLC v4

The tutorial says port 8080, but nothing appears

You are probably reading Runtime v3 instructions. Runtime v4 listens for Editor/API connections on port 8443 and does not expose the old browser dashboard.

The Windows installer name says v3

Do not install an old OpenPLC_Editor_v3.x_Windows.exe from a copied tutorial. Start at the current official download page and record the version offered for your architecture.

The program builds but does not run

Check that:

  • the Program POU is instantiated;
  • the instance is assigned to a task;
  • the task is enabled and cyclic;
  • the selected target matches the build;
  • the runtime is started after upload; and
  • no second POU overwrites the same output later in the scan.

The simulator works but hardware does not

Separate the layers:

  1. confirm the selected board/runtime target;
  2. check the pin or plugin map;
  3. observe the program variable;
  4. observe the logical output;
  5. measure the electrical output with the load isolated;
  6. verify polarity and common reference; and
  7. then test the interface module and load.

Modbus values are shifted

Check function code, data type, zero/one-based notation, byte order and the OpenPLC variable-to-register map. Do not “fix” a one-register shift by changing every tag until the addressing convention is documented.

Runtime v4 will not start

Use the current service/container logs, not a guessed v3 log path. For native Linux, check:

sudo systemctl status openplc-runtime.service
sudo journalctl -u openplc-runtime.service

For Docker, use the container's logs and confirm port 8443 plus the required capabilities/volume were applied.

OpenPLC FAQ

Is OpenPLC free?

The current Editor and Runtime source repositories are publicly available under open-source licences. That removes a conventional per-seat editor fee, but it does not remove hardware, engineering, hosting, support, cybersecurity or licence-compliance costs. Review the exact repository and dependency licences.

Is OpenPLC v4 the current version?

Yes for new Runtime work. Runtime v3 is archived and explicitly marked end-of-life. On August 30, 2026, the latest published releases were Editor v4.2.11 and Runtime v4.1.10. Treat those as a dated test record, not a permanent “latest” claim.

Does OpenPLC v4 have a web interface on port 8080?

No. That is a common v3 instruction. Runtime v4 is headless and the current documentation directs the Editor to connect over HTTPS on port 8443.

Can I simulate without hardware?

Yes. The current Editor includes a built-in Simulator. It is suitable for program logic and learning. It does not validate field wiring, electrical behavior, proprietary controller firmware or functional safety.

Which programming languages are supported?

Current Editor documentation explicitly covers Structured Text, Ladder Diagram, Function Block Diagram and Instruction List. Other OpenPLC generations and surfaces have referenced SFC; verify the exact installed Editor rather than assuming an identical language list across every release.

Can OpenPLC run on Raspberry Pi or Arduino?

OpenPLC supports standard-computing Runtime targets and many embedded-board profiles, but the exact board, architecture and compiler path must appear in the current board selector/documentation. A family name such as “Raspberry Pi” or “Arduino” is not a promise that every model is supported.

Can I use OpenPLC in an industrial machine?

Only after engineering the complete system and validating that the chosen hardware, operating system, I/O, network, environmental design and lifecycle controls meet the application's requirements. Do not use a general-purpose OpenPLC setup as a safety PLC or claim certification the selected system does not have.

Does OpenPLC support Modbus?

The current Runtime v4 protocol matrix lists Modbus server, Modbus client and Modbus RTU master support. Exact transport, mapping and target availability still require configuration and testing.

Where can I get an OpenPLC project example?

The conveyor-reject section on this page includes a complete Structured Text listing and a plain-text download, plus the I/O list, acceptance matrix and grading criteria needed to evaluate it. The official OpenPLC documentation also publishes small examples. Confirm the example's Editor generation before importing it; old v3 project instructions are not proof of v4 compatibility.

How should I test an OpenPLC project?

Start with the built-in Simulator and a written matrix covering nominal behavior, simultaneous commands, timeouts, reset permissives, edge cases and restart state. Save the observed variable and timer evidence with the exact Editor version. A successful compile or one highlighted rung does not prove the full requirement.

Is OpenPLC the same as a Siemens or Allen-Bradley PLC?

No. OpenPLC teaches IEC-oriented control concepts and provides its own runtime. It does not reproduce the compiler, firmware, instruction edge cases, safety functions or commissioning workflow of a proprietary controller.

Official Sources and Test Record

These primary sources were checked on August 30, 2026:

Practise the Logic Before Installing

If you want to practise the seal-in and timer examples before downloading OpenPLC, our related browser-based PLC simulator provides lessons and scenario-based feedback. Check its versioned product facts for the current free allowance, dialect list, and access caveat.

Disclosure and limit: plcprogramming.io and PLC Simulation Software share the same publisher. The browser product is an educational simulator, not OpenPLC Editor, Runtime v4 or a hardware emulator. Use it to practise the control idea, then rebuild and validate the project in the current OpenPLC toolchain.

Related resources:

#OpenPLCTutorial#OpenSource PLC#PLCProgramming#RaspberryPi PLC#ArduinoPLC#FreePLC Software
Share this article:

Related Articles