Good programming practice

Rhonda said:
sometimes being too clever in the code is a bad thing. Now I try to program so that I will be able to read & understand it 5 years down the road, after having not looked at it in all that time.

Good point Rhonda. Use comments along with consistent structure to make your programs pedictable and understandable; even to yourself.

The use of indirects, replaceable parameter subroutines and block moves with counters for multiplexing will save space, but you will LOSE (bewilder) those that are trying to troubleshoot the process. This is not to say that you can never use these techniques, but you should do so only when you must conserve resources.

A well designed structure i.e., Alarm bit range declared, timer/ counter registers standard between programs, inter-PLC communication registers and so on; can go a long way toward making your programs something that is familiar and COMFORTABLE to the maintenance tech on the floor. Even when the process is very different, he will know where you generally "put" things. The downside to this is that,in time, your structure will have to change due to advances or changes in your PLC/HMI equipment. But you will still have the same general style.

A bbs for an exchange of ideas between PLC hacks is a great idea!
My name is Joey and it's a pleasure to find other eggheads like myself out there! :)
 
I forgot (missed) page 2 like the noob I am. Many good points made there. Had I read it first, I might not have posted.

I still think this is a great idea!
 
Welcome to the club Joey! You can thank the august Phil Melore for this lovely site, which is now on it's 3rd (4th?) generation. I've been here for years, and PLCs.net has been here years longer than me, so go cruising through the archives sometime. Fun and educational!

TM
 
jtn said:
One plant I work at frequently made a standard where every panel with a PLC in it was required to have an ethernet drop so that everyone could work off of the same program on the server. This helped greatly with the documentation issues.

This is exactly right. I implemented this startegy a while back in a mill. It cost ten grand or so per processor, but the reslult was well worth the effort.
 
One of the best programming jobs I have ever worked with was anything but simple. It was very consistent. Reading it took lots of dedication, and knowledge of programming. The programmer used MCR's and JMP's almost as often as XIC's. The system was full of TTL and encoders. The result was a fast running program that for all its complexity, was stable and reliable.

The rest of the system was designed to a very high standard, and installed to that same standard. End result, very little troubleshooting had to be done. Maintenance was a different matter. Tuning was yet another. Still, if you had the smarts to tune the system, and kept all the parts in good condition, the machine simply ran. Plant managers dream.



I almost forgot, the documentation filled several volumes.



Point being, sometimes, with a complicated system, the controls/programming is just as complicated, and not the ideal playground for the tinkering want-a-be.



So simplicity a matter of circumstances, if yours justifies a very simple straight forward approach, fine, if not, the machine still has to run.
 
Great forum. First post, so forgive the FNG if I cause irritation.

A lot of good points made already.

It sounds obvious, but it may be helpful to point out that good practice may just be the absence of bad practice. It's hard to say what makes code easy to read and maintain, but very easy for me to list what makes it terrible.

After being unemployed for about 6 months, I had some consulting jobs find me. Fixing/finishing PLC (AB and idec) programming where the origional programmers had either quit, or been fired, so I have recent experience with what I consider poor code.

First is a thing I've cleaned up in a couple of programs, and from what I have seen, it is a sin common to many PLC programmers (I was guilty of it on my first couple of projects, in fact):

If part of a process has, say six valid states, DO NOT use 6 boolian variables (internal relays, bits, flags, whatever you want to call them) to represent these 6 states. Only use a boolian (one) if you are sure there will only ever be, at most, two states.


