FBD for TwinCat Beckhoff... Function Block Input Output How is this working - plc

Seems IW_PR_Schrittnummer is only referenced in 3 spots... where it's declared and where its read in the fbd routine... I guess what I'm asking is something writing a number to this variable... or what? If so how would I find it... also what is the action being performed by this first function block? looks like there are 4 inputs, Auto, is Auto Active, does tasknumber = 0, and is Press Free. if all 4 of these are true... then End Auto. Does that sound right??? someone else programmed this for a job that does work. The tags are in German.
1st FBD
Variable Reference
Variable Declaration
2nd fbd just for reference

The IW_PR_Schrittnummer is linked to input I/O using AT %ID716 command. So it gets its value from I/O memory. That basically means that "take this value from input memory at address 716 and the size is D (double word, 32 bits).
I'm not sure how you can check what is in that address when it's defined with direct addressing like this. Hopefully someone else knows a good tip for this!
More info about addresses: https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/18014401038842507.html&id=6547931155168793261
More info about addresses: https://help.codesys.com/webapp/_cds_at_declaration;product=codesys;version=3.5.15.0
That logic from your 1st image works as you said. So AutoFinde will be TRUE, if Auto, AutoAktiv, IstFrei are all TRUE and the input IW_PR_Schrittnummer is 0. Otherwise the AutoFinde will always be FALSE.

Related

Setting up openai gym

I've been given a task to set up an openai toy gym which can only be solved by an agent with memory. I've been given an example with two doors, and at time t = 0 I'm shown either 1 or -1. At t = 1 I can move to correct door and open it.
Does anyone know how I would go about starting out? I want to show that a2c or ppo can solve this using an lstm policy. How do I go about setting up environment, etc?
To create a new environment in gym format, it should have the 5 functions mentioned in the gym.core file.
https://github.com/openai/gym/blob/e689f93a425d97489e590bba0a7d4518de0dcc03/gym/core.py#L11-L35
To lay this down in steps-
Define observation space and action space for your environment, preferably using gym.spaces module.
Write down the step function which performs agent's action and returns a 4 tuple containing - next set of observations from the environment , reward ,
done - a boolean indicating whether the episode is over , and some extra info if you want.
Write a reset function for the environment to reinitialise the episode to a random start state and return a 4 tuple similar to step.
These functions are enough to be able to run an RL agent on your environment.
You can skip the render, seed and close functions if you want.
For the task you have defined,you can model the observation and action space using Discrete(2). 0 for first door and 1 for second door.
Reset would return in it's observation which door has the reward.
Then agent would choose either of the door - 0 or 1.
Then perform a environment step by calling step(action), which will return agent's reward and done flag as true - signifying that the episode is over.
Frankly, the problem you describe seems too simple to accomplish for any reinforcement learning algorithm, but I assume you have provided that as an example.
Remembering for longer horizons is usually harder.
You can read their documentation and toy environments to understand how to create one.

How to set baudrate on TwinCAT3 PLC for EL6002 or EL6001 comport?

I cannot find how to set baudrate for the Beckhoff EL6002. I got a hint that I should use CoeWrite block for that but as I am bit new to TwinCAT I cannot find the correct function block. Could someone send a code example (on structured text) how to do that?
An alternative to programming it would be to configure it directly via the IO configuration. If you add a Startup value, it will be set every time the IO changes from a specified state to another. In the pic below, PS means when going from Pre-Op to Safety. So it will work, even if you replace the IO.
Another solution is to change it under the IO configuration and COE-online tab. When you update it there, it will always remember the value.
In code, you can update it through CoE (Can over EtherCAT) too. You can find the index number of the setting variable from documentation. For channel 1, it seems to be 8000:11 so index = 8000 and subindex = 11.
Then by using mailbox writer block (FB_EcCoESdoWriteEx) from Tc2_EtherCAT library it is possible to write a value to that parameter. So when your PLC program starts, first run the code that updates the variable to desired baudrate.
For example, something like this:
TargetValue := 1; //WORD, Check documentation for correct value
//MailBoxWriter = Instance of FB_EcCoESdoWriteEx
MailBoxWriter(
sNetId:= **AmsNetId of the EtherCAT master**,
nSlaveAddr:= **Serial interface terminal port**,
nSubIndex:= 11,
nIndex:= 8000,
pSrcBuf:= ADR(TargetValue),
cbBufLen:= SIZEOF(TargetValue),
bExecute:= TRUE,
tTimeout:= T#500MS,
bCompleteAccess:= FALSE,
bBusy=> ,
bError=> ,
nErrId=>
);
The sNetIdis AmsNetId of the EtherCAT bus master. It can be linked from IO configuration, see Master->Infodata->AmsNetId.
The nSlaveAddr is terminal port from EL6002 and it can be linked from IO configuration, see Terminal->InfoData->AdsAddr->port.

