ladder logic

sequencer

exercise

PLC Elevator Logic Exercise: Step-by-Step

‌
PLC elevator logic exercise diagram showing 3-floor shaft wired to a PLC rack with ladder logic rungs

The elevator is one of the best training exercises for ladder logic because it forces you to deal with three things that trip up beginners every time: latching call requests that must survive after the button is released, direction interlocks that prevent the car from reversing mid-travel, and timed events for doors. Get through this exercise and you will have used contacts, coils, latches, timers, and a simple state variable in one connected project.

This exercise models a 3-floor, single-car elevator with one up/down call button per floor (6 buttons total), a limit switch at each floor, a door open/close timer, and a direction bit. The PLC platform is Rockwell Studio 5000 / Logix, but the logic translates directly to any IEC 61131-3 ladder environment. You do not need motion control or a drive for this exercise. A pair of relay outputs driving a small gearmotor in forward/reverse is enough to simulate it on a test rig or in software.

I/O List and Tag Definitions

Keep the I/O tight. This is a training exercise, not a real elevator controller covered by EN 81-20, so you do not need safety-category wiring here. If you want to understand how safety inputs would layer on top, the concepts in Safety Relay Wiring: Circuits Explained apply directly.

TagTypeDescription
Btn_Call_F1_UpBOOL InputFloor 1 Up call button (momentary NO)
Btn_Call_F2_UpBOOL InputFloor 2 Up call button
Btn_Call_F2_DnBOOL InputFloor 2 Down call button
Btn_Call_F3_DnBOOL InputFloor 3 Down call button
LS_At_Floor1BOOL InputLimit switch, car at floor 1
LS_At_Floor2BOOL InputLimit switch, car at floor 2
LS_At_Floor3BOOL InputLimit switch, car at floor 3
Door_ClosedBOOL InputDoor closed feedback (NO contact)
Call_Latch_F1BOOL InternalLatched call request for floor 1
Call_Latch_F2BOOL InternalLatched call request for floor 2
Call_Latch_F3BOOL InternalLatched call request for floor 3
Dir_UpBOOL InternalCar travelling up
Dir_DnBOOL InternalCar travelling down
Floor_CurrentINT InternalCurrent floor number (1/2/3)
Floor_TargetINT InternalRequested destination floor
Motor_UpBOOL OutputHoist motor forward (up)
Motor_DnBOOL OutputHoist motor reverse (down)
Door_Open_SolBOOL OutputDoor open solenoid
Door_TimerTON InternalDoor dwell timer (3 s preset)
I/O and internal tags for the 3-floor elevator exercise (Studio 5000 / Logix)

How the Logic Is Structured

Break the program into four clear rungs groups. Doing this before you write a single contact saves you an hour of untangling later.

  1. Call latching: Latch each floor call request when the button is pressed; unlatch when the car arrives at that floor.
  2. Current floor tracking: Update Floor_Current using the limit switches.
  3. Direction and target selection: Compare Floor_Current to the nearest pending call and set Dir_Up or Dir_Dn. This is where most beginners make mistakes.
  4. Door control: When the car arrives, stop the motor, open the door, run the dwell timer, then close the door and clear the latch.

Step 1: Latching the Floor Calls

Each floor call button is momentary. The instant the operator releases it, the input drops. You must latch it internally or the car will never know where to go. Use OTL/OTU pairs.

For floor 1: OTL(Call_Latch_F1) when Btn_Call_F1_Up goes true. OTU(Call_Latch_F1) when LS_At_Floor1 is true AND the door has opened (Door_Timer.DN). Apply the same pattern for floors 2 and 3. The unlatch condition is important: do not unlatch on arrival alone. Wait until the door timer completes, otherwise the car might re-register the same floor immediately on the next scan.

Step 2: Tracking the Current Floor

Use three MOV rungs. When LS_At_Floor1 is true, MOV 1 into Floor_Current. When LS_At_Floor2 is true, MOV 2. When LS_At_Floor3 is true, MOV 3. Floor_Current only updates while a limit switch is active, which is exactly what you want. Between floors, it holds the last known value.

Gotcha: If your limit switches are mechanically noisy and bounce, Floor_Current can flicker. Add a small TON (50 ms) before the MOV so the switch has to stay active for at least one stable scan cycle. This is a common issue on cheap training rigs with microswitches.

Step 3: Direction and Target Selection (the Hard Part)

This is where the exercise earns its keep. You need to compare Floor_Current against the pending call latches and decide which direction to travel. For a 3-floor car with no directional preference algorithm, the simplest working rule is:

  • If Call_Latch_F3 is true AND Floor_Current < 3, set Dir_Up.
  • If Call_Latch_F1 is true AND Floor_Current > 1, set Dir_Dn.
  • If Call_Latch_F2 is true AND Floor_Current < 2, set Dir_Up.
  • If Call_Latch_F2 is true AND Floor_Current > 2, set Dir_Dn.
  • Dir_Up and Dir_Dn must be interlocked: XIO(Dir_Up) on the Dir_Dn rung and vice versa.

