0

Problem

I have a PLC hooked up to several motors (which are all of the same type) via CanOpen. The PLC is programmed using CodeSys with "Structured Text". In order to activate the motors each one has to run through an initialization state machine, for which I have to send some commands in sequence (Power on, activate etc.). But as far as I understand I have to explicitly assign a variable for each boolean which has to be activated (mot1_power_on, mot2_power_on, mot1_enable, mot2_enable etc.).

Question

How to efficiently initialize several (likewise) motors with CodeSys and structured text, where each has to run through a initialization state machine? I find it bad practice to assign a bool for each motor and each variable and then programming the same code several times. How can this task be handled efficiently? Is there a way to pass the motor or some struct to some function, which then performs this task for each of the motors? In C++ I would instantiate a class to perform this task, but how can this be done in CodeSys where I have to explicitly assign a variable for each motor?

Background

I am new to codesys, but I have some background in c/c++, matlab, python and other coding languages.

U_flow
  • 475
  • 5
  • 18
  • If you believe you could solve this in C++ using a class, then try using a Function Block which is essentially a CODESYS class. You can define a [FB_Init](https://help.codesys.com/api-content/2/codesys/3.5.12.0/en/_cds_method_fb_init_fb_reinit/) method if you need a custom cunstructor – Guiorgy May 07 '21 at 12:00
  • Define structure that contain all properties of motor including FB that runs it. Define an array of those structures. In a cycle perform any operation you like. – Sergey Romanov May 09 '21 at 07:58

1 Answers1

1

Having programmed in C++, I will assume you are familiar with object-oriented programming. Function blocks in CODESYS are really similar to classes in OO languages. So go ahead and create a "motors" class with whatever member variable and methods you wish to use. Instantiate this class for each of your motors (either through individual variables or an array), and make sure whatever code needs to run is called, somehow, from your main program.

I expect the part that will not feel as natural is the part about I/O, and this is what you refer to when you say "assign a variable for each boolean". Because in your project, the (probably BIT rather than BOOL) values you need to read and write have hardware addresses (like %I12.3, %Q3.2). Once you have the classes/instances in place, you still need to tell each instance where to find its own I/O. You would rather not use separate global variables for that, which could lead to code duplication, right?

Here is one way to do it:

  • Create a structure for each I/O memory block you want to address. The simplest case is all inputs variables are together in I/O memory, and all outputs variables are together too, so that means two structures to define. These structures must match the I/O memory layout bit for bit.

  • Be careful that TRUE/FALSE I/O is generally exposed as BIT values. When you include consecutive BIT members in your structures, CODESYS will pack them inside bytes (whereas BOOL take up at least one full byte). BIT members are very often needed to ensure a structure matches the true layout of values in I/O memory. Be mindful that all types other than BIT are byte-aligned ; as an example, a lonely BIT variable between to BYTE variables will take up a whole byte.

  • In your function block, declare variables using your structures as a type, with undefined addresses.

     inputs AT %I*: MY_INPUTS_STRUCTURE;
     outputs AT %Q*: MY_OUTPUTS_STRUCTURE;
    
  • These undefined addresses essentially act as references. Each instance of your function block will receive its own, independent reference. In other for that to work, you have, however, to "map" those undefined addresses to hardware addresses. Under CODESYS this can be done in a couple of ways : you can go to the mapping page of the motor in the project and do it for each variable individually, or you can add a VAR_CONFIG to your project, which will allow you to have one mapping per structure (no need to associate each variable in the structure individually).

  • Note that when mapping whole structures rather than individual variables, you may have byte order (little-endian vs big-endian) issues to deal with when using multi-byte types if the fieldbus byte order differs from the CPU byte order.

It may seem a bit heavy at first, but once you figure it out it really is not, and it allows you to create function blocks with I/O that can be put in libraries and reused in many projects.

Fred
  • 6,590
  • 9
  • 20
  • Thanks for your answer, regarding your io idea, I did something similar in which I create struct to hold All Motor variables and referenced them to the specific instance. However I did Not find classes in codesys, but that is exactly what I need. Do you have a tutorial or Video which explains how to create classes in codesys? – U_flow Jan 09 '22 at 15:35
  • What you will use as classes are called function blocks, and they are a type of POU (program organization unit). To create one, right-click on the container for the function block, select "New object / POU", select the "function block" type, and the implementation language at the bottom (I do everything in structured text). FB can be created in side the Application object of the device, but there is a dedicated POU pane in CODESYS (Alt+1 is the default keyboard shortcut) where FB will be accessible to all devices and applications. – Fred Jan 09 '22 at 16:05
  • This is a tutorial that shows the dialog box used to create a function block : https://www.youtube.com/watch?v=SLQEtTvi3m8. If you are used to text-based programming languages (which everyone outside automation calls "programming languages"), remember that the other languages are not mandatory, and function blocks to not have to be made with the aim of integrating them in a visual programming language. – Fred Jan 09 '22 at 16:22
  • @Fred, can you shown an example of this methode? Especially the layout of such memory I/O block and Input/Output structure? I'm having a hard time figuring it out and don't get is right. – SturmGhost Apr 03 '23 at 12:30
  • It is very difficult to show an example, because the example would need to define MY_INPUTS_STRUCTURE and MY_OUTPUTS_STRUCTURE. Those structures are 100% dependent on what actual I/O you have. Is it a simple I/O card with 8 individual bits? Is it a bigger and more complex structure on a Profinet connection with a mix of bit values, byte values and multi-byte values (which may have byte ordering issues). Figuring this all out goes way beyond the scope of my answer. – Fred Apr 04 '23 at 13:16