Very few write cycles in stm32f4

I'm using a STM32F401VCT6U "discovery" board, and I need to provide a way for the user to write addresses in memory at runtime.
I wrote what can be simplified to the following function:
uint8_t Write(uint32_t address, uint8_t* values, uint8_t count)
{
uint8_t index;
for (index = 0; index < count; ++index) {
if (IS_FLASH_ADDRESS(address+index)) {
/* flash write */
FLASH_Unlock();
if (FLASH_ProgramByte(address+index, values[index]) != FLASH_COMPLETE) {
return FLASH_ERROR;
}
FLASH_Lock();
} else {
/* ram write */
((uint8_t*)address)[index] = values[index]
}
}
return NO_ERROR;
}
In the above, address is the base address, values is a buffer of size at least count which contains the bytes to write to memory and count the number of bytes to write.
Now, my problem is the following: when the above function is called with a base address in flash and count=100, it works normally the first few times, writing the passed values buffer to flash. After those first few calls however, I cannot write just any value anymore: I can only reset bits in the values in flash, eg an attempt to write 0xFF to 0x7F will leave 0x7F in the flash, while writing 0xFE to 0x7F will leave 0x7E, and 0x00 to any value will be successful (but no other value will be writable to the address afterwards).
I can still write normally to other addresses in the flash by changing the base address, but again only a few times (two or three calls with count=100).
This behaviour suggests that the maximum write count of the flash has been reached, but I cannot imagine it can be so fast. I'd expect at the very least 10,000 writes before exhaustion.
So what am I doing wrong?
You have missunderstood how flash works - it is not for example as straight forward as writing EEPROM. The behaviour you are discribing is normal for flash.
To repeatidly write the same address of flash the whole sector must be first erased using FLASH_EraseSector. Generally any data that needs to preserved during this erase needs to be either buffered in RAM or in another flash sector.
If you are repeatidly writing a small block of data and are worried about flash burnout do to many erase write cycles you would want to write an interface to the flash where each write you move your data along the flash sector to unwriten flash, keeping track of its current offset from the start of sector. Only then when you run out of bytes in the sector would you need to erase and start again at start of sector.
ST's "right way" is detailed in AN3969: EEPROM emulation in STM32F40x/STM32F41x microcontrollers
This is more or less the process:
Reserve two Flash pages
Write the latest data to the next available location along with its 'EEPROM address'
When you run out of room on the first page, write all of the latest values to the second page and erase the first
Begin writing values where you left off on page 2
When you run out of room on page 2, repeat on page 1
This is insane, but I didn't come up with it.
I have a working and tested solution, but it is rather different from #Ricibob's answer, so I decided to make this an answer.
Since my user can write anywhere in select flash sector, my application cannot handle the responsability of erasing the sector when needed while buffering to RAM only the data that need to be preserved.
As a result, I transferred to my user the responsability of erasing the sector when a write to it doesn't work (this way, the user remains free to use another address in the sector to avoid too many write-erase cycles).
Solution
Basically, I expose a write(uint32_t startAddress, uint8_t count, uint8_t* values) function that has a WRITE_SUCCESSFUL return code and a CANNOT_WRITE_FLASH in case of failure.
I also provide my user with a getSector(uint32_t address) function that returns the id, start address and end address of the sector corresponding to the address passed as a parameter. This way, the user knows what range of address is affected by the erase operation.
Lastly, I expose an eraseSector(uint8_t sectorID) function that erase the flash sector whose id has been passed as a parameter.
Erase Policy
The policy for a failed write is different from #Ricibob's suggestion of "erase if the value in flash is different of FF", as it is documented in the Flash programming manual that a write will succeed as long as it is only bitreset (which matches the behavior I observed in the question):
Note: Successive write operations are possible without the need of an erase operation when
changing bits from ‘1’ to ‘0’.
Writing ‘1’ requires a Flash memory erase operation.
If an erase and a program operation are requested simultaneously, the erase operation is
performed first.
So I use the macro CAN_WRITE(a,b), where a is the original value in flash and b the desired value. The macro is defined as:
!(~a & b)
which works because:
the logical not (!) will transform 0 to true and everything else to false, so ~a & b must equal 0 for the macro to be true;
any bit at 1 in a is at 0 in ~a, so it will be 0 whatever its value in b is (you can transform a 1 in 1 or 0);
if a bit is 0 in a, then it is 1 in ~a, if b equals 1 then ~a & b != 0 and we cannot write, if bequals 0 it's OK (you can transform a 0 to 0 only, not to 1).
List of flash sector in STM32F4
Lastly and for future reference (as it is not that easy to find), the list of sectors of flash in STM32 can be found on page 7 of the Flash programming manual.