In Studio 5000, use GRT (Greater Than) and LES (Less Than) compare instructions on the same rung as the call latch contact. For example: XIC(Call_Latch_F3) + LES(Floor_Current, 3) = OTL(Dir_Up). The XIO interlock on the same coil prevents Dir_Dn from being set at the same time.

Once Dir_Up or Dir_Dn is set, drive Motor_Up or Motor_Dn through an XIC contact on the direction bit, gated by XIO(LS_At_Floor3) for the up direction (do not drive up past the top floor) and XIO(LS_At_Floor1) for the down direction. Those limit switch interlocks are your crude overtravel protection.

Ladder logic direction interlock rungs for PLC elevator logic exercise
Direction interlock structure: Dir_Up and Dir_Dn OTL coils each have an XIO of the opposite direction to prevent simultaneous energisation.

Step 4: Door Control with a TON Timer

When the car arrives at a called floor, the sequence is: stop the motor, open the door, dwell for 3 seconds, close the door, clear the call latch. The TON handles the dwell. The Door_Closed feedback input re-enables motor operation.

The arrival condition is: the limit switch for the target floor is active AND the corresponding call latch is set. Tie both into the TON enable rung. Set PRE to 3000 ms. When Door_Timer.DN goes true, pulse OTU on the call latch and de-energise Door_Open_Sol. Add XIO(Door_Closed) to the Motor_Up and Motor_Dn rungs so the motor cannot run with the door open.

Ladder Rung: Elevator Door Dwell and Call Clear

Elevator Floor 2 Arrival: Door Timer and Call Latch Clear (Studio 5000). Ladder logic (5 rungs): Rung 0: examine if LS_At_Floor2 is on (XIC), then examine if Call_Latch_F2 is on (XIC), then examine if Door_Closed is off (XIO), then TON on Door_Timer. Rung 1: examine if LS_At_Floor2 is on (XIC), then examine if Call_Latch_F2 is on (XIC), then examine if Door_Closed is off (XIO), then energize output Door_Open_Sol (OTE). Rung 2: examine if Door_Timer.DN is on (XIC), then unlatch output Call_Latch_F2 (OTU). Rung 3: examine if Door_Timer.DN is on (XIC), then unlatch output Dir_Up (OTU). Rung 4: examine if Door_Timer.DN is on (XIC), then unlatch output Dir_Dn (OTU). When the car is at floor 2 with an active call latch and the door is not yet closed, the 3-second door dwell timer runs and the door solenoid is energised. When the timer completes, the floor call latch and both direction bits are unlatched, ready for the next call.

Elevator Floor 2 Arrival: Door Timer and Call Latch Clear (Studio 5000)Ladder logic
Toggle inputs
Rung 0
Ladder logic rung: examine if LS_At_Floor2 is on (XIC), then examine if Call_Latch_F2 is on (XIC), then examine if Door_Closed is off (XIO), then TON on Door_Timer examine if LS_At_Floor2 is on (XIC), then examine if Call_Latch_F2 is on (XIC), then examine if Door_Closed is off (XIO), then TON on Door_Timer XIC LS_At_Floor2 LS_At_Floor2 LS_At_Floor2 XIC Call_Latch_F2 Call_Latch_F2 Call_Latch_F2 XIO Door_Closed Door_Closed Door_Closed TON Door_Timer 3000 0 TONTimerDoor_TimerDoor_TimerPreset30003000Accum00
Rung 1
Ladder logic rung: examine if LS_At_Floor2 is on (XIC), then examine if Call_Latch_F2 is on (XIC), then examine if Door_Closed is off (XIO), then energize output Door_Open_Sol (OTE) examine if LS_At_Floor2 is on (XIC), then examine if Call_Latch_F2 is on (XIC), then examine if Door_Closed is off (XIO), then energize output Door_Open_Sol (OTE) XIC LS_At_Floor2 LS_At_Floor2 LS_At_Floor2 XIC Call_Latch_F2 Call_Latch_F2 Call_Latch_F2 XIO Door_Closed Door_Closed Door_Closed OTE Door_Open_Sol Door_Open_Sol Door_Open_Sol
Rung 2
Ladder logic rung: examine if Door_Timer.DN is on (XIC), then unlatch output Call_Latch_F2 (OTU) examine if Door_Timer.DN is on (XIC), then unlatch output Call_Latch_F2 (OTU) XIC Door_Timer.DN Door_Timer.DN Door_Timer.DN OTU Call_Latch_F2 Call_Latch_F2 Call_Latch_F2 U
Rung 3
Ladder logic rung: examine if Door_Timer.DN is on (XIC), then unlatch output Dir_Up (OTU) examine if Door_Timer.DN is on (XIC), then unlatch output Dir_Up (OTU) XIC Door_Timer.DN Door_Timer.DN Door_Timer.DN OTU Dir_Up Dir_Up Dir_Up U
Rung 4
Ladder logic rung: examine if Door_Timer.DN is on (XIC), then unlatch output Dir_Dn (OTU) examine if Door_Timer.DN is on (XIC), then unlatch output Dir_Dn (OTU) XIC Door_Timer.DN Door_Timer.DN Door_Timer.DN OTU Dir_Dn Dir_Dn Dir_Dn U
energizedTip: click a contact in the diagram to flip its bit.
When the car is at floor 2 with an active call latch and the door is not yet closed, the 3-second door dwell timer runs and the door solenoid is energised. When the timer completes, the floor call latch and both direction bits are unlatched, ready for the next call.
Do not forget to unlatch Dir_Up and Dir_Dn on arrival. If you only unlatch the call latch and leave the direction bit set, the car will immediately re-evaluate and set the direction again on the very next scan, which may cause it to leave before the door has finished closing. Unlatch the direction inside the Door_Timer.DN rung so it only clears after the dwell.

