1

I'm right now trying to convert my original python socket reading code into structure text in TwinCAT3. The following is the original python code that unpacks the read_data = socket.recv(1116) data into different things:

def ur_read(read_data):
    moment=[0,0,0,0,0,0]
    joint_p=[0,0,0,0,0,0]
    joint_v=[0,0,0,0,0,0]         
    tcp_p=[0,0,0,0,0,0]
    tcp_v=[0,0,0,0,0,0]
    tcp_force=[0,0,0,0,0,0]
    state=0
    time_new=0
    try:
        for i in range(len(read_data)):            
            if [read_data[i],read_data[i+1],read_data[i+2],read_data[i+3]] == [0,0,4,92]:
                time = struct.unpack('>d', read_data[i+4:i+12])
                moment[0], = struct.unpack('>d', read_data[i+204:i+212])
                moment[1], = struct.unpack('>d', read_data[i+212:i+220])
                moment[2], = struct.unpack('>d', read_data[i+220:i+228])
                moment[3], = struct.unpack('>d', read_data[i+228:i+236])
                moment[4], = struct.unpack('>d', read_data[i+236:i+244])
                moment[5], = struct.unpack('>d', read_data[i+244:i+252])
                joint_p[0], = struct.unpack('>d', read_data[i+252:i+260])
                joint_p[1], = struct.unpack('>d', read_data[i+260:i+268])
                joint_p[2], = struct.unpack('>d', read_data[i+268:i+276])
                joint_p[3], = struct.unpack('>d', read_data[i+276:i+284])
                joint_p[4], = struct.unpack('>d', read_data[i+284:i+292])
                joint_p[5], = struct.unpack('>d', read_data[i+292:i+300])
                joint_v[0], = struct.unpack('>d', read_data[i+300:i+308])
                joint_v[1], = struct.unpack('>d', read_data[i+308:i+316])
                joint_v[2], = struct.unpack('>d', read_data[i+316:i+324])
                joint_v[3], = struct.unpack('>d', read_data[i+324:i+332])
                joint_v[4], = struct.unpack('>d', read_data[i+332:i+340])
                joint_v[5], = struct.unpack('>d', read_data[i+340:i+348])
                tcp_p[0], = struct.unpack('>d', read_data[i+444:i+452])
                tcp_p[1], = struct.unpack('>d', read_data[i+452:i+460])
                tcp_p[2], = struct.unpack('>d', read_data[i+460:i+468])
                tcp_p[3], = struct.unpack('>d', read_data[i+468:i+476])
                tcp_p[4], = struct.unpack('>d', read_data[i+476:i+484])
                tcp_p[5], = struct.unpack('>d', read_data[i+484:i+492])
                tcp_v[0], = struct.unpack('>d', read_data[i+492:i+500])
                tcp_v[1], = struct.unpack('>d', read_data[i+500:i+508])
                tcp_v[2], = struct.unpack('>d', read_data[i+508:i+516])
                tcp_v[3], = struct.unpack('>d', read_data[i+516:i+524])
                tcp_v[4], = struct.unpack('>d', read_data[i+524:i+532])
                tcp_v[5], = struct.unpack('>d', read_data[i+532:i+540])
                tcp_force[0], = struct.unpack('>d', read_data[i+540:i+548])
                tcp_force[1], = struct.unpack('>d', read_data[i+548:i+556])
                tcp_force[2], = struct.unpack('>d', read_data[i+556:i+564])
                tcp_force[3], = struct.unpack('>d', read_data[i+564:i+572])
                tcp_force[4], = struct.unpack('>d', read_data[i+572:i+580])
                tcp_force[5], = struct.unpack('>d', read_data[i+580:i+588])
                state,= struct.unpack('>d', read_data[i+1052:i+1060])  
                time_new, = struct.unpack('>d', read_data[i+4:i+12])
                break
    except:
        print('exp')

According to the python code, I've written a socket connection and read function block in TwinCAT3. However, I'm right now facing some problem doing data encoding:

FUNCTION_BLOCK DataEncoding
VAR_INPUT
    DataReceived: ARRAY[0..1115] OF BYTE;
END_VAR
VAR_OUTPUT
    moment: ARRAY[0..5] OF LREAL := [6(0.0)]; // LREAL stands for Double
    joint_pos: ARRAY[0..5] OF LREAL := [6(0.0)];
    joint_vel: ARRAY[0..5] OF LREAL := [6(0.0)];
    tcp_pos: ARRAY[0..5] OF LREAL := [6(0.0)];
    tcp_vel: ARRAY[0..5] OF LREAL := [6(0.0)];
    tcp_force: ARRAY[0..5] OF LREAL := [6(0.0)];