CJ1W-CT021 Card Error Omron PLC

I got this error on a CJ1W-CT021 card. It happen all of a sudden after its been running the program for some time. How i found it was by going to the IO Table and Unit Set up. Clicked on parameters for that card and found two settings in red.
Output Control Mode and And/Or Counter Output Patterns. This was there reading
Output Control Mode = 0x40 No Applicable Set Data
And/Or Counter Output Patterns = 0x64 No Applicable Set Data
no idea on how or why these would change they should of been
Output Control Mode = Range Mode
And/Or Counter Output Patterns = Logically Or
I have added some new code, but nothing big or really even used as i had the outputs of the new rungs jumped out. One thing i thought might cause this is every cycle of the program it was checking the value of an encoder connected to this card. Maybe checking it too offten? Anyhow if anyone has any idea what these do or how they would change please post.
Thanks
Glen
EDIT.. I wanted to add the bits i used, dont think any are part of this cards internal io but i may be wrong?
Work bits 66.01 - 66.06 , 60.02 - 60.07 , 160.12, 160.01 - 160.04, 161.02, 161.03
and
Data Bits (D)20720, 20500, 20600, 20000, 20590, 20040
I would check section 4-1 through 4-2-4 of the CT021 manual - make sure you aren't writing to reserved memory locations used for configuration data of the CT021 unit.
EDIT:
1) Check Page 26 of the above manual to see the location of the machine switch settings. The bottom dial sets the '1's digit and the top dial sets the '10's digit (ie machine number can be 0-99);
2) Per page 94, D-Memory is allocated from D20000 + (N X 100) (400 Words) where N is equal to the machine number.
I would guess that your machine number is set to 0 (ie: both dials at '0'), 5, or 6. In the case of machine number '0', this would make the reserved DM range D20000 -> D20399. In this case (see pages 97, 105) D20000 would contain configuration data for Output Control Mode (bits 00-07) and Counter Output Patterns (bits 08-15). It looks like you are writing 0x6440 to D20000 (or D20500, D20600 for machine number 5 or 6, respectively) and are corrupting the configuration data.
If your machine number is 0 then stay away from D20000-D20399 unless you are directly trying to modify the counter's configuration state (ie: don't use them in your program!).
If the machine number is 1 then likewise for D20100-D20499, etc. If you have multiple counters they can overlap ranges so they should always be set with machine numbers which are 4 apart from each other.

What is a Flag in CX-Programmer?

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.