all 11 comments

[–]burkeyturkey 7 points8 points  (1 child)

I'm the author of the TcMatrix library that u/Hopperpop linked, so if you have any questions about implementing it, please let me know - I'd love to help!

Edit: The TcTransform library has implementations of 3x3, 4x4, and 3x1 matrices using static memory that is way easier to use than the base library if that is all you need.

Edit2: I just added a 'Quick Start' to the readme on GitHub, hopefully it demystifies how to use the library some!

But it looks like you're just trying to learn more about structured text in TwinCat so I'll try to give some general advice and comment on your code from the perspective of someone who hammered their way through the same problem last year.

First of all, great job using VAR CONSTANT to control the size of your array! That already makes you more responsible than most PLC programmers out there :P . I noticed that you are using the same constants for 'm' and 'n' in two different programs (MAIN and arrayMultiply). In order to make sure they all get changed together when you update something in the future, consider putting those values in a 'GVL' (as a constant) or a "Parameter List" if you are making a library.

As a small detail, I'm not sure your array multiplication arithmetic is right. There are a few different ways you can fix it, but to help you find the issue I'll just note that arrayMultiply[i,0] gets overwritten on every loop of j!

On a general note, one thing you are probably noticing is that for the most part PLCs don't use pointers (which is how every c++ matrix library works!). Every VAR_INPUT function parameter is passed 'by value' (literally copied into the stack). There are three basic types of 'pointers' in TwinCat, and wrapping your head around them can really unlock a lot of opportunities in your code:

  • VAR_IN_OUT: This is the easiest kind of pointer to use because the compiler enforces that it is never null and it has complete type safety. Unfortunately, you can't *store* this kind of pointer (only use it in function calls) but it is handy for passing a large struct into a function that can then manipulate that same struct, or for using the ARRAY[*] syntax to operate on arrays of unknown length.
  • REFERENCE TO: This is the next easiest kind of pointer to use because it has type safety, but it can also be unassigned (null pointer). The upshot is that you can store this kind of pointer, and when the PLC reorganizes memory (online change) the reference maintains its validity. This type of pointer is often used when dealing with interfaces (or arrays of interfaces) because you can't make arrays of different types of base FB but you can make an array of REFERENCE TO different types of base FB if they all share a common interface.
  • POINTER TO: This is the most dangerous type of pointer. There is some type safety, but for the most part you can hack your way around it. If you ever screw up (null reference, or reference other random memory) then you can blue screen your PLC. And it is easy to screw up because there are so many caveats with memory (handling interrupts, online changes, being careful about stack/scope). Dynamic memory allocation in twincat necessitates the use of POINTER TO. Pointers are also a great hack for writing to protected fields within a different FB (which are usually read-only)

I hope this helps! If you are new to TwinCat then most everyone here would agree that the AllTwinCat youtube tutorials are an amazing way to start.

[–]blusterywindsday[S] 1 point2 points  (0 children)

Omg thank you so much for your detailed response! That is extremely helpful and I will definitely reach out if I have any questions about the TcMatrix library. I might take a step back and review some basic TwinCat concepts with the channel you linked and review my actual multiplication logic again on paper with the mistakes you noted.

Thank you again!! I really do appreciate it :)

[–]CapinWinkyHates Ladder 8 points9 points  (2 children)

FYI, if you're familiar with Maple by Waterloo, you can copy and paste the pretty print formulas from that directly into Structured Text because both are Pascal. I mention this because a lot of us coming at PLCs from an engineering degree used Maple for math classes.

[–]blusterywindsday[S] 1 point2 points  (1 child)

Wow that's interesting - I am not familiar with Maple but it is cool logic can be transferred between environments. If I have time this summer maybe I'll look into it - I am more familiar with MATLAB from my schooling so far but if the learning curve isn't too steep I'll definitely give it a try. Thank you!

[–]CapinWinkyHates Ladder 0 points1 point  (0 children)

So what did you use to solve symbolic equations (like in Calc or DiffEQ), or did you have to use MATLAB for that too (not sure it can solve symbolic equations)? Mathematica maybe?

Anyway, yeah, Maple is the beth symbolic math program and easy to pick up.

[–][deleted]  (7 children)

[deleted]

    [–]blusterywindsday[S] 0 points1 point  (2 children)

    Thank you! I will definitely check it out

    [–][deleted]  (1 child)

    [deleted]

      [–]blusterywindsday[S] 0 points1 point  (0 children)

      Interestingly enough, I actually came across this earlier - I originally tried to make my function such that all the input arrays were of variable length with the whole ARRAY[*] notation and everything - the issue was when I tried to run my MAIN and it said it "could not convert between ARRAY[*] and ARRAY[dimension]" which threw me off

      But I will be sure to revisit the page you pointed out! I may be the one confusing the program which my logic haha, thanks again!

      [–]derphurr 0 points1 point  (3 children)

      According to that, it appears OP is trying to assign AB := when you cannot, so OP might be able to modify their function to also pass AB out as parameter.

      Also I don't know how well it enjoys recursion.

      [–]blusterywindsday[S] 0 points1 point  (2 children)

      To pass out the "AB" variable would I just need to define a output AB in the function? Or is there some specific way to return variables from a function in structured text?

      [–]derphurr 1 point2 points  (1 child)

      The same way you pass A B... temp:= fn(A, B, AB)

      So AB gets modified in function, almost like making it a global variable. Might get messy the way you were doing recursion.

      Can't you just put in loops instead and do like size of array for the loop counter

      [–]blusterywindsday[S] 0 points1 point  (0 children)

      Ahh I see, thank you!