This is part of an RSLogix 5000 Tutorial.
Now let’s move over to the WashingMachine program that we created earlier:
Notice that we’ve already created Aa_Main and selected it as the main routine for this program. Go ahead and add the following routines to the WashingMachine program:
Make sure that you add JSR instructions in Aa_Main to call these routines, and make sure they call these routines in the same order they’re shown in the list.
Notice I’ve broken the low level control routines into two sections and I used “B” and “C” prefixes on the routine names to separate them. The “B” routines control the mode of the machine and provide rudimentary feedback to the person using the machine. The “C” routines control the actual machine actuators like the valves and the motion.
You already know how to add contacts, coils, branches and timers, and how to add new tags if you need to. (If you need a refresher, see the last section.) So let’s start looking at some logic to see what it does:
Cycle Selection and Temperature Selection
Similar to modes in an industrial machine, this washing machine has a cycle selection feature: Normal, Permanent Press, or Gentle. Here’s how the operator interface is supposed to work:
- Fill the machine with clothes
- Close the lid
- Select a cycle
- Press start
- When the cycle is complete, the cycle complete light turns on
- The cycle complete light turns off when you open the lid
There are also two other ways to stop the cycle: a cycle stop button, and by opening the lid. Note that in both of these cases, the machine should stay in cycle, and can be resumed by pressing the start button again. Let’s look at the cycle selection logic in Ba_CycleSelection:
The first thing you might notice is that we’re using the cycle indicator outputs to hold the state of our cycle selection. In a large application we probably wouldn’t do this. We would use internal coils to hold our mode selection state and then drive both the indicator lights and probably the HMI indicators from those internal coils. But this is a simple machine, and this works.
We’re using a common mode selection pattern here with a “no mode” coil at the top. In order to go into a mode we make sure we’re out of any other modes first. This ensures one scan of the PLC with no mode bits energized between mode selections. Look carefully at the second rung (for the Normal Cycle). The first parallel branch gives us the condition to start the cycle (no mode, and the Normal Cycle button). We seal this in with the Normal Cycle coil itself. The second parallel branch in that rung does the following:
- If we’re not “running” yet, we can break out of Normal cycle by selecting another cycle
- It prevents the race condition where we have no cycle selected and then we press two cycle select buttons simultaneously (you can only select a cycle if you have one button of the three pressed)
- Once the cycle is “running” we can’t accidentally change cycles by pressing another cycle selection button
Finally, after the second parallel branch, we break the cycle selection when the cycle is complete. This also has the effect of preventing another cycle from being selected until someone opens the lid, which turns off the cycle complete condition.
The washing machine also has three temperature settings: Hot, Warm, and Cold. The temperature selection logic in Bb_TempSelection is identical to the cycle selection logic above, so I won’t show that here.
Cycle Start and Cycle Stop
In the logic above you saw the cycle running and cycle complete signals. These are set in the Bc_CycleStart routine:
Looking at the parallel branch part of the first rung, we’re testing to see if we’ve selected any cycle and any temperature (“not no cycle” is the same as “any cycle”) and we need to see the cycle start button pressed. Once we trigger the cycle running condition, it seals in around the start button and keeps the cycle running. The rest of the rung defines our stopping condition. As we mentioned earlier, there are three ways to stop the cycle: pressing the stop button, opening the lid, or having the automatic cycle complete normally.
The second rung defines the cycle complete condition. As you can see, it only turns on when the cycle running condition is on, and it turns off when the lid is opened, but you also probably noticed that it’s incomplete. The “AFI” instruction means “always false input”. It’s like a normally open contact that never turns on. I put this in here as a place-holder because I haven’t written the logic yet that will trigger the completion of the cycle.
The AFI instruction is particularly handy for this because RSLogix 5000 will give us a warning any time it encounters an AFI. I like using these wherever I need to come back later and complete something that I wasn’t ready to complete earlier. I also use them in most output rungs when I’m writing the program so that all outputs are disabled when I download the program the first time. Then I can go through and remove the AFI instructions one at a time and test one output at a time without worrying about side-effects that might cause unexpected motion.
Like all user-friendly consumer grade appliances, we have a single indicator light that tells the owner that there’s something wrong. This logic is so complicated and perverse that I put it in its own routine just to isolate it from the rest of the logic:
Output Rungs for the Inlet Valves
We have to go through all of our machine outputs and at least create and “stub” output rungs to get going. In most cases we won’t have enough logic ready to actually make them turn on, but we want to fill in the basic sanity check logic first, to prevent programming mistakes later from causing machine crashes (literally) or unexpected motion. When you’re starting up a machine for the first time, it’s a lot better if the machine doesn’t move when it should, rather than moving when it shouldn’t. So at the beginning, be thinking, “when should this output never turn on”?
I created a routine called Ca_InletValves for my logic to control the Inlet Valve inputs (LO02.0 and LO02.1):
The inlet valves fill the washing machine with cold and hot water. In this case, we never want to be filling with water if we have a critical fault (the idea of a critical fault is that is should stop all actions immediately) and we also never want to be filling if the water level full sensor is on. This is a nice sanity check that prevents our sequence logic from causing an overflow if we ever get stuck in the Filling state.
I added AFI instructions here too, to act as placeholders for the auto sequence logic that we’re going to add later.
Output Rungs for the Outlet Pump
Similarly I created an output rung for the outlet pump motor starter. In this case, we don’t want to run the outlet pump once there’s nothing to pump:
Programming Motion Control for the Agitator Axis
The reason I included a motion control axis in our fictional washing machine was so I could give an example of how to program motion control in RSLogix 5000.
What defines “motion” control?
So when we’re talking about motion control, what do we mean? In general, it’s any time that your machine moves, but I don’t think that’s accurate enough. I think it’s more accurate to say that it’s any time an axis (servo, slide, cylinder, etc.) moves from one point to another point. The reason I’m being pedantic about this is because if you just have a contactor that turns on a motor and you’re not sensing some position (perhaps you’re just doing speed control) then that’s not really what we mean when we talk about motion control. However, if you start a motor and it turns a ball screw and you run it until you hit a sensor, and then you turn it off, that’s motion control (or close enough).
Whenever you see terms like Advance/Retract, Raise/Lower, Grasp/Release or Engage/Disengage then you’re talking about motion control because you have some kind of motion from point A to point B, and back again. These are simple two position motions, but it’s also expandable to 3, 4, or N positions. You can even have a position that’s calculated dynamically, like if you use machine vision to locate a part on a conveyor belt and you want to pick it up. There’s a dynamic pickup position, probably a pounce position, a drop off position, and perhaps other positions throughout your motion profile.
The Five Rung Logic Block
I’m going to demonstrate a programming pattern called five rung logic that’s applicable to all these cases. When most people first see five rung logic, they think it’s overkill. So did I. However, they have two advantages:
- They can be adapted to suit any of the above situations
- They’re a standard pattern, so other programmers who are familiar with five rung logic will find it easier to follow and troubleshoot your logic
I also found that during commissioning most of my motion control logic eventually grows to the point where it’s at least as complex, or worse, than a five rung logic block, so I discovered it’s better to just layout all your motion positions with five rung blocks at the beginning, and it makes commissioning go a lot faster.
The Five Rung UDT
The five run logic block is a great place to apply the RSLogix 5000 user defined type (UDT) feature. UDT’s are difficult to change when you’re doing online programming, so they’re not good for program structures that change a lot, but five rung logic is so standardized that you can build a UDT and use it all over the place. Here’s what a general five rung UDT looks like:
To create the UDT, go to the controller organizer, under the Data Types folder, right click on the User-Defined subfolder, and select New Data Type… Then create the following:
Notice I’ve added two extra things that I didn’t talk about above. One is the FaultTMR Timer. This should be obvious – if we’re going to have a timeout fault, we need a timer. The second is the “PB” tag. We may not have use of a “manual mode” on a washing machine, but every machine in an industrial automation setting will have a manual mode, and you’ll almost always want a button on your HMI that says “Move to Position A”. We include the logic for this right in the five rung block itself, so I usually like to allocate a bit for the pushbutton right in my five rung UDT.
Here’s what a generic five rung logic block looks like (note that this is only to move one axis to one position):
You have to customize it for each situation. The contents of the safety and trigger rungs are obviously unique, but the command rung sometimes changes depending on the scenario. You may have more than just manual and automatic modes. Some automatic actions may actually happen when you’re not in automatic mode. Sometimes you may want an axis to “jog” (for instance a hydraulic axis moves slow, and you may want it only to move in manual mode if you hold your finger on the button) and in that case, you couldn’t seal in the Command bit around the manual mode pushbutton (you’d just seal it in around the trigger contact).
In a simple case, you would take the Command coil and use it to drive your Advance output, whether it be a solenoid, or whatever. In our case, we have a servo axis. This means we need to use RSLogix 5000 motion control blocks.
We need two motion blocks for each position we want to move to: an MAM instruction (motion axis move) and an MAS instruction (motion axis stop). The MAM instruction makes us go, but the MAS instruction let’s us stop motion when we need to abort it:
Notice that the MAM instruction has a Move Type parameter that I set to 1. This means it’s an incremental move. There are more options than just absolute and incremental. Check the MAM instruction help (highlight the MAM and press F1) to see a description of these options. Since I’m using a rotary axis here, I’m giving my command in degrees, so this instruction tells the axis to move 90 degrees forward from where it is now.
I’m just using the Command coil from my five-rung logic to drive the motion here. If the MAM instruction completes the move, it will turn on the .PC bit (program complete?). However, if it doesn’t complete (and the Command coil drops out before it completes), then the second rung will detect that the motion is in progress (the .IP bit) and will execute the MAS instruction to stop the move command.
For an incremental move, it’s reasonable to use the .IP bit from the MAM instruction in the “In Position” (or “Complete”) rung of your five-rung logic block. However, when doing absolute moves to a fixed position, I find it more reliable to base my In Position logic on the following axis tags:
That is, you can take the axis’ actual position and compare it against some limits you set to denote your position (plus or minus a tolerance). The position lock status tells you that the axis is within the position limits set in the axis configuration. You need to take the axis homed status into account before you even look at the actual position tag (normally the position won’t be valid if you haven’t homed). Homing is a lesson for another tutorial or blog post, but I’ll give you a hint: MAH.
Whew… that was rather long. Now it’s on to the sequence of operations…