Post by gunstr on CODESYS control on RPi starts, shortly runs, then exits
CODESYS Forge
talk
(Post)
Thank you very much for the quick answer! The RPi hw were delivered last week so it's probably a resent version. I found an old scrapped board (2 years or so) with a broken GPIO that I tested with the same SD card image and with that board Codeys can run for the full 2h demo period without issues. Then I went back the the new board to test the 4.17.0.0 release but the installation fails... [INFORMATION] Standard output: create and install daemon [INFORMATION] Standard output: codesyscontrol started [WARNING] Unable to detect Raspberry Pi Architecture. Setting armv6l as default, you can change this through the settings panel. [INFORMATION] Standard output: codesyscontrol stopped [ERROR] Expected exit value of command failed: expected 0, received 1 [WARNING] Error setting the Raspberry Pi Architecture [ERROR] Error installing codesyscontrol Do you have any idea what could be the reason? I'm using an OS image including Python drivers for LCD and some I/O:s from last year to keep things stable, but also after upgrading with sudo apt update && sudo apt upgrade I still get the same error Reverting back to 4.15.00 works fine: [INFORMATION] Standard output: create and install daemon [INFORMATION] Standard output: codesysedge started [INFORMATION] Successfully installed codesyscontrol [INFORMATION] Successfully started CODESYS Edge Gateway for Linux [INFORMATION] Successfully started CODESYS Control for Raspberry Pi SL but as before the Codesys services stops after 30 seconds. And I noticed that the Codesys control stops and is not reachable also if I have no application loaded.
Last updated: 2025-09-02
Post by serwis on Dynamic target position tracking
CODESYS Forge
talk
(Post)
Hello, I am trying to control a servo drive and dynamically set its position. I control the drive via EtherCAT with a cycle time of 500us. I use the MC_MoveAbsolute block for this. The problem is that when using a PID controller, I generate the positions I want the drive to move to on an ongoing basis, and I would like the position to be set immediately. The MC_MoveAbsolute block must receive a rising edge to execute, and I would like the movement to be performed without waiting for this edge. I have created a function that generates a rising edge every 1 ms, but I am unable to change this time to 500 ”s because the TON function does not support times shorter than 1 ms. Below is the code to call the rising edge: IF Exe = TRUE THEN delay1(IN:=TRUE, PT:=T#1MS); IF delay1.Q = TRUE THEN Exe := FALSE; delay1(IN:=FALSE); END_IF END_IF IF Exe = FALSE THEN delay(IN:=TRUE, PT:=T#1MS); IF delay.Q = TRUE THEN Exe := TRUE; delay(IN:=FALSE); END_IF END_IF END_IF Here is the code for calling the MC_MoveAbsolute function: MoveDegree( Axis:= Tilt, Execute:= Exe, Position:= position_target - (base_angle_real * feedforward_turn), Velocity:= vel, Acceleration:= acc, Deceleration:= dec, Jerk:= jerk, Direction:= MC_DIRECTION.shortest, BufferMode:= MC_BUFFER_MODE.Aborting, Done=> , Busy=> , Active=> , CommandAborted=> , Error=> , ErrorID=> ); I realize that there are probably better methods for performing this type of task. How can I implement motion with a dynamically changing setpoint? THANKS
Last updated: 2025-09-05
Post by imdatatas on The default ramp type selection in SoftMotion V4.18.0.0 is Quadratic
CODESYS Forge
talk
(Post)
Dear @gseidel, Thank you for your clarification. I fully agree that the quadratic ramp type may have certain technical advantages. However, the main problem is backward compatibility and consistency across projects. In many automation projects, application developers rely on the fact that creating a new axis object will behave exactly the same way as in previous versions. With SoftMotion V4.18.0.0 and later, if an application developer adds an axis and overlooks the changed default, the motion function blocks behave differently than expected. In particular, since the Jerk value in SM3_Basic function blocks is ineffective in trapezoid ramp type, users are accustomed to leaving this parameter empty in their projects. In many existing projects, this variable has not even been assigned. When the default is changed to quadratic, the Jerk parameter suddenly becomes relevant, which can cause errors or unexpected behaviour in the field. From a user perspective, a default setting should always be the âsafeâ and âexpectedâ option, while alternative options (like quadratic) can be selected manually if desired. Keeping the default as trapezoid ensures compatibility with existing projects and prevents unexpected issues, while still allowing users to benefit from quadratic ramps if they explicitly choose so. For these reasons, I kindly ask you to reconsider making trapezoid the default again. This would significantly reduce the risk of unexpected behaviour in future projects while still preserving the advantages of the quadratic ramp type for those who actively select it. Of course, the final decision is entirely at your discretion. Best Regards, imdatatas
Last updated: 2025-09-26
Post by jst69 on Python script: Launch Codesys, Execute Script, Exit Codesys
CODESYS Forge
talk
(Post)
Dear all: Question about scripting: I am creating a .NET program that is supposed to Open codesys, open template project, export a bunch of pou, then exit codesys. Launch works, Open project works, Export works, But how do i tell codesys to close itself? I can tell windows to terminate codesys, but i would prefer to do it properly. from __future__ import print_function import sys import System proj = projects.primary # We're interested in POU nodes: POUGuid = Guid("6f9dac99-8de1-4efc-8465-68ac443b7d08") # We collect all POU nodes in that list. pous = [] # From the parent node on, we recursively add POU nodes: def CollectPous(node): if node.type == POUGuid: pous.append(node) else: for child in node.get_children(): CollectPous(child) # Now we collect all the leaf nodes. for node in proj.get_children(): CollectPous(node) # We print everything just to know what's going on. for i in pous: print("found: ", i.type, i.guid, i.get_name()) # And now we export the files. for candidate in pous: # We create a list of objects to export: # The object itsself objects = [candidate] # And sub-objects (POUs can have actions, properties, ...) objects.extend(candidate.get_children()) # And the parent folders. parent = candidate.parent while ((not parent.is_root) and parent.is_folder): objects.append(parent) parent = parent.parent # Create an unique file name: if len(sys.argv) == 1: filename = "parent\\%s.export" % (candidate.get_name()) else: filename = "%s\\%s.export" % (sys.argv[1],candidate.get_name()) # print some user information print("exporting ", len(objects), " objects to: ", filename) # and actually export the project. proj.export_xml(objects, filename) proj.close() print ("script finished.") System.exit(0) // Dont work .NET: public static void Export(string path,string proj) { if (checkSettings()) { var p = new System.Diagnostics.Process(); p.StartInfo.FileName = Properties.Settings.Default.CSVersion +"\\CODESYS\\Common\\CODESYS.exe"; p.StartInfo.Arguments = " --Profile=" + qoute(Properties.Settings.Default.CSProfile) + " --culture=en" + " --project=" + qoute(path + "\\" + proj) + " --runscript=" + Properties.Settings.Default.LastOpenProjectPath + "\\INPUT_DATA\\SCRIPT\\Export.py" + " --scriptargs:" + qoute(path) ; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.UseShellExecute = false; p.StartInfo.CreateNoWindow = false; p.Start(); p.StandardOutput.ReadToEnd(); p.CloseMainWindow(); p.Close(); } }
Last updated: 2024-01-16
Post by full0pullpolen on Device User Logon
CODESYS Forge
talk
(Post)
The following guide describes how you can adapt the user management for the first time in a project. It deals with the definition of a user and a group to which he belongs. Requirement: the project for which the user management is to be set up is opened. There is no adapted user configuration yet. Select Project Settings ⣠Users and Groups and then the Users tab. The user Owner is already created by default. Click on Add. â The dialog box Add User appears. Enter a login name, for example âDev1â, and a password. Leave the option Activated activated. Click on OK. â On creating a group for the first time, CODESYS now requests you to authenticate yourself to perform this action. In this case, enter âOwnerâ as the current user. Do not enter a password, just click on OK. The user Dev1 appears in the list and is automatically a member of the group 'Everyone'. Change to the tab Groups, in order to add the user to a new group. â The groups Everyone and Owner have already been created. Click on Add in order to open the dialog box Add Group. Specify at least one name for the new group, for example âDevelopersâ. Activate the checkbox next to the entry User âDev1â in the field Members. Click on OK. â The group Developers now appears with has user member 'Dev1'. Switch to the Users tab. â The user Dev1 now appears as a member of the groups âEveryoneâ and âDevelopersâ.
Last updated: 2024-01-24
Post by full0pullpolen on Device User Logon
CODESYS Forge
talk
(Post)
The following guide describes how you can adapt the user management for the first time in a project. It deals with the definition of a user and a group to which he belongs. Requirement: the project for which the user management is to be set up is opened. There is no adapted user configuration yet. Select Project Settings ⣠Users and Groups and then the Users tab. The user Owner is already created by default. Click on Add. â The dialog box Add User appears. Enter a login name, for example âDev1â, and a password. Leave the option Activated activated. Click on OK. â On creating a group for the first time, CODESYS now requests you to authenticate yourself to perform this action. In this case, enter âOwnerâ as the current user. Do not enter a password, just click on OK. The user Dev1 appears in the list and is automatically a member of the group 'Everyone'. Change to the tab Groups, in order to add the user to a new group. â The groups Everyone and Owner have already been created. Click on Add in order to open the dialog box Add Group. Specify at least one name for the new group, for example âDevelopersâ. Activate the checkbox next to the entry User âDev1â in the field Members. Click on OK. â The group Developers now appears with has user member 'Dev1'. Switch to the Users tab. â The user Dev1 now appears as a member of the groups âEveryoneâ and âDevelopersâ.
Last updated: 2024-01-24
Post by full0pullpolen on Device User Logon
CODESYS Forge
talk
(Post)
The following guide describes how you can adapt the user management for the first time in a project. It deals with the definition of a user and a group to which he belongs. Requirement: the project for which the user management is to be set up is opened. There is no adapted user configuration yet. Select Project Settings ⣠Users and Groups and then the Users tab. The user Owner is already created by default. Click on Add. â The dialog box Add User appears. Enter a login name, for example âDev1â, and a password. Leave the option Activated activated. Click on OK. â On creating a group for the first time, CODESYS now requests you to authenticate yourself to perform this action. In this case, enter âOwnerâ as the current user. Do not enter a password, just click on OK. The user Dev1 appears in the list and is automatically a member of the group 'Everyone'. Change to the tab Groups, in order to add the user to a new group. â The groups Everyone and Owner have already been created. Click on Add in order to open the dialog box Add Group. Specify at least one name for the new group, for example âDevelopersâ. Activate the checkbox next to the entry User âDev1â in the field Members. Click on OK. â The group Developers now appears with has user member 'Dev1'. Switch to the Users tab. â The user Dev1 now appears as a member of the groups âEveryoneâ and âDevelopersâ.
Last updated: 2024-01-24
Post by testlogic on Sending Sequential Modbus TCP Packets
CODESYS Forge
talk
(Post)
I have a Modbus TCP slave device where I need to do sequential writes to the same register. The register I'm writing to is kind of like a command line, each packet is a command word encoded in Hexadecimal. I am having difficulty implementing this system in CoDeSys 3.5 SP19. I feel like the structure of the program should be something along the lines of (Pseudocode): ModbusTCPSend(Command Register, Command1) ModbusTCPSend(Command Register, Command2) ModbusTCPSend(Command Register, Command3) I have tried to implement this with a rising edge trigger wMot1OPCode := 16#E1; //Stop Motor & Kill Program xMot1SendOP := TRUE; //Send OP on rising edge xMot1SendOP := FALSE; //Reset wMot1OPCode := 16#9E; //Disable Motor xMot1SendOP :=TRUE; //Send OP on rising edge xMot1SendOP := FALSE; //Reset Where "wMot1OPCode" is the IO map for writing to the command register, and "xMot1SendOP" is the rising edge trigger for that modbus channel. However, this doesn't work. The device never responds to the modbus commands. It seems like the trigger variable is switched too quickly for modbus to send the packet. I know the modbus register is working, because I can set the channel to cyclic and the device will respond. However, I can't use this reliably because I need each command to be sent once, in order. Cyclic keeps re-sending the commands and seems like it could miss a command as well if one was sent in-between cycle time. I have also trying using the Application trigger as described by https://faq.codesys.com/pages/viewpage.action?pageId=24510480, but this is also not working for me. See attached picture for my FBD code. This seems like a simple function, I can't tell what I'm doing wrong here. Thanks for the help.
Last updated: 2024-03-06
Post by manuknecht on Maximum dynamic limits of MC_MoveLinearAbsolute and MC_MoveLinearRelative
CODESYS Forge
talk
(Post)
Hello all I use an axis group with two linear axes in a kinematic system. Using MC_MoveLinearAbsolute and MC_MoveLinearRelative, I am trying to realise dynamic movements (set velocity: 1 m/s, set acceleration: 30 m/s^2) with the highest possible jerk, as I want to compare this with a movement with a trapezoidal velocity profile. However, my measurements show that the axes accelerate with a maximum jerk of approx. 800 m/s^3, even if the value in the function block was set to 10,000 m/s^3. I have already increased the dynamic limits of the two axes accordingly (Velocity: 5000 u/s, Acc-/Deceleration: 250'000 u/s^2, Jerk: 100'000'000 u/s^3, where 1 u = 1 mm), but this had no effect. I have checked the input parameters of the function blocks and the VelFactor, AccFactor and JerkFactor factors are all set to the maximum (value 1). Reducing the cycle time has resulted in a higher jerk, but as we are already working with a cycle time of 1 ms, there is nothing more that can be done here. The axes themselves are still a long way from drawing the maximum current, which is why I assume that this should not be a problem either. Are there other factors or parameters that influence the dynamic limits and therefore allow faster movements? The PLC I am using is a Raspberry Pi 4 and Codesys V3.5 SP20 with all libraries up to date. Thanks in advance Manuel
Last updated: 2024-05-08
Post by xcqt on Oop best practice
CODESYS Forge
talk
(Post)
Hi all, Iâm currently trying to improve my OOP structure in CODESYS and Iâm looking for some input on how others approach this. I understand the basics like inheritance, interfaces, abstract FBs, methods, and properties, but I still struggle a bit with the overall architecture and whatâs considered clean or scalable in bigger projects. As an example, Iâm working on two different energy meter function blocks: FB_EnergyMeter_MQTT reads data from MQTT (strings) FB_EnergyMeter_Modbus reads data from Modbus (words) Both have their own Update() method and implement the same interface (something like IF_EnergyMeter). Later on, Iâll probably add more meter types, but they should all behave the same from the controllerâs point of view. Now, thereâs a FB_GridControl block that needs power data from these meters. I see two options here: Define the meter blocks inside FB_GridControl and call them directly (for example fbModbusMeter.UpdateModbus()). Keep the meter blocks outside and pass them into FB_GridControl as interface references, so the control block doesnât know which specific type of meter itâs dealing with. Option 2 feels cleaner and more flexible to me, but Iâm not entirely sure how to handle the data flow in that case. Should I pass the meter instance through an interface reference (REFERENCE TO IF_EnergyMeter)? Or is there a better way to link the external FBs to the control block? Iâd like to hear how you structure this kind of setup or see an example from someone who has done something similar. EDIT: I think i need to do something like this fbModbusUpdateInput(wInput:= wWordValue); fbMqttUpdateInput(strInput:= strStringValue); IF bUseMqtt THEN Meter REF = fbMqttUpdateInput; ELSE Meter REF = fbModbusUpdateInput; END_IF fbControl.SetMeter(UsedMeter := Meter); Or am i thinking wrong? Thanks, Thomas
Last updated: 2025-10-16
Post by e13740e on Parameterized Property syntax for array element processing
CODESYS Forge
talk
(Post)
Since parameterized (indexed) properties are not possible, I decided to use architectural approach "Indexing Property Adapter" to achieve the intended goal â avoiding code duplication for validated access to array elements. Essence: Create a Function Block Adapter (FB_PropertyAdapter) that encapsulates the logic for working with a single element of the target array (e.g., with one settings structure). Declare Properties inside the adapter block for accessing each individual field of the data structure. All validation logic is implemented within the Set accessors of these properties. Data Binding via VAR_IN_OUT: The adapter block receives a reference to a specific data element from the global array through its VAR_IN_OUT section, which ensures direct work with the original data without copying. Create an Array of Adapters: In the parent POU (e.g., FB_SettingsManager), an array of these adapter blocks is created â one for each element of the global array that needs to be managed. Initialize Bindings: In a FOR loop, each adapter instance from the array is given a reference to the corresponding data element. Result: This approach allows accessing the data via the index of the adapter array, and then through the property name, which simulates the behavior of an indexed property: MyAdapterArray[Index].MyProperty Thus, the validation and data access logic is written only once inside the adapter block and is then reused multiple times by creating instances of it in an array. This completely solves the problem of code duplication while providing a clean, scalable, and object-oriented architecture compatible with standard CODESYS features. Question closed.
Last updated: 2025-10-19
Post by mariussandu on OPC-UA
CODESYS Forge
talk
(Post)
Hello, I am experiencing an intermittent OPC UA server issue on CODESYS Control for Raspberry Pi SL 4.21.0.0. Runtime information: codesyscontrol 4.21.0.0 Raspberry Pi 4 Model B Rev 1.1 - 4Gb OPC UA Server: CmpOPCUAServer 3.5.22.x Server IP: 192.168.0.110 OPC UA endpoint: opc.tcp://192.168.0.110:4840 The main OPC UA client is Node-RED running on 192.168.0.111. This has an active subscription with some tags and also some write functions active. The system normally works correctly for a period, but at some time the OPC UA communication stopped. Node-RED started reconnecting continuously but could not reconnect. I also tried connecting using UaExpert, but UaExpert returned: BadTimeout At the same time, the PLC application itself was still running. Before restarting CODESYS, I captured the TCP connections. The OPC UA server was still listening: tcp 11 0 192.168.0.110:4840 0.0.0.0:* LISTEN However, there were many connections from the Node-RED client stuck in CLOSE_WAIT: 192.168.0.110:4840 192.168.0.111:45008 CLOSE_WAIT 192.168.0.110:4840 192.168.0.111:53678 CLOSE_WAIT 192.168.0.110:4840 192.168.0.111:44032 CLOSE_WAIT 192.168.0.110:4840 192.168.0.111:36612 CLOSE_WAIT 192.168.0.110:4840 192.168.0.111:45012 CLOSE_WAIT 192.168.0.110:4840 192.168.0.111:36592 CLOSE_WAIT ... Some of these sockets also had data remaining in Recv-Q, for example: Recv-Q = 61 Recv-Q = 121 There were roughly 15â20 OPC UA connections in CLOSE_WAIT. Restarting only the CODESYS runtime immediately restored OPC UA communication. After restart: LISTEN 0 10 192.168.0.110:4840 and both Node-RED and UaExpert can connect normally again. There are no obvious OPC UA errors during startup or in log. On RPI 2 I had a memory leak regarding OPCUA so I had to upgrade to RPI4. What can I do in this case? Thank you!
Last updated: 2026-08-26
Post by alexgooi on Codesys KNX implementation
CODESYS Forge
talk
(Post)
Dear forum, We are currently doing some research on the Codesys KNX implementation (https://store.codesys.com/en/codesys-knx-sl.html). We almost have it working but we are missing the last part. The setup: We have a Codesys virtual control container running on docker (4.17.0.0), the I/O is running over an Ethernet IP coupler (WeidmĂŒller), and this is running fine. As far as Iâm concerned this tells me that the ethernet device is working properly (the container has access to the outside world, including multicast). Underneath this ethernet adapter the KNX module is added (see picture). In the KNX device (Codesys) 2 input variables are added (see picture), and these are exported to ETS (ETS 5). In ETS A Codesys KNX device has been imported and the Codesys export was imported, afterwards the group addresses are attached to the variables (see picture). Afterwards this configuration is downloaded to the Codesys controller (Container) via ETS. ETS asks for the pressing of the programming button, when the virtual programming button is pressed the download starts and finishes without any errors. This tells me that ETS is communicating with the Codesys controller, and that the download process is ok (so far so good). Now the part where we are struggling with, somehow we need to convert the KNX TP to KNX IP. For this we have the following interface: Zenio KIPI SC (https://www.zennio.com/product/kipi-sc/) this is a KNX TP to IP interface. We have the following setup for this device (see picture) (an IP in the same subnet is used). We tried multiple combinations of IP addresses but the TP devices are simply not communicating to the Codesys container. Does anyone has any advice on what to try next. To make the question more explicit how can we link the TP bus to the Codesys device? Kind Regards Alex
Last updated: 2026-01-05
Post by wold on CodeMeter Network Server: Keep runtime dongle local-only and export only a second CmStick
CODESYS Forge
talk
(Post)
Hello, I am running a CODESYS Control Runtime on a Raspberry Pi. Two CmSticks are connected to the same system: CmStick A - Runtime license - MultiCore license - KNX license CmStick B - Engineering / Developer licenses My goal is: The runtime on the Raspberry Pi shall use CmStick A locally. Licenses from CmStick A shall NOT be provided by the CodeMeter Network Server. Only licenses from CmStick B shall be available to remote network clients. During troubleshooting I observed that the CodeMeter Network Server collects licenses from both CmSticks. The KNX license appears to be local-only, but the runtime and multicore licenses of the same dongle are still visible through the server. I would like to know if a supported configuration exists for the following scenario: One CmStick remains strictly local to the runtime. A second CmStick on the same machine is exported through the CodeMeter Network Server. Questions: Is it possible to exclude a specific CmStick from being exported by the CodeMeter Network Server? Can this be configured via License Access Permissions (ACL), WebAdmin, or another mechanism? Can export rules be applied per CmStick, per Firm Code, or per Product Code? If supported, could you provide a configuration example or a reference to the relevant documentation? The reason for asking is that after removing a separately installed CodeMeter server component and returning to a local-only setup, the runtime licensing behaviour became stable again. Therefore I am looking for the officially supported way to keep the runtime dongle local while still providing engineering licenses from a second dongle over the network. Thank you.
Last updated: 2026-08-02
Post by dclements on Feature Request: Read-Only References / Pointer-to-Const Support
CODESYS Forge
talk
(Post)
I would like to suggest adding support for persistent read-only references or pointers in CODESYS, similar to a C++ pointer-to-const (const T*). For example, something conceptually similar to: POINTER TO CONSTANT ST_MyData or REFERENCE TO CONSTANT ST_MyData The important distinction is that the reference itself may still be passed around or reassigned, but the referenced object cannot be modified through that reference. CODESYS currently supports VAR_IN_OUT CONSTANT, which provides read-only reference semantics for parameters, but there does not appear to be an equivalent type that can be stored in a variable or returned from a method. A practical use case is a registry that owns long-lived definitions. The registry needs to retain ownership of the data while downstream systems maintain persistent references to it. Currently, the main options are: Return the struct by value, which loses reference semantics and requires a copy. Return POINTER TO ST_Definition, which allows consumers to modify registry-owned data. Convert the structure into a Function Block and expose a getter-only interface, which provides the desired encapsulation but introduces more complexity and memory overhead. A read-only reference/pointer type would allow libraries to expose persistent, zero-copy access to internally owned data while preserving encapsulation. This would be particularly useful for library APIs and object-oriented CODESYS architectures where ownership of data should remain with one component while other components are allowed to observe it. Similar requests for constant references/pointers have been discussed on CODESYS Forge previously, so this appears to be a recurring use case rather than something specific to one application.
Last updated: 2026-09-01
Post by kishan on SMC_Interpolator / CNC Abort â ControlAxisByPos Sometimes Remains Busy and Axis Continues Moving
CODESYS Forge
talk
(Post)
Hello, I am working with CODESYS SoftMotion CNC using a preprocessing chain, SMC_Interpolator, and SMC_ControlAxisByPos for controlling the CNC axes. I have noticed an issue when aborting CNC execution. When I execute the Abort command, I abort both the CNC preprocessing blocks and SMC_Interpolator. Normally the CNC process stops correctly. However, occasionally after the abort: SMC_Interpolator has already been aborted. CNC preprocessing has also been aborted/reset. But SMC_ControlAxisByPos.bBusy remains TRUE. The corresponding physical axis can still continue moving for some distance. This does not happen every time. My basic sequence is similar to: G-code / CNC preprocessing â SMC_Interpolator â Transformation â SMC_ControlAxisByPos â SoftMotion Axis When the operator requests CNC Abort, I set the Abort inputs of the interpolator and preprocessing function blocks. My questions are: Does SMC_Interpolator.bAbort only stop/reset the interpolator, or should it also stop the motion currently being executed by SMC_ControlAxisByPos? Can SMC_ControlAxisByPos remain Busy after the interpolator has been aborted? If bAvoidGaps = TRUE, could SMC_ControlAxisByPos still be trying to reach the last fSetPosition using the fGapVelocity / fGapAcceleration / fGapDeceleration settings after the interpolator has stopped? What is the recommended sequence for safely aborting a running CNC program? For example, should the sequence be something like: Stop / Abort Interpolator Disable SMC_ControlAxisByPos Execute MC_Stop for all physical axes Wait until all axes reach standstill Abort/reset preprocessing blocks and CNC queues Reset CNC state Re-enable axis controllers Or is there a recommended CODESYS CNC method for performing a complete CNC Abort? I would especially like to understand why SMC_ControlAxisByPos.bBusy can occasionally remain TRUE and continue moving the axis even though the interpolator and preprocessing blocks have already been aborted. CODESYS SoftMotion CNC is being used with real EtherCAT servo axes. Any explanation about the correct abort/stop sequence would be appreciated.
Last updated: 2026-09-25
Post by hhermsen on Codesys v3.5.22.10 - Internal error:System.AggregateException...Value cannot be null...Parameter name: expLValue
CODESYS Forge
talk
(Post)
Internal compiler error in SP22.x (expLValue null) â SP21 unaffected â need help isolating root cause I'm hitting the same internal compiler crash reported here. Same exact stack trace (AssignmentStatementReplacer â CreateAssignmentExpression â ArgumentNullException: Value cannot be null. Parameter name: expLValue), but in my case triggered by a self-written library, not a Visualization object â so this looks like a general SP22.x codegen regression rather than something tied to one specific language feature. What I've confirmed: Reverting to SP21 â no issue, builds clean SP22.x â internal compiler crash during Build > Application, code generation phase, with zero useful location info (no POU, no line number) check_for_errors/precompile-only passes cleanly; the crash only happens on a real full build, meaning static analysis never sees it coming What I've tried to isolate the cause (without success): Removed a suspected pattern involving a VAR_IN_OUT parameter used directly as a FOR-loop control variable, combined with early RETURN inside the loop â crash persisted identically afterward Confirmed no Visualization Manager or similar object in the project (ruling out the trigger in the linked report) Used an AI coding assistant (Claude Code) to search for other suspicious patterns â no luck pinpointing the exact statement Question @codesys-com Since the compiler gives no location info at all, is there any way to get more diagnostic output from the SP22.x codegen phase (verbose/debug build flags, log level settings, etc.)? Without that, isolating this in a large library means blind bisection â cutting the codebase in half repeatedly until the crash disappears, which is slow and error-prone without official tooling support. Happy to share the affected project or a minimal repro if that helps CODESYS engineering track it down.
Last updated: 2026-07-11
Post by clesio on CAA.File.Write â Unexpected characters when writing a CSV file
CODESYS Forge
talk
(Post)
Hello everyone, I am trying to create a routine in CODESYS to export a report to a CSV file using the CAA.File library. The file is created successfully, but I am getting some unexpected/unknown characters in the generated CSV. The problem seems to be related to the SIZEOF() function. I am using it for the szSize parameter of File.Write, as recommended in the CODESYS documentation. However, when I use SIZEOF(), the CSV contains extra characters and parts of previous strings. I also tried using LEN(), but in my application the file is created empty, even though the string and the calculated length appear to be correct. Here is the relevant part of my code: PROGRAM Relatorio VAR // Bool b_Executa_fb_Cria_Arquivo : BOOL; b_Executa_fb_Fecha_Arquivo : BOOL; b_Escreve_dados : BOOL; b_Erro_fb_Escreve : BOOL; //STR s_Nome_Arquivo : STRING; s_Palavra : STRING; s_Palavra_Anterior : STRING; s_Data_Atualizada_Formatada : STRING; s_Dia : STRING; s_Mes : STRING; s_Ano : STRING; s_Hora_Atualizada_Formatada : STRING; s_Hora : STRING; s_Minu : STRING; s_Segu : STRING; //INT i_modo_fb_Cria_Arquivo : INT; i_ErroID_fb_Escreve : INT; //UINT i_Tamanho_Palavra : UINT; // Blocos de Funcao fb_Cria_Arquivo : FILE.Open; fb_Fecha_Arquivo : FILE.Close; fb_Escreve : FILE.Write; // DATA E HORA sc_DataTime : SysTimeRtc.RTS_SYSTIMEDATE; // STRUCT = sc uidResultRtcGet : UDINT; //stGetDate : SysTimeRtc.RTS_SYSTIMEDATE; uidResultConvertToDate : UDINT; uidResult : RTS_IEC_RESULT; END_VAR VAR_INPUT //BOOL b_SET_Executa_fb_Cria_Arquivo : BOOL; b_RES_Executa_fb_Cria_Arquivo : BOOL; b_Executa_fb_Escrita : BOOL; // INT i_Linhas_Cabecalho : INT; i_Linhas_Cabecalho_Anterior : INT; END_VAR // Para Testes s_Nome_Arquivo := 'relatorio/Teste1M.CSV'; i_modo_fb_Cria_Arquivo := 0; // TRATAMENTO DE DATOS DATA e HORA uidResultRtcGet := SysTimeRtcGet(uidResult); uidResultConvertToDate := SysTimeRtcConvertUtcToDate(dwTimestampUtc := uidResultRtcGet, pDate := sc_DataTime); // FORMATA DATA EM UMA STRING s_Dia := UINT_TO_STRING(sc_DataTime.wDay); s_Mes := UINT_TO_STRING(sc_DataTime.wMonth); s_Ano := UINT_TO_STRING(sc_DataTime.wYear); s_Data_Atualizada_Formatada := CONCAT(s_Dia, CONCAT('/', CONCAT(s_Mes, CONCAT('/', s_Ano)))); // FORMATA HORA EM UMA STRING s_Hora := UINT_TO_STRING(sc_DataTime.wHour); s_Minu := UINT_TO_STRING(sc_DataTime.wMinute); s_Segu := UINT_TO_STRING(sc_DataTime.wSecond); s_Hora_Atualizada_Formatada := CONCAT(s_Hora, CONCAT(':', CONCAT(s_Minu, CONCAT(':', s_Segu)))); // ABRE e CRIA ARQUIVO IF (b_SET_Executa_fb_Cria_Arquivo OR b_Executa_fb_Cria_Arquivo) AND NOT(b_RES_Executa_fb_Cria_Arquivo) THEN b_Executa_fb_Cria_Arquivo := TRUE; ELSE b_Executa_fb_Cria_Arquivo := FALSE; END_IF fb_Cria_Arquivo( xExecute := b_Executa_fb_Cria_Arquivo, sFileName := s_Nome_Arquivo, eFileMode := i_modo_fb_Cria_Arquivo, xExclusive := FALSE, ); //i_Tamanho_Palavra := SizeOf(s_Palavra); // ESCREVE NO ARQUIVO fb_Escreve( xExecute := b_Executa_fb_Escrita, hFile := fb_Cria_arquivo.hFile, szSize := SIZEOF(s_Palavra), pBuffer := ADR(s_palavra) ); // FECHA ARQUIVO fb_Fecha_Arquivo( xExecute := b_Executa_fb_Fecha_Arquivo, hFile := fb_Cria_arquivo.hFile ); IF Criacao_Edicao_Arquivos.b_Escreve_Cabecalho THEN CASE i_Linhas_Cabecalho OF 1 : s_palavra := 'ESTERILIZADOR'; 2: s_palavra := 'MAQ4; $R$L'; 3: s_palavra := CONCAT(CONCAT('CLIENTE: ',GVL.sReceitaAtual), '$R$L'); 4: s_palavra := CONCAT(CONCAT('NUMERO LOTE: ',DINT_TO_STRING(GVL.Lote)), '$R$L'); 5: s_palavra := CONCAT(CONCAT('OPERADOR: ', DINT_TO_STRING(GVL.Operador)), '$R$L'); 6: s_palavra := CONCAT(CONCAT('DATA: ', s_Data_Atualizada_Formatada), '$R$L'); 7: s_palavra := CONCAT(CONCAT('HORA: ', s_Hora_Atualizada_Formatada), '$R$L'); 8: s_palavra := '$R$L'; 9: s_palavra := 'PARAMETROS AJUSTADOS $R$L'; 10: s_palavra := CONCAT('TEMPO PRE COND.: ', CONCAT(INT_TO_STRING(GVL.rc_T_PreCondicionamento), ' min $R$L')); 11: s_palavra := CONCAT('PULSOS INERTIZACAO 1: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosInertizacao_1), ' PULSOS $R$L')); 12: s_palavra := CONCAT('PULSOS INERTIZACAO 2: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosInertizacao_2), ' PULSOS $R$L')); 13: s_palavra := CONCAT('PULSOS AERACAO: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosAeracao_2), ' PULSOS $R$L')); 14: s_palavra := CONCAT('PRESSAO DE VACUO 1: ', CONCAT(REAL_TO_STRING(GVL.rc_PV1_max), ' bar $R$L')); 15: s_palavra := CONCAT('PRESSAO DE VACUO 2: ', CONCAT(REAL_TO_STRING(GVL.rc_PV2), ' bar $R$L')); 16: s_palavra := CONCAT('PRESSAO INERTIZACAO 1: ', CONCAT(REAL_TO_STRING(GVL.rc_PN1), ' bar $R$L')); 17: s_palavra := CONCAT('PRESSAO INERTIZACAO 2: ', CONCAT(REAL_TO_STRING(GVL.rc_PN2), ' bar $R$L')); 18: s_palavra := CONCAT('PRESSAO AERACAO: ', CONCAT(REAL_TO_STRING(GVL.rc_PAR), ' bar $R$L')); 19: s_palavra := CONCAT('PRESSAO ETO: ', CONCAT(REAL_TO_STRING(GVL.rc_PressaoETO), ' bar $R$L')); 20: s_palavra := CONCAT('PRESSAO Compl.: ', CONCAT(REAL_TO_STRING(GVL.rc_PressaoETO_2), ' bar $R$L')); 21: s_palavra := CONCAT('MASSA ETO: ', CONCAT(REAL_TO_STRING(GVL.rc_QuantidadeETO), ' Kg $R$L')); 22: s_palavra := CONCAT('TEMPO PRE COND. Vacuo/Vapor: ', CONCAT(INT_TO_STRING(GVL.rc_T_Vapor_1), ' min $R$L')); 23: s_palavra := CONCAT('SET-POINT: ', CONCAT(REAL_TO_STRING(GVL.ihm_SPTemperatura), ' °C $R$L')); 24: s_palavra := CONCAT('TEMPO ESTERILIZACAO: ', CONCAT(INT_TO_STRING(GVL.rc_TempoEsterilizacao), ' min $R$L')); 25: s_palavra := CONCAT('TEMPO PARADA: ', CONCAT(INT_TO_STRING(GVL.rc_T_PressaoParada), ' min $R$L')); 26: s_palavra := CONCAT('UMIDADE: ', CONCAT(REAL_TO_STRING(GVL.rc_UmidadeRelativa), ' % $R$L')); 27: s_palavra := '$R$L'; END_CASE END_IF Note: The code I am attaching does not include the execution/sequence management of the function blocks. I have omitted this part to keep the example focused on the CSV writing routine. The function blocks are triggered and managed by a separate state machine. I am not sure what the correct approach is in this case, especially since the official documentation recommends using SIZEOF() for szSize. I will attach my code and a screenshot of the generated CSV showing the issue. Has anyone experienced something similar or could suggest the correct way to write a changing STRING to a CSV file using CAA.File.Write?
Last updated: 2026-09-08
Post by clesio on CAA.File.Write â Unexpected characters when writing a CSV file
CODESYS Forge
talk
(Post)
Hello everyone, I am trying to create a routine in CODESYS to export a report to a CSV file using the CAA.File library. The file is created successfully, but I am getting some unexpected/unknown characters in the generated CSV. The problem seems to be related to the SIZEOF() function. I am using it for the szSize parameter of File.Write, as recommended in the CODESYS documentation. However, when I use SIZEOF(), the CSV contains extra characters and parts of previous strings. I also tried using LEN(), but in my application the file is created empty, even though the string and the calculated length appear to be correct. Here is the relevant part of my code: PROGRAM Relatorio VAR // Bool b_Executa_fb_Cria_Arquivo : BOOL; b_Executa_fb_Fecha_Arquivo : BOOL; b_Escreve_dados : BOOL; b_Erro_fb_Escreve : BOOL; //STR s_Nome_Arquivo : STRING; s_Palavra : STRING; s_Palavra_Anterior : STRING; s_Data_Atualizada_Formatada : STRING; s_Dia : STRING; s_Mes : STRING; s_Ano : STRING; s_Hora_Atualizada_Formatada : STRING; s_Hora : STRING; s_Minu : STRING; s_Segu : STRING; //INT i_modo_fb_Cria_Arquivo : INT; i_ErroID_fb_Escreve : INT; //UINT i_Tamanho_Palavra : UINT; // Blocos de Funcao fb_Cria_Arquivo : FILE.Open; fb_Fecha_Arquivo : FILE.Close; fb_Escreve : FILE.Write; // DATA E HORA sc_DataTime : SysTimeRtc.RTS_SYSTIMEDATE; // STRUCT = sc uidResultRtcGet : UDINT; //stGetDate : SysTimeRtc.RTS_SYSTIMEDATE; uidResultConvertToDate : UDINT; uidResult : RTS_IEC_RESULT; END_VAR VAR_INPUT //BOOL b_SET_Executa_fb_Cria_Arquivo : BOOL; b_RES_Executa_fb_Cria_Arquivo : BOOL; b_Executa_fb_Escrita : BOOL; // INT i_Linhas_Cabecalho : INT; i_Linhas_Cabecalho_Anterior : INT; END_VAR // Para Testes s_Nome_Arquivo := 'relatorio/Teste1M.CSV'; i_modo_fb_Cria_Arquivo := 0; // TRATAMENTO DE DATOS DATA e HORA uidResultRtcGet := SysTimeRtcGet(uidResult); uidResultConvertToDate := SysTimeRtcConvertUtcToDate(dwTimestampUtc := uidResultRtcGet, pDate := sc_DataTime); // FORMATA DATA EM UMA STRING s_Dia := UINT_TO_STRING(sc_DataTime.wDay); s_Mes := UINT_TO_STRING(sc_DataTime.wMonth); s_Ano := UINT_TO_STRING(sc_DataTime.wYear); s_Data_Atualizada_Formatada := CONCAT(s_Dia, CONCAT('/', CONCAT(s_Mes, CONCAT('/', s_Ano)))); // FORMATA HORA EM UMA STRING s_Hora := UINT_TO_STRING(sc_DataTime.wHour); s_Minu := UINT_TO_STRING(sc_DataTime.wMinute); s_Segu := UINT_TO_STRING(sc_DataTime.wSecond); s_Hora_Atualizada_Formatada := CONCAT(s_Hora, CONCAT(':', CONCAT(s_Minu, CONCAT(':', s_Segu)))); // ABRE e CRIA ARQUIVO IF (b_SET_Executa_fb_Cria_Arquivo OR b_Executa_fb_Cria_Arquivo) AND NOT(b_RES_Executa_fb_Cria_Arquivo) THEN b_Executa_fb_Cria_Arquivo := TRUE; ELSE b_Executa_fb_Cria_Arquivo := FALSE; END_IF fb_Cria_Arquivo( xExecute := b_Executa_fb_Cria_Arquivo, sFileName := s_Nome_Arquivo, eFileMode := i_modo_fb_Cria_Arquivo, xExclusive := FALSE, ); //i_Tamanho_Palavra := SizeOf(s_Palavra); // ESCREVE NO ARQUIVO fb_Escreve( xExecute := b_Executa_fb_Escrita, hFile := fb_Cria_arquivo.hFile, szSize := SIZEOF(s_Palavra), pBuffer := ADR(s_palavra) ); // FECHA ARQUIVO fb_Fecha_Arquivo( xExecute := b_Executa_fb_Fecha_Arquivo, hFile := fb_Cria_arquivo.hFile ); IF Criacao_Edicao_Arquivos.b_Escreve_Cabecalho THEN CASE i_Linhas_Cabecalho OF 1 : s_palavra := 'ESTERILIZADOR'; 2: s_palavra := 'MAQ4; $R$L'; 3: s_palavra := CONCAT(CONCAT('CLIENTE: ',GVL.sReceitaAtual), '$R$L'); 4: s_palavra := CONCAT(CONCAT('NUMERO LOTE: ',DINT_TO_STRING(GVL.Lote)), '$R$L'); 5: s_palavra := CONCAT(CONCAT('OPERADOR: ', DINT_TO_STRING(GVL.Operador)), '$R$L'); 6: s_palavra := CONCAT(CONCAT('DATA: ', s_Data_Atualizada_Formatada), '$R$L'); 7: s_palavra := CONCAT(CONCAT('HORA: ', s_Hora_Atualizada_Formatada), '$R$L'); 8: s_palavra := '$R$L'; 9: s_palavra := 'PARAMETROS AJUSTADOS $R$L'; 10: s_palavra := CONCAT('TEMPO PRE COND.: ', CONCAT(INT_TO_STRING(GVL.rc_T_PreCondicionamento), ' min $R$L')); 11: s_palavra := CONCAT('PULSOS INERTIZACAO 1: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosInertizacao_1), ' PULSOS $R$L')); 12: s_palavra := CONCAT('PULSOS INERTIZACAO 2: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosInertizacao_2), ' PULSOS $R$L')); 13: s_palavra := CONCAT('PULSOS AERACAO: ', CONCAT(INT_TO_STRING(GVL.rc_PulsosAeracao_2), ' PULSOS $R$L')); 14: s_palavra := CONCAT('PRESSAO DE VACUO 1: ', CONCAT(REAL_TO_STRING(GVL.rc_PV1_max), ' bar $R$L')); 15: s_palavra := CONCAT('PRESSAO DE VACUO 2: ', CONCAT(REAL_TO_STRING(GVL.rc_PV2), ' bar $R$L')); 16: s_palavra := CONCAT('PRESSAO INERTIZACAO 1: ', CONCAT(REAL_TO_STRING(GVL.rc_PN1), ' bar $R$L')); 17: s_palavra := CONCAT('PRESSAO INERTIZACAO 2: ', CONCAT(REAL_TO_STRING(GVL.rc_PN2), ' bar $R$L')); 18: s_palavra := CONCAT('PRESSAO AERACAO: ', CONCAT(REAL_TO_STRING(GVL.rc_PAR), ' bar $R$L')); 19: s_palavra := CONCAT('PRESSAO ETO: ', CONCAT(REAL_TO_STRING(GVL.rc_PressaoETO), ' bar $R$L')); 20: s_palavra := CONCAT('PRESSAO Compl.: ', CONCAT(REAL_TO_STRING(GVL.rc_PressaoETO_2), ' bar $R$L')); 21: s_palavra := CONCAT('MASSA ETO: ', CONCAT(REAL_TO_STRING(GVL.rc_QuantidadeETO), ' Kg $R$L')); 22: s_palavra := CONCAT('TEMPO PRE COND. Vacuo/Vapor: ', CONCAT(INT_TO_STRING(GVL.rc_T_Vapor_1), ' min $R$L')); 23: s_palavra := CONCAT('SET-POINT: ', CONCAT(REAL_TO_STRING(GVL.ihm_SPTemperatura), ' °C $R$L')); 24: s_palavra := CONCAT('TEMPO ESTERILIZACAO: ', CONCAT(INT_TO_STRING(GVL.rc_TempoEsterilizacao), ' min $R$L')); 25: s_palavra := CONCAT('TEMPO PARADA: ', CONCAT(INT_TO_STRING(GVL.rc_T_PressaoParada), ' min $R$L')); 26: s_palavra := CONCAT('UMIDADE: ', CONCAT(REAL_TO_STRING(GVL.rc_UmidadeRelativa), ' % $R$L')); 27: s_palavra := '$R$L'; END_CASE END_IF Note: The code I am attaching does not include the execution/sequence management of the function blocks. I have omitted this part to keep the example focused on the CSV writing routine. The function blocks are triggered and managed by a separate state machine. I am not sure what the correct approach is in this case, especially since the official documentation recommends using SIZEOF() for szSize. I will attach my code and a screenshot of the generated CSV showing the issue. Has anyone experienced something similar or could suggest the correct way to write a changing STRING to a CSV file using CAA.File.Write?
Last updated: 2026-09-08
Post by dantheman on Connecting to SoftPLC Only Works By Turning Off Modbus Ethernet Port
CODESYS Forge
talk
(Post)
I have an IPC with 2 ethernet ports and 1 Wi-Fi. I'm using ModbusTCP with the ethernet port named "enp2s0" connected to my remote I/O. This works fine when testing with Python and also works with CODESYS, but CODESYS is only able to scan for the Linux SoftPLC when I turn off the "enp2s0" interface. In other words, I can't get online with the IDE if I want my ModbusTCP comms to run with CODESYS. I'm using a Linux SoftPLC that has the following entry in CODESYSControl.cfg, hoping that this will allow me to connect with "enp1s0" or "wlp3s0", and leave "enp2s0" for field comms, but this seems to only make the source IP of the ModbusTCP comms to be bound to "enp2s0". That last point is the case only if I don't restart the service, but if I do restart the service after changing the config file, the source IP for the ModbusTCP comms then becomes the one for "enp1s0", which is very confusing to me: [SysSocket] Adapter.0.Name="enp2s0" Adapter.0.EnableSetIpAndMask=1 On the device list, I only have "enp2s0" given as the ethernet device that has the ModbusTCP master & slave beneath it, shown in Screenshot 1. On the IPC, I can ping the ModbusTCP client (remote I/O) from "enp2s0", and I've attached a Wireshark capture of running ModbusTCP from the CODESYS runtime as Screenshot 2, 3 & 4 (again, I can't get online when this is running, I have to turn off "enp2s0" to connect even when it's idle and I don't have an active TCP session with my Python tests). Like I explained above, the source IP is "enp1s0", even though the ethernet device on the project is "enp2s0". I was lucky to catch the red message that showed the source IP that makes sense to me (the one for "enp2s0"), but for some reason that connection was reset and I never saw that packet again. I've also tried this with Auto-reconnect both enabled & disabled, for the ModbusTCP Master device. I also have to turn off "enp1s0" and then turn it on, just so that I can have the ModbusTCP comms running from "enp2s0" (which is not intuitive in any way to me, I'd love some help understanding that phenomenon as well) in the weird manner that I've described above. I would be very appreciative if someone can help me figure out this pickle. I'd love to just connect to CODESYS through my Wi-Fi interface and leave my ethernet ports for field comms.
Last updated: 2024-08-01
Post by thn-power on Updating OPC UA Core Nodeset on PLS
CODESYS Forge
talk
(Post)
Hi After much trail and error I think I found the root cause to my OPC UA problem. The problem is that I cannot manage to build and download a program with a a custom OPC UA Information model. We use a Weidmueller WL2000 PLS, but the problem also exsist on the Win V3 PLC. Our custom information model is based on the latest versions of the OPC UA Core Nodeset v 1.05.03 (2023-09-20) and UA/DI nodeset 1.04.0 (2022-11-03) Those nodesets are installed in the Codesys Information Model Repository (3.5.19.6) However, when trying to build I get the following error. [ERROR] Untitled1: Communication Manager [Device: PLC Logic: Application]: The information model http://opcfoundation.org/UA/ is required by http://bos.org/ with a minimal publication date from 15.12.2023 but the device has only a model from 15.09.2021 installed. Probably the information model from 15.09.2021 is missing in the information model repository. [ERROR] Untitled1: Communication Manager [Device: PLC Logic: Application]: The information model http://opcfoundation.org/UA/DI/ is required by http://bos.org/ with a minimal publication date from 03.11.2022 but the device has only a model from 09.03.2021 installed. Probably the information model from 09.03.2021 is missing in the information model repository. Build complete -- 2 errors, 1 warnings : No download possible I think the problem is that the UA Core nodeset is implemented in the PLC firmware (at least that in Siemens S7), and that only includes the "old" nodeset from 2021-09-21 etc. So the question is, how (or if?) can I transfer the new nodeset to the PLS? I have created separate Information models under Communication manager with the newer code nodesets (UA and DI). But it seems that the compiler does not recognize them being excising, neither in the Codesys IDE or on the PLC. Would have guessed that this is a common issue, sine many manufacturers use the latest versions of the OPC UA standard, and that it would be a solution to the problem.
Last updated: 2024-09-20
Post by george32 on Readable IO names
CODESYS Forge
talk
(Post)
Hello Folks, I have a quite basic understanding of how PLC programming works. However I keep getting stuck on 1 problem I could not get my head around. The problem is as follow: I have a PLC with 60 IO (20 inputs, 40 outputs). Each IO is defined as a function block. Furthermore I have an external IO card connected trough a CanBus connection. This IO card has 4 analog input channels (USINT), 4 digital inputs (Bool) and 4, digital outputs (Bool) Because I have 2 different components which both has data have I made 4 arrays to store the data off every component in one variable. PLC_Input: Array [1..20] of BOOL; PLC_Output: Array [1..40] of BOOL IOCard_Input: Array [1..8] of BOOL IOCard_Output: Array [1..4] of BOOL Because the control and reading of the different in and outputs is done by a TCP connection I want to use some kind of enumeration or struct to give each index a name so that my main would be a little bit more readable instead of all the magic numbers. Also this would make my program more dynamic for the furter in case I need to changes some in the IO nummers. For example: pump is placed on the fysical terminal strip number place 54, which is the 3th output of the IO card in the program: if I am sending a message with value 54 I would like to control IOCard_Output[3]. If there is a solution or methode to get this done, I can eventually do the following in my main program: IOCard_Output[Pump]. I have tried the following: IOCard_Output[Pump - 51] with an enumration but this keeps raising an error I hope some of you could help me further with this problem. In gross lines: I want to couple all the different IO to a more readable name and this readable name should control the right Array index Thanks in advance, George
Last updated: 2024-09-26
Post by jari-koivuluoma on Problem trying Net Base Services 3.5.15.0 TCP connection
CODESYS Forge
talk
(Post)
I have a need to send messages between 2 PLCs and I cant use network variables (because of size limit) so I tried writing this simple test program. This seems to work fine. I can send messages back and forth when a first "Start server" and then "Connect client". See the attached image. However, if I disconnect the client by setting ClientConnect to false and try to re-connect then the TCP_Client just gives me TIMEOUT error. When I stop and start the server again, then Im able to reconnect. How is this supposed to work? Why reconnecting wont work. There is not other way of disconnecting the client than setting xEnable of the TCP_Client to false. This is just a testing program and I will try it on 2 seperate devices once this works. PROGRAM PLC_PRG VAR CONSTANT mySize : UDINT := 255; END_VAR VAR Server: NBS.TCP_Server; ServerIpStr: STRING := '127.0.0.1'; ServerIP: NBS.IP_ADDR; ServerPort: UINT := 50000; ServerConnection: NBS.TCP_Connection; Client: NBS.TCP_Client; ServerRead: NBS.TCP_Read; ServerWrite: NBS.TCP_Write; ServerSend: STRING(mySize); ServerReceive: STRING(mySize); ServerConnect: BOOL; bServerSend: BOOL; IP: NBS.INADDR; ConnectedClientIP: STRING; ClientPort: UINT := 50000; ClientIpStr: STRING := '192.168.1.49'; ClientIP: NBS.IP_ADDR; ClientRead: NBS.TCP_Read; ClientWrite: NBS.TCP_Write; ClientSend: STRING(mySize); ClientReceive: STRING(mySize); ClientConnect: BOOL; bClientSend: BOOL; Error: BOOL; Message: BOOL; END_VAR // Server ServerIP.sAddr := ServerIpStr; Server( ipAddr := ServerIP, uiPort := ServerPort ); ServerConnection( xEnable := Server.xEnable, hServer := Server.hServer, ); IP := ServerConnection.IPAddress; ConnectedClientIP := F_Concat7( BYTE_TO_STRING(IP.S_un_b.s_b1),'.', BYTE_TO_STRING(IP.S_un_b.s_b2),'.', BYTE_TO_STRING(IP.S_un_b.s_b3),'.', BYTE_TO_STRING(IP.S_un_b.s_b4)); ServerRead( xEnable := ServerConnection.xActive, hConnection := ServerConnection.hConnection, szSize := SIZEOF(ServerReceive), pData := ADR(ServerReceive) ); IF ServerRead.xReady AND ServerRead.szCount > 0 THEN Message := TRUE; END_IF IF ServerRead.eError > 0 THEN Error := TRUE; END_IF ServerWrite( xExecute := ServerConnection.xActive AND bServerSend, hConnection := ServerConnection.hConnection, szSize := LEN(ServerSend)+1, pData := ADR(ServerSend) ); IF ServerWrite.xDone THEN bServerSend := FALSE; END_IF IF ServerWrite.eError > 0 THEN Error := TRUE; END_IF // Client ClientIP.sAddr := ClientIpStr; Client( xEnable := ClientConnect, ipAddr := ClientIP, uiPort := ServerPort, udiTimeOut := 10000000 ); ClientRead( xEnable := Client.xActive, hConnection := Client.hConnection, szSize := SIZEOF(ClientReceive), pData := ADR(ClientReceive) ); IF ClientRead.xReady AND ClientRead.szCount > 0 THEN Message := TRUE; END_IF IF ClientRead.eError > 0 THEN Error := TRUE; END_IF ClientWrite( xExecute := Client.xActive AND bClientSend, hConnection := Client.hConnection, szSize := LEN(ClientSend)+1, pData := ADR(ClientSend) ); IF ClientWrite.xDone THEN bClientSend := FALSE; END_IF IF ClientWrite.eError > 0 THEN Error := TRUE; END_IF
Last updated: 2024-10-03
Post by mondinmr on Frustration-Fueled Feedback on Project File Management and Git Integration
CODESYS Forge
talk
(Post)
Good day, Iâm writing this message out of frustration regarding the current way project files are saved as encrypted XML and single-file format in CODESYS. I find this approach to be quite tedious for several reasons: Limited Access to Structured Text: Not being able to access Structured Text (ST) externally makes it impossible to work with alternative editors like VSCode. Tools like VSCode are incredibly responsive and feature advanced systems such as GitHub Copilot, which would be a real game-changer when working with ST IEC. While CODESYS works well for small code snippets or debugging, when the codebase grows, switching to VSCode to boost productivity becomes essential, and copy-pasting between environments is a cumbersome workaround. Poor Integration with Git: This file format also makes it very difficult to integrate effectively with Git. I have tested the internal demo, but for advanced merges, it is unusable. Without properly formatted plain text, itâs impossible to leverage the vast ecosystem of external tools around Git that allow smooth merges in heterogeneous teams. File Corruption on Network Drives: I often work from multiple locations with shared network drives. When the development environment saves a file and something goes wrong midway (which can occasionally happen when using VPNs and network drives), the entire project becomes irrecoverable. Thereâs no way to cancel the save process, and the development environment freezes. This has happened to me at least four times over the past two weeks, and one of those incidents cost me an entire day of work. All of this is particularly disappointing because I truly believe that the libraries, runtime, and overall work done by CODESYS are exceptional. I find it fantastic that there is a platform allowing development of PLCs and control systems using OOP, which is a huge advantage in modern control engineering. I apologize for the rant, but this issue has been extremely frustrating. Best regards.
Last updated: 2024-10-15
Post by wiekon on OPC UA Probleme
CODESYS Forge
talk
(Post)
Hallo zusammen, ich hoffe, ihr könnt mir helfen. Eigentlich möchte ich etwas ganz einfaches erreichen: CODESYS Runtime auf Raspberry Pi (OPC UA Client ĂŒber Datasources Manager) <--> Cognex Designer (OPC UA Server) auf Windows PC Es will einfach nicht klappen. Wenn ich die Datenquelle hinzufĂŒge, Adresse opc.tcp://192.168.150.10:4840 kommt immer BadRequestTimeout. Es ist keine Security und keine Authentication auf dem Server eingerichtet. Auf dem gleichen Raspberry klappt es aber wunderbar mit dem Tool opcua-client! Das heiĂt fĂŒr micht, es ist kein Raspberry oder Firewall Thema. Was auch geht: Diese CODESYS Runtime auf dem Raspberry ist OPC UA Server (einfach ĂŒber die Symbolkonfiguration) und eine andere CODESYS Runtime (ControlWin auf meinem Rechner) ist Client und verbindet sich ĂŒber den DatasourceManager. Allerdings: Die Daten kommen im Client nur im 1s Takt an, obwohl die Aktualisierungsrate auf 10 ms eingstellt ist und sowohl Server, als auch die DatasourcesTask im Client auf 10 ms laufen. Ich kann einstellen, was ich will, es bleibt bei exakt 1 Sekunde Aktualisierungszeit im Client. Warum ist das so? Wenn ich auf dem gleichen Windows PC, auf dem die ControlWin lĂ€uft den UaExpert verwende und mich zum Raspberry verbinde, kriege ich die Daten im 10 ms Raster! Am Server liegts also nicht! ZurĂŒck zu meiner eigentlichen Aufgabe: Ich konnte mir vorĂŒbergehend so behelfen, dass ich auf dem gleichen Raspberry einen IO-Broker laufen lasse, der zwei Instanzen des OPC UA Clients hat. Er verbindet sich mit dem OPC UA Server des Raspberry und des Cognex Designers (also die zweite Instanz auf dem Raspberry, die es schafft, sich mit dem zu verbinden, nur Codesys schafft es nicht). Der IO Broker ist also das Bindeglied zwischen beiden OPC UA Servern. Ăber Javascript kopiere ich bei WertĂ€nderung die Daten vom einen Server auf den anderen. Das ganze Funktioniert tadellos, nur die Performance ist nicht so toll, wobei ich mir nach der Erfahrung mit den zwei Codesys Instanzen nicht sicher bin, ob es nicht an Codesys liegt und der IO Broker nichts dafĂŒr kann. Ich komme mit dem Thema einfach nicht weiter. Könnt ihr mir Tipps geben? Am liebsten wĂ€re mir natĂŒrlich der direkte Weg: Cognex Designer als Server --> Codesys als Client Aber zur Not wĂ€re auch der IO Broker ein gangbarer Weg, allerdings muss die Performance stimmen. Gibt es noch weitere Wege? Ich danke euch fĂŒr eure kreativen Ideen und LösungsvorschlĂ€ge!
Last updated: 2024-11-29
To search for an exact phrase, put it in quotes. Example: "getting started docs"
To exclude a word or phrase, put a dash in front of it. Example: docs -help
To search on specific fields, use these field names instead of a general text search. You can group with AND or OR.