Extending the Exercise: Where to Go Next

Once the basic logic runs, push yourself with these additions:

  • Directional preference: If the car is travelling up and a floor 2 call comes in while passing through floor 2 going to floor 3, should it stop? Add logic that checks whether the call direction matches the current travel direction before unlatching.
  • Cabin buttons: Add three inputs simulating buttons inside the car (one per floor). These latch the same Call_Latch_Fx tags, so the cabin and hall calls share the same destination logic.
  • Fault detection: Add a watchdog TON that trips if the car has been between floors for more than 15 seconds without hitting a limit switch. OTL a Motor_Fault bit and kill both motor outputs.
  • HMI floor indicator: Write Floor_Current to an HMI integer tag and display it as a floor number. If you want to display direction arrows, map Dir_Up and Dir_Dn to bit indicators.
  • Second car: Duplicate the entire program section for a second car on the same shaft. Now you need car-selection arbitration logic. That is a real scheduling problem.

Common Mistakes in This Exercise

MistakeSymptomFix
Unlatching the call on arrival, not on door closeCar leaves before door fully closesMove OTU into the Door_Timer.DN rung
No interlock between Dir_Up and Dir_DnBoth motor outputs energise, tripping a drive fault or blowing a fuseAdd XIO(Dir_Up) to every rung that sets Dir_Dn and vice versa
Missing overtravel limit on motor rungsCar drives into end stop at floor 1 or floor 3Add XIO(LS_At_Floor1) to Motor_Dn rung; XIO(LS_At_Floor3) to Motor_Up rung
Floor_Current not initialised on first PLC power-upCompare instructions behave unexpectedly on startupAdd a first-scan rung (using S:FS or FirstScan tag) that MOVs 1 into Floor_Current if LS_At_Floor1 is true, otherwise 0
Door_Timer not reset after the car leavesTimer accumulator carries over to next arrivalAdd RES(Door_Timer) on a rung gated by XIO(LS_At_Floor2) so the timer resets when the car is not at floor 2
Most common logic errors in the elevator exercise and how to fix them

Running It Without Real Hardware

You do not need a physical rig to get value from this. Studio 5000 Logix Emulate lets you run the program and force inputs from the I/O tree. Set up a watch window with all the call latches, Floor_Current, Dir_Up, Dir_Dn, and Door_Timer.ACC visible at once. Then force Btn_Call_F3_Dn true for one scan, verify Call_Latch_F3 latches, then force LS_At_Floor3 true and watch the timer run. That single sequence exercises three of the four logic groups.

CODESYS users can do the same with the CODESYS SoftPLC and the built-in simulation mode. GX Works3 (Mitsubishi) has a simulator that handles TON and compare instructions without modification. The logic structure shown here is platform-agnostic: only the instruction names differ.

If you have already completed the PLC Bottle Filling Machine project, the elevator is a natural next step. The bottle filler gives you timer and counter fundamentals in a linear sequence. The elevator adds branching logic and state variables, which is where real production machines live.

What This Exercise Actually Teaches

By the time you have a 3-floor elevator running correctly, you have used OTL/OTU latches, TON timers, compare instructions, interlock logic, and an integer state variable. Those five tools cover the majority of real-world PLC programs. The elevator just packages them into a scenario that is easy to visualise and verify, which is why it has been a classroom staple for decades. The fact that it comes up in job interviews fairly often does not hurt either.

Related Blogs