I apologize that I cannot speak the Polish language, but it seems your English is pretty good, so hopefully you can understand well enough.
The key here is a software principle called "separation of concerns." There are two concerns here:
- When any one engine should be running
- Which engine to run when any one engine is running.
Applying "separation of concerns" means that we treat these issues separately.
When one motor should be running
This can be implemented on one rung with a simple Start/Stop Circuit pattern (see
here, or almost any beginning tutorial of Ladder logic). The output ("RUN") bit of this "circuit" will be a bit that has either has a value of 0 when no engine should be running, or has a value of 1 when one engine should be running. The "separation of concerns" means that this bit does not "know"
which of the two engines should be running, only that
one of the engines should be running.
In prose, the logic for the Start/Stop Circuit can be stated like this:
IF ((value of start_command is 1) OR (value of run was 1 on the last scan cycle)) AND (stop_command is 0) THEN [assign value of run to 1] ELSE [assign value of run to 0]
In the Start/Stop Circuit pattern, the OR is implemented by the parallel branches; the AND is implemented by the parallel branches in series with a contact on the
stop command input; the assignments of either value to
run is implemented with a coil.
Which motor should be running when one motor is running (i.e. when run bit value is 1)
Fortunately, there are only two motors, so the logic for this is straightforward. We can model (represent) which engine is to run with a single bit; we will call the bit
which; the value of
which is 0 when engine 1 is to run, and the value of
which is 1 when engine 2 is to run. Let us ignore, for the moment, the problem of how to assign and/or change the value of
which, and also the problem of how to handle a lockout (blockade) of either engine, and look instead how to command the motors to run using this
which data model:
(A) IF (value of run is 1) AND (value of which is 0) THEN (assign value of engine1 to 1) ELSE (assign value of engine1 to 0)
(B) IF (value of run is 1) AND (value of which is 1) THEN (assign value of engine2 to 1) ELSE (assign value of engine2 to 0)
Note that this uses a another separation of concerns:
engine1 is dependent only on the values of
run and of
which, but does not care about the value of
engine2, and
vice versa. I mention this because it is also possible to leave the
engine1 logic alone, and make
engine2 be dependent on the result of
engine1, like this:
(B.alternate) IF (value of run is 1) AND (value of engine1 is 0) THEN (assign value of engine 2 to 1) ELSE (assign value of engine2 to 0).
In other words, if any one motor should be running, but
engine1 is not running, then
engine2 must run. I mention this because, while both of these ways to control
engine2 are simple, when we add in the logic for lockouts (blockades), it will be simpler to only apply that lockout logic to
engine1, and let the result of that logic, e.g. when
which value is 0 (i.e.
engine1 should be active if neither engine is locked out) AND
lockout1 is 1 (engine1 is locked out), propagate to the
engine2 logic via the simpler (
B.alternate) option above.
Lockout logic
Using (
B.alternate) above, we only need to apply any lockout (blockade) logic to
engine1.
- If engine1 is locked out, then engine1 must be prevented from running, independent of the state of which
- This can be implemented via an AND (value of lockout1 is 0) expression to (A) above.
- So even if run value is 1 and which value is 0, if lockout1 value is 1, then (A) says "Nie mój cyrk, nie moje małpy"
- If engine2 is locked out, then engine1 must run when run value is 1, independent of the state of which
- This can be implement via an OR (value of lockout2 is 0) expression to the (value of which is 0) clause of (A) above
So
(A) becomes:
(A.lockout) IF (value of run is 0) AND ((value of which is 0) OR (value of lockout2 is 1)) AND (value of lockout1 is 0) THEN (assign value of engine1 to 1) ELSE (assign value of engine1 to 0)
It might also be wise to add an
AND (value of lockout1 is 0) expression to
(B.alternate) above, to ensure that, in case both engines' are locked out at the same time, that neither engine will be commanded to run.
Assigning a value to which
I left this bit for last, because it is my favorite. The specification is that which the engines 1 and 2 alternate which runs each time any one engine is commanded to run. To do this, we need a simple bit of logic to execute:
Code:
which which
---]/[------( )--
The prose equivalent would be
IF which THEN (assign value of which to 0) ELSE (assign value of which to 1)
However, that code must execute as a one-shot e.g. on the single scan cycle when an engine stops running i.e. transitions from running to not running. On all other scan cycles, e.g. when an engine is running, or when an engine is not running but it was also not running on the previous scan cycle, the value of
which must
not change. I don't know what instructions are available to "Drive composer," but if there is an edge detector, the something like this might work:
Code:
run off_edge
------]N[------( )-----
where the
off_edge bit will be 1 on the scan cycle when
run transitions from 1 to 0. Then that
off_edge bit can control the
which bit like this (my favorite circuit):
Code:
off_edge which which
--+---] [-------]/[-----+----( )----
| |
| off_edge which |
+---]/[-------] [-----+
There are many other ways to toggle a bit; look at the [Downloads] link above, under the [Allen-Bradly] link, for the word "Alternator" on this web site.
One thing to mention is that, while this will work, it may not do exactly what is desired. For example, if engine 2 is locked out, the
which bit will continue to flip back and forth between 0 and 1, and when the engine 2 lockout is removed, if that happens while no engine is running, engine 1 could still be the next engine to start. Or, if engine 1 is running while the value of
lockout2 is 1, but the value of
which is 1, then ending the lockout could immediately stop engine 1 and start engine 2, and that may not be a desirable behavior. There are ways to modify this approach so that does not happen; specifically, adding the lockout logic to the coil that writes the value of
which, instead of having lockout logic before the coil that writes the value of
engine1.
Finally, the ideas provided here are meant as an example only; there are many ways to "skin this cat" (English/American idiom). There will be many threads on this website that you can find using the search terms "lead lag" that solve a similar problem. I strongly suggest you read some of those threads and think about this problem and come up with a solution that makes the most sense to you.