If a state machine is called periodically (in MatLAB Simulink or PLC program), is it possible to transition between states during the same plc cycle/simulink step?.
In Twincat 3 (PLC) there is such an option "Cycle-internal" as in link below:
https://infosys.beckhoff.com/content/1033/tf1910_tc3_uml/63050395607969163.html
are there any constraints to use such option? would the system still be real time capable?
Edited as I can't write a long comment:
1- In your example, If the state is an In-Cycle state and is responsible for generating set points for the motor till it reaches the required set point (hence taking a lot of time). The program can be "stuck" in this state causing a task overrun, and violating the real time constraints.
Suggested solution: Control the max. number of calls for this state with the variable "Max. DO cycle calls" : https://infosys.beckhoff.com/english.php?content=../content/1033/tf1910_tc3_uml/63050395607969163.html&id=, or is it possible/better to implement this task in a separate PLC task?
2- For a state chart with no In-Cycle states, the program stops excuting the chart, saves the states, and execute the rest of the program after ONE evaluation of the current active state(s).
If all states in the chart are In-Cycle, where does the program stops excuting the chart to execute the rest of the program?
Is the only solution is to have some states that are not In-Cycle and making sure they are reached fast enough not to cause a task overrun?
Yes this is possible. It is completely dependent on how you define your state machine code. The answer by Filippo explains how the Cycle-Internal option could be used.
Another way to look at this is that in Structured Text normally a state machine would be implemented with a Case structure.
In order to have multiple states within a single cycle you would require two Case structures or run the same Case structure twice (With a For or While loop for example)
For example if let's say you would like to act on an error state as soon as you move to the error state. Your first Case statement would transition the state to "Error".
In your second Case statement you would check for an "Error" state and act on it immediately.
A PLC is made to be real time capable, so to answer your last question, yes the system is real time capable regardless of the programming language you are using.
When you use the tf1910 extension, code for the Beckhoff runtime is generated in the background, which will run cyclically every x ms depending on your configurations.
Translating the Cycle-Internal operation to a structured language could look like this:
Imagine you have a software-component Motor which extends a software-component StateMachine.
StateMachine defines different (primitive) states like Init, Ready, Busy, Idle, Error etc.
V Boot()
|
|
<Init>
|
|
| Start()
|
|
<Ready> -----------<--------------+-------------<-----------+
| | |
| | |
| Execute() | |
| | |
| | |
| | Reset() |
<Prepare> | |
| | |
| | |
| | |
Wait() | Fault() | |
<Waiting> ---<-------->--- <Busy> ----------->----------- <Error> |
EndWait() | |
| |
| |
| |
| Done() |
| |
| |
| |
<Idle> ---------------------->------------------------------+
As a consequence Motor also inherits those states.
Now, if Motor is in the Init state, calling the Start() method will change the state from Init to Ready.
Depending on the architecture of your program this change can have an immediate effect on the program flow (this means in the current cycle) or in the next cycle.
Let's say, our StateMachine Function Block implements Cycle-Internal as a boolean input variable: bCycleInternal
and it's current state as an enumaration variable: eStateMachine
Let's also say that, depending on the value of eStateMachine (thus the current state of the state machine), StateMachine calls a specific method (e.g. for Init Init(), for Ready Ready() etc.)
When bCycleInternal is true and the Start() method changes the current state from Init to Ready, Ready() is called directly after Init() in the same cycle.
Otherwise, if bCycleInternal is false, when changing the state of the state machine (or the value of eStateMachine) from Init to Ready with the Start() method, Ready() is called not before the next cycle.
Related
I'm having statefull service, and I'm using reliable dictionary as a work item store. Code-wise:
var workItemStore =
this.StateManager.GetOrAddAsync<IReliableDictionary<TKey, TValue>>(storeName);
Debugging internals shows this is a returns a wrapper over DistributedDictionary class, that is using TStore class to do heavy lifting.
I have a work item processor (kind of like queue), in which I'm adding values to this store (workItemStore) and after I'm done I'm removing them. However when I make memory dump I still can see the old (removed) keys and values to be present even after explicitly GC.Collect().
Sample memory dump:
Object type | Count | Size (Bytes) | Inclusive Size (Bytes)
-------------------------------------------------------------------------------------
LockManager | 10,635 | 53,526,856 | 511,008,280
ReaderWriterLockSlim | 2,772,648 | 261,374,208 | 248,745,216
TStore<Guid, WorkItem, ...> | 3,236 | 15,999,256 | 216,851,864
Dictionary<UInt64, LockHashValue> | 2,772,560 | 217,807,600 | 207,288,816
Drilling down LockManager, ReaderWriterLockSlim and Dictionary<UInt64, LockHashValue> points to values in TStore.
Is there a way how to force cleanup of items from IReliableDictionary (i.e. remove removed items from memory) ?
After digging into this the problem is that removal is only logical removal - it doesn't actually remove items from memory. The removal should happen eventually though when in-memory changes are serialized to disk.
I'm trying to learn by programming for a Bosch/Rexroth MLC. I wrote this sequence, but I'm not sure if there's a better way to do things.
Pseudo-code would look something like this:
wRunningCount=300
wStandstillCount=150
wCount
zeroSpeed
IF zeroSpeed THEN
wCount=wStandstillCount
ELSE
wCount=wRunningCount
FI
But I want to move this functionality into function blocks. (Already have a TON that will receive the wCount)
Right now I have:
__MOVE____
zeroSpeed-|EN ENO|-
wStandStillCount-|_________|-wCount
__MOVE___
zeroSpeed-o|EN ENO|-
wRunningCount-|_________|-wCount
Is there some better way to do this?
depending on how you want to initialize your variables you can do this
Otherwise there is not better way to do it then you are right now.
Why can't you use the ton block in ST? The rest of your code looks pretty good.
TON_0(enable:=TRUE, PT:=T#1s);
IF TON_0.Q THEN //if timer done
//do stuff
TON_0(enable:=FALSE); //reset timer
END_IF
Most 61131 implementations will have a "SEL" block that should do this fairly nicely...
__SEL__
zerospeed |G Q|wCount
| |
wrunning |IN0 |
| |
wstandstill|IN1 |
|_______|
Imagine inter-processes communication
+--------------+ +------------+
| main_process | ==produces data somewhat to=> | monitoring |
+--------------+ +------------+
where:
the main_process is running non-stop and produces some data for monitoring
the monitoring is running only sometimes, and when it is running it should read the data produced by main_process
and when the monitoring is not running the data produced by main_process should be not saved.
The question is: How to write like "on demand" IPC?
The code for main_process is basically the next (the real one is more complicated):
use 5.014;
use warnings;
my $box = new BlackBox( callback => sub {
my ($self, $jref) = #_;
#
# processing of $jref
#
});
$box->run();
The callback is called every 2-5 seconds and as i told above, this process should run non-stop. I can't change the BlackBox.
I need:
write the processing of $jref part - what should send $jref to somewhere
and the monitoring process itself, what should read the data, when it is running...
Don't need any code, need only some pointers to the right direction, or idea how to do this, without filling up my memory or HDD, so the simplest way:
write the $jref to the file is not suitable because it will fill my HDD when the monitoring is not running.
If someone care, the $jref is a reference to json string, so i can do:
use JSON::XS qw(decode_json):
my $perlref = decode_json($$jref);
My first thought was "UDP to localhost?"
Variations on that idea include AF_UNIX or a named pipe. With a stream socket you'd do a non-blocking connect, and with the pipe you'd do O_WRONLY|O_NONBLOCK, and if you get EAGAIN just return without writing.
You can save your file handle and reuse it across multiple calls, just close it and reopen if you get EPIPE. You'll want $SIG{PIPE}='IGNORE'; hopefully the black box doesn't object to that.
The reading side is as simple as cat $path_to_fifo or nc -l -u -p $udpport, slightly harder if you do an AF_UNIX socket.
It sounds like using a socket will be enough. Choose a port number P and try to connect to the monitor from the main application (localhost:P). If the port is open, send the actual data, not the reference. If the port is closed then just ignore the data. Your monitor will listen on P and process any data received through this port.
During the reading of PLC documentation (Omron CP1L PLC and CX-Programmer), there are some missing explanation. For example, it defines "Flag" as "a bit that serves as an interface between in*struction", does that mean flag is some sort of conditional Power Flow?
It gets more confusing with the terms "Differential Up/Down", "Carry Flag"? What are flags and what do they do in the ladder logic? Are they a simple or instruction to use or just a concept that I don't really need to program in ladder?
[EDITED]
Where to add / modify / delete the flag in an instruction? I open up the edit but flag isn't there.
Ok, this is a better question.
PLCs are like any program - data is stored as different types. Think of flags as interchangeable with the term "bit", "boolean", etc. They are very important.
If you have CX-Programmer, a much better place to get information is the Instruction Reference (Help --> Instruction Reference --> yourPLC). These show time diagrams of most of the instructions and how each of the parameters and flags operate.
For example, a basic timer (TIM) works by assigning it a value. If you use a BCD type 100ms timer and assign its SV (setpoint value) a BCD value of 300 then you have created a timer with a 30 second limit (300 x 100ms). When the timer turns on it will begin counting and the PV (process value) will start from 300 and count down. When the value reaches zero the timer's flag turns ON to indicate that it has expired. If the timer's number is, say T100 then you can use T100 as a contact in another rung of logic - it will be true when the timer's execution conditions are TRUE and the timer has expired.
Differentials (UP/DOWN) are special flags which are true for only one PLC scan (ie: they are true for one execution cycle only) when their input conditions change from FALSE to TRUE (ie:OFF to ON) for UP differentials, and TRUE to FALSE (ie:ON to OFF) for DOWN differentials. You would use differentials in cases where you wanted to perform an action the moment a given condition changes.
Flags can be used for almost anything. You can use them as general booleans in your own programs, they can be parts of certain operations (ie: the CY (carry) flag is used on arithmetic operations which result in a carry - other flags are used to indicate overflows or div/0 errors, etc).
Edit again : (to answer extended question).
A basic timer's completion flag is a contact with its number. Say I have a 100ms timer, T100, which turns on when contact 10.00 is on:
10.00 ___
|-----| |---------------------------------------|TIM|
|100|
| |
|#20|
|___|
Now, once 10.00 has been ON for two seconds, the timer will elapse and the flag for timer 100, T100, will turn ON. If I had another rung where
| T100 W15.00
|-----| |-----------------------------------( )
Then work bit W15.00 would be turned on when the timer elapsed and would remain on so long as the timer's input condition remained satisfied (ie: so long as 10.00 remains ON). Flags work in different ways for different things, however. Each operation can use them in different ways.
The example from the Omron Instruction Reference (Help -> Instruction Reference -> [select PLC]) looks like this :
Well very good explanation with example and the flags value can be found in memory area it is pure binary either 0 or 1, as i was read the documentation work-bit memory location changes as per timer type e.g TIM/TIMX or TIMH or TIMHX, both are BCD timers but unit for the timer changes.
I am trying to use PLC's to monitor a race track. I will be using 3 Photo sensors to show which car crossed the finish line first. Each sensor will have be OTL (Latched) instruction. Each lane will have a light to indicate which car was in first place. The car not in first lights will not come. There will be 3 judges. At the completionof each race, once the winner has been recorded, the 3 judges will use their respective switches to reset the indicator lamps to an off state (Unlatched) in preparation for the next race.To inhibit any attempt at cheating by the race judges , the judges switches are programmed so that all 3 judges must agree to reset and a reset can only occur after all 3 cars have passed the finish line. The judges will be programmed with a One Shot Rising (OSR) instruction. It sh.ould be noted that we're working with a SLC 500 PLC. I fail to mention that Iam using Rockwell Automation software RS Logics, so please use Rockwell's instructions on your ladder logic.
This is rather straight forward. I'm answering generically for the PLC make isn't defined.
// You need 3 of these sets, one for each Lane, prefixed 1, 2, 3, accordingly
|---|Photo1|----------------|-----------(OTL1)----|
|---|OTL1|-----|/ResetCmd|--|
|--|OTL1|---|/OTL2|---|/ OTL3|----------(Light1)--|
// We have two work booleans, used in relation with the reset logic.
// All3In is an AND of all 3 OTLs indicating that all 3 cars have passed the finish line
// SomeOTLON is an OR of the 3 OTLs indicating that one or more OTL latches hasn't been reset
|--|OTL1|---|OTL2|----|OTL3|----------------------(All3In)--|
|--|OTL1|----|---------------------------------(SomeOTLON)--|
| |
|--|OTL2|----|
| |
|--|OTL3|----|
// We need 3 latches like the following, one per judge
// Essentially the Latch comes on when all 3 cars are in and the judge presses his button
// The latch comes off after all 3 OTLs dropped
|--|Judge1|---|All3In|----------|-------------(Judge1Latch)--|
| |
|--|Judge1Latch|---|SomeOTLON|--|
// Finally the Reset Command
|--|Judge1Latch|---|Judge2Latch|---|Judge3Latch|--|------(ResetCmd)--|
| |
|--|ResetCmd|------|SomeOTLON|--------------------|
Et voilĂ . Only possible trouble is if the "JudgeN" switches are not One Shot Rising (but they seem to be as per the problem text), it would be possible for a judge to make his/her push button stick and still have the ResetCmd latch on when all 3 cars arrive.