END_VAR
VAR
    i: INT;
    BYTEARR_to_STRING: BYTEARR_TO_MAXSTRING;
END_VAR

And in the body part:

FOR i := 0 TO 1116 BY 1 DO
    IF DataReceived[i] = 0 AND DataReceived[i+1] = 0 AND DataReceived[i+2] = 4 AND 
    DataReceived[i+3] = 92
        moment[0] := TO_LREAL(BYTEARR_to_STRING(in:= DataReceived[(i+204)..(i+212)]));
    END_IF
END_FOR

The problem I've encountered is that I'm not sure how to write conversion between byte array and LREAL. Furthermore, the array indexing of DataReceived[(i+204)..(i+212)] seems to have some errors. Can anyone teach me how to index specific part like (204 to 212) in ARRAY[0..1115]? And also the tramsformation between byte array and LREAL.

Thanks!

Harry
  • 15
  • 5
  • Maybe you could already do the byte to lreal conversion in the python code. It seems that the Python code is already specific with the `moment` and `joint_p` variables. Regarding array slicing, i.e. `DataReceived[(i+204)..(i+212)]`, this is not possible in TwinCAT. You would have to use a for loop to get specific values. – Roald Aug 18 '21 at 07:01
  • I don't know python. How does it transfer bytes into a number? Is it the byte representation of a double number? or how does it convert in python? Or do you want the number the byte represents written into an lreal? – Uwe Hafner Aug 18 '21 at 09:36
  • @UweHafner Thanks for your reply. The python **unpack** function will transfer the bytes into double as the declaration is ">d". I thought it would not be a matter for you to realize the TwinCAT problem so I didn't explain it. Sorry for that. The main issue might be that I'm not familiar with the structure text coding. – Harry Aug 18 '21 at 09:47
  • @Roald wow, thanks for telling me that in structure text is not allow to index the array like that. That might be a really good point to cut through. – Harry Aug 18 '21 at 09:49
  • As @Roald said you have to write the code to access the array yourself taking the single bytes and transfer them to your LREAL. That was why I was asking what the binary representation of the bytes was transfering to double values? Because you are converting i.e. 9 bytes (204..212) into an lreal which only holds 8 bytes. – Uwe Hafner Aug 18 '21 at 10:12
  • @UweHafner I've understood your concern. Thanks for your information. Sorry for making you misunderstand the code. In python, (204 : 212) actually means 204 to 211, without counting the last term 212. I'm not sure whether this concept holds for structure text also. Thanks. – Harry Aug 18 '21 at 10:30
  • You can memcpy bytes to the lreal if that is what you need. Then you would not even need to loop through the array but call memcpy(destination, source, length). The source would be the starting byte like DataReceived[204] and length 8. – Uwe Hafner Aug 18 '21 at 10:33

1 Answers1

3

You can memcopy the bytes to the LREAL.
ADR() is the function that gets the memory address of the variable:

FOR i := 0 TO 1116 BY 1 DO
    IF DataReceived[i] = 0 AND DataReceived[i+1] = 0 AND DataReceived[i+2] = 4 AND DataReceived[i+3] = 92 THEN
        memcpy(ADR(moment[0]), ADR(DataReceived[(i+204)]), 212-204);
    END_IF
END_FOR
kolyur
  • 457
  • 2
  • 13
Uwe Hafner
  • 4,889
  • 2
  • 27
  • 44
  • according to the answer you've offered, I got some questions hope that you can help me resolve. According to the simple code sample, I'm curious about the type transform between LREAL and BYTE array. So the memcpy function will copy the byte to the desired address and the data type of the address will be automatically set? – Harry Aug 18 '21 at 13:03
  • 1
    That is the problem with this code. It takes a memory section and copies the content to another memory section. Because the destination memory section is defined as an LREAL section for the PLC it interprets the memory content as LREAL. In my answer I am assuming that the byte order in which you receive the information is the same as it is copied to the target. Memcpy knows nothing about types. It only copies bits and bytes. – Uwe Hafner Aug 18 '21 at 13:38
  • 1
    The `memcpy` code will work as long as your input data is an actual 64-bit floating point value split into 8 bytes while maintaining the IEEE754 format. The code in your original post seems to be interpreting the bytes as individual ASCII characters (`BYTEARR_TO_MAXSTRING`) which is vastly different. – kolyur Aug 18 '21 at 13:58