Get signed 32-bit integer from two unsigned 16-bit GI's

  • I need to receive a 32-bit signed integer that is used for computations. I am aware that it might be represented with some loss of information if I put it in a register but that is a cceptable (Max integer value in Numerical Register). The bits of the 32-bit value is read in two 16-bit GI's (unsigned integers), and then needs to be 'reconstructed' as a 32-bit signed integer and I am struggling to do so.


    For 16-bit unsigned/signed conversion, the following thread posts some options to do so:

    However, these methods in my case would require computations with an unsigned 32-bit integer range (2**32) which is not representible in FANUC/KAREL as far as I know. Are there any other methods for me to use? Short of mapping the 32-bit signed integer to individual DI's and then reconstructing* the value myself, I'm out of ideas.


    *while on the topic of reconstruction, does FANUC (or KAREL specifically) use two's complement representation of signed integers?

  • Place your Ad here!
  • It all depends on your abilities on the data source side.

    If possible, send always the absolute value, and separately a "negative" flag.

    In the robot, convert to negative when necessary, by subtracting from zero.


    This being said, what do you need 32-bit values in the robot for?

    Signed 16-bit covers more than ±3.2 meters distance with 0.1mm resolution.

  • Thanks for the replies to those who did.


    I have tested with a KAREL program to convert 32 DIs to a 32-bit signed integer (FANUC works with two's complement representation as expected). Some of my findings:

    - conversion done by treating first 31 bits as an unsigned integer, IF last bit is FALSE value stays positive, if value is TRUE: subtract 2147483647 from the value and then subtract 1 (can't subtract 2**16=2147483648 at once because of maximum integer value..)

    - when the first 31 bits are all TRUE (values '-1' and '+2147483647'), KAREL can't assign the value to the integer variable, therefore -1 and 2147483647 are special cases which need to be accounted for


    I will probably end up discussing if 16-bit precision would also suffice in terms of resolution, like Sergei suggested, since this seems to be enough for our application. This would also mean I can use GI's, which will basically perform the required conversion in the background.

  • Quote

    Karel has special Constants:

    MAXINT +2147483647

    MININT -2147483648

    I have done some research on these issues.

    - Behavior of Karel/Karel variables

    - Behavior of TP programs or registers


    Error inside Karel manual:

    ----

    2.1.6 Predefined Identifiers

    ...

    MAXINT INTEGER +2147483647

    MININT INTEGER-2147483648

    ...However,the predefined identifier MININT is an exception to this rule. This identifier must always be used in place of its value, -2147483648. The value or number itself can not be used...

    ----

    The above statement is wrong.


    The value -2147483648 (MININT) can be used normally and is displayed correctly.

    It turns out that the value of MAXINT is always 2147483646.

    However, if the value is stored after the two's complement, it should be 2147483647.

    In Karel, however, the maximum integer value is 2147483646. If the bits are set to the "regular value of MAXINT, i.e. 2147483647, and then assigned to a Karel integer variable, the value is uninitialized.

    So not all (regular)values are possible.


    In TP, however, it behaves differently with the registers.

    Calculating and setting with MaxINTEGER works. Also the overflow behaves as expected.

    Only the display on TP and in the web interface is not "nice".


    Here are some comparisons TP / Karel


    Karel:

    --

    value = MININT; --> value -2147483648

    value = -2147483648; --> value -2147483648

    --

    value = MAXINT; --> value +2147483646

    value = 2147483646; --> value +2147483646

    IF value = MAXINT ... --> true


    value = 2147483647 ; --> value *****

    value = MAXINT +1 ; --> value *****

    value = 2147483646 +1 ; --> value *****

    IF UNINIT(value)... --> true

    -- no more calculation possible, only query if UNINIT works

    --> recognition is possible, but "calculating" becomes "messy"


    TP

    R[1] = -2147483648; --> R[1] -2147483648

    R[1] = -2147483647-1; --> R[1] -2147483648


    R[1] = 2147483646; --> R[1] 2147483646

    R[1] = 2147483646+1; --> R[1] ******* (2147483647)

    R[1] = R[1] +1 ; --> R[1] -2147483648


    -- Calculation and overflow works as expected

    -- The display is ***** not nice


    When a program with ascii upload is played to the controller with the following code:


    : R[1] = 2147483647;

    it will be displayed like this:

    : R[1] = ******; --> When the LS prog is downloaded it contains the stars and cannot be uploaded anymore. It is like with uninitialized positions in TP programs.


    I hope I could help a little further and/or bring light into the darkness.

    best regards

    PnsStarter

  • Thanks for the replies! The project has been put on hold for a short while but I've just picked it up again and solved the issues.


    I went with this suggestion:

    R[1] = (high byte * 65535) + low byte

    Except the high byte should be multiplied by 65536 (=2**16) to achieve a 16 bit shift. Additionally, it seemed that while GI/GO's are set as unsigned integers, as soon as they're read in Karel they are converted to a 16-bit signed representation.. For this reason I had to add the check for negative values of low byte. The following code works for me (using GO instead of GI for easier debugging at the moment):


    Code
    v1 = GOUT[1] * 65536
    v2 = GOUT[2]
    IF (v2 < 0) THEN
        -- convert from signed to unsigned
        v2 = v2 + 65536
    ENDIF
    value_int = v1 + v2
    SET_INT_REG(1, value_int, status)
  • To do that with a 16bit integer, what I usually do is to check if value is greater than 32767. If so, value is negative, so you need to substract 65536 to the GI value and you will obtain the negative value on the register.


    I think your approach is good, but after doing the merge of the two integers you need to do a similar thing but checking the complete range of a 32bit value on the R[1], if value is greater than 2147483687, then substract 4294967296.


    That way is how you can check if the sign bit is set at 1 or 0, since any value greater than half the range of the integer implies the sign bit is set.


    Remember that if you are using a siemens plc to transfer the values, you need to swap the bytes before sending them to the robot since they work with different endianness, so you may need to split the 32bit value on plc into two 16bit values and swap the bytes on both of them just before sending to the robot. (Do a FC with a dnum input, two num outputs and split the bytes, swap 1/2 and 3/4 on a temp variable and output that two nums, then you can transfer them directly to the robot GI. On Tia you can access individual bytes by adding a %0, 1... etc to the input, so if input is called "InputDnum" you can access first byte by writting "InputDnum.%0" or something similar, i don't remember the exact way right now but it's possible)



    Edit: I do all this using TP, not karel, since I try to avoid karel when I can so people can read the code and modify it when needed, if you have problems with karel doing a cast to the value and converting it to an integer then you may need to debug a little more until it works. If you will be doing this conversion for two or 3 values I wouldn't bother in doing it with karel, just do it on tp and forget forever about it.

    Edited 2 times, last by Shellmer ().

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account
Sign up for a new account in our community. It's easy!
Register a new account
Sign in
Already have an account? Sign in here.
Sign in Now

Advertising from our partners