Instead use one integer variable (Data register- whatever) and put a state number in there. You can always add more valid states later on, so there is no restriction here. One simple test can insure that it does not get set to illeagle values (assuming you don't skip around).

You can then test that integer to figure out which state you're in. You can then only be in one state at a time, and no logic at all is required to force that to be true. Yes, a compare eats more time and memory than a simple contact, but you make up for it reliability, readability, etc. Also consider that the boolian approach requires lots of logic to prevent more than one state at a time. If you ever do manage to create enough logic to reliably insure that no more than one of those boolians is true at once, there is no way the next guy will be able to follow it.


Two real world examples of this:

-A step-by-step process that used a series of internal relays where each step finished by clearing it's own relay, and setting the relay for the next step. All kinds of micky mouse stuff replaced by a "step counter". As it turned out, the process later had to be modified to skip some steps under certain conditions, and it was simple to just advance the step counter to where it needed to go, rather than insuring the correct relays got set and cleared.

-A water treatment system which used two sand-filters. Three valves at inlet, and three at outlet for each filter. Only 4 permissable states (of 64 possible) for the 6 valves on each filter. So origoinal progammer had 4 boolians per filter to establish the state. Of course two or more of these would sometimes get set at the same time, and of course the code was so convoluted it was impossible for me to figure out why. After about 8 hours of trying to make it work the way it was orgiounally written, I spent a couple hours re-writing and debugging it so each filter had ONE state register, and all (those) problems were solved.



Next thing:

I like to see all the conditions that establish the state of an output (or anything, but it usually comes up with outputs) on the same rung as the output coil. It can lead to some messy looking rungs, but it is way easier to debug.

Instead, I see one or two conditons that control an intermediate relay,
and then a couple of those relays controlling a third intermediate relay, and finally that last intermediate contact doing absolutlely nothing except controlling one coil. Thus the four rungs that control the one output are scattered all over the code, and you have to do a lot of backtracking to find any problems.

I understand the argument for doing it this way. Some of those intermediate relays may be used elsewhere, and if you get it right on the rung where it is controlled, then you don't have to fix it three other places. But then when the next guy has to fix it, he has to find the three places that broke when he fixed the fourth one.

The way I see it, for every byte of memory and microsecond of cycle time that this "effiency" saves will cost about an hour of troubleshooting.

Anyway, I'd preach for some middle ground. It seems pretty stupid to me to have logic controlling an internal relay who's only function is to drive a single output. If you need to trace back more than two rungs to determine what inputs/conditions control a given output, then the programmer was being too fancy.

As for naming conventions: [rant] It is perfectly obvious to anyone looking at ladder logic when they are looking at a relay. Therefore, using the word "relay" in every freaking variable name that is in fact a "relay" is just stupid. In fact, I can tell if it is an internal relay, or a special function relay by it's allocation prefix, so "internal" and "special function" don't need to be in the name either. Please use the keystrokes thus saved to provide less cryptic information about the actual function of these "relays". The same applies to registers, inputs, and outputs. Thank you. [/rant]


As for how to segment, or organize a program. Putting all the valve controls in one module, and all the pump controls in another, and all the level controls in a third may make sense when you start.

However, since the pumps require that certain valves be set a certain way, and those pumps are used to control the levels, then the guy troubleshooting will end up bouncing between all your modules to solve every single problem. And, to make it all work, your going to have lots of intermediate variables to communicate states between those modules. So your nice, well organized program is anything but when viewed from the standpoint of "why process X isn't working".

Thus I find it much easier if the program is modular in the form of having all the controls for each process bunched togethor. Sometimes processes interact, or share resources, so this doesn't always work out though.

Sorry for the ranting. First time I've encountered a group who whould understand these issues, and couldn't resist temptation to vent.


ciao,
Kevin
 
Kevbo,

Welcome to Phil's great site :D

Sorry for the ranting. First time I've encountered a group who whould understand these issues, and couldn't resist temptation to vent
there's no reason to be sorry, we all do it...nice 1st post :site:
 
Hi Kevbo,

Thanks for the excellent "bad" examples! Especially the 6 boolean flags vs. one integer - that is an excellent example for how to simplify things so they're easier to write, easier to read, easier to understand, maintain, and extend.

And I agree, good structure/organization is definitely one of those things that look different once you have some experience with troubleshooting...

-Rhonda
 
Program rev

JTN we went through the same thing here. With a program terminal at each machine center, a laptop and one in the shop it was difficult to keep up. I ran many feet of Cat5e and networked the terminals to a server at the center of the Mill. Everyone now saves updates to the server, and saves locally to each program terminal hard drive. Laptops just plug in and files are saved that way. As for programming, Kiss, Simple may not be the best description to use, how about understandable. The word simple does not mean incomplete or short. If the code cant handle errors that commonly occure, it is not good programming. Here in the woods, when a machine goes down, the clock starts ticking.....after 2 min the shift lead hand shows up and wants to know what is going on...at 10 min the white hats start to accumulate into a herd and many offer their advice and keep asking how much longer....at 15 min the manager shows up and every where the electrician goes the white hat herd follows pushing buttons and cleaning photoeyes,asking if it going to be much longer...at 20 min you are tracing the logic on line for the third time and there is this herd of white hats all around you asking why some bits are flashing and others are not and why it is taking so long. At this point the computer room is full of people dicussing their last hernia operation and the weather with the topic changing every min or so. For me guys and gals.. if I can easily trace the logic and find the problem before the herd starts to form I'm a happy camper :) Have a good weekend !!!
 
Kevbo said:
Instead use one integer variable (Data register- whatever) and put a state number in there. You can always add more valid states later on, so there is no restriction here. One simple test can insure that it does not get set to illeagle values (assuming you don't skip around).



ciao,
Kevin

Hi to all.



Firstly I would like to say how pleased I am to have found this site. I have used some of the comments made on this site to convince the powers that be to effect some policy changes regarding our implementation of the control philosophy for our multiple sites, so well done to all. I also feel that the regulars here are the most knowledgeable off all programmers I have spoken to, especially local ones.



Kevbo, (or any one else) could you please give a bit more detail on the comment I quoted from your lat post? Would it be possible for you to give a code example of the two principals? Iam new here so if you (the room) feel that I should start a new topic requesting this, please feel free to point it out.
 
Hi all, I red a lot of contributions from fellows troubleshooting PLC at 3AM, I d'like to add mine.


Something that drives me crazy is variables that are never written or/and do not appear in the cross references.
This happens when you process a complete word and use a single bit out of it or indirect adressing.

Siemens PLC's use PW, so if you write a 16 bits word to the output board's PW, you access 16 outputs. However A12.4 is NEVER used in the program, now start investigating why that &é#çù*§ relay do not energize, good luck...

I had to write specifications for PLC programming and this way of adressing bits was forbidden !

Hope this helps

Antoine.
 
DDV said:
Kevbo, (or any one else) could you please give a bit more detail on the comment I quoted from your lat post? Would it be possible for you to give a code example of the two principals?

I'm new to forum as well, so spiffy graphics are something for the future. We'll see if ascii art will work. Note that this is just off the cuff generic notation, and specifics will vary by PLC.

"Bad" way looks like this:

State 1
|---| |---------------[State 1 stuff]---|


State 2
|---| |---------------[State 2 stuff]---|


State 3
|---| |---------------[State 3 stuff]---|


etc. The problem is that it can be tricky to keep the state relays from being set at the same time. It can be done, but it is confusing, and easy for the "next guy" to mess up.

Better (according to me anyhow) way:


|---[statereg = 1?]---[State 1 stuff]---|

|---[statereg = 2?]---[State 2 stuff]---|

|---[statereg = 3?]---[State 3 stuff]---|

|---[statereg >= 4?]--[error handling stuff]---|

Now it is only possible to have one state active at a time. statereg can be set to zero if none of the states are active, and the last line provides a simple check for illeagle states.

The only time I'd want to see it done the first way is if there are only two possible (including future changes) states, and then it would be:

Estop
|---|/ |---------------[normal mode stuff]---|


Estop
|---| |-----------[Emergency stop stuff]---|


Note that this is not the greatest example, because normally you'd want emergency stop conditions to be implimented in dedicated hardware....Estop condition is just the first thing I thought of where there are only two possible states, and you can know for sure (probably) that a third related state will never be added.

The NC and NO contacts are equivilent to comparing the bit to 0 and 1 in this case.
 
Three big rules come to mind...

* Use state machines and minimize the number of state variables.

* Transfer all I/O via a mapping layer to internal coils. You can then have a set of rungs to actually map the stuff to real I/O. This makes debugging a lot easire, and allows better isolation from the real world system you're controlling.

* Do a similar thing with comms. Group all you IN and OUT comms data into blocks. This keeps your comms quicker, and makes it clearer who is changing what. Again, use a mapping layer if possible.
 
I am currently working on a mobile stacker that operates on rails. It can move west or east. The previous programmer made it possible to select east and west at the same time and then changed the value in each start delay timer so that the correct one would beat the other to the punch. Talk about confusing. I didn't consider the reg=1=west or reg=2=east, will definately put that one into my bag of tricks.
Thanks Kevbo and welcome.

Brian.
 
Please don't take this as a challenge. I'd really like to understand where you are coming from.

MikeGranby said:
......
* Transfer all I/O via a mapping layer to internal coils. You can then have a set of rungs to actually map the stuff to real I/O. This makes debugging a lot easire, and allows better isolation from the real world system you're controlling.


Could you please elaborate on how/why this makes debugging easier? Seems like one more layer of obfuscation to me. I'm not getting how logically "isolating" the program from the real world makes for a more understandable/maintainable program.

One of the programs I have to maintain was done this way (AND HOW!) and I've lost count of the number of times I've wondered what the origional programmer was smok....ummm....thinking.
 

Similar Topics

I'm looking for some starter kits but there aren't so many on the market, so I'm thinking about buying individual components for my needs. I just...
Replies
15
Views
2,370
Good Day Friends! I really want to advance in PLC Programming like our guys here in this forum, and I'm Pleading to all friends here to help by...
Replies
5
Views
2,719
hi al.. i am a bigginer to plc programming..ladder logic can anybody pls suggest the best programming practices using in industries..
Replies
21
Views
5,156
Morning folks--I have been programming in RS 5 and 500 for quite a few years. I need to get proficient in navigating in 5000 and I would like to...
Replies
3
Views
1,785
Hi, Following a large project our company recently finished, I would like to ask what is the best method for object oriented programming. We...
Replies
10
Views
12,378
Back
Top Bottom