Bit of a coding Conundrum

  • Alright all, Something that's really bugging the hell out of me. Really interested to hear if any has had this issue or knows a way around it. Essentially what i want is to read an INT value from a String[]


    So for instance if i input some variables into a routine such as:


    Input1 :IN, Input2 :IN, Input3 :IN


    DECL INT iCounter,Num1

    DECL INT Input1,Input2,Input3

    DECL CHAR StringName[6]


    StringName = "Input"


    FOR iCounter = 1 to 3

    SWRITE (StringName[],Stat,Offset,"%1d",iCounter)

    ;So now StringName[] will Equal "Input1" which is the same as the routine input

    ENDFOR


    BUT what im then having issues with is using the value of "Input1" because most of the kernal will read this as a CHAR type and not INT. I've tried STRTOINT, I tried Casting it out and back in.

    The only way i think it could work is:


    *%7s is an example

    SREAD (StringName[],Stat,Offset,"%7s",Num1)


    So I'm essentially reading the value of the string to convert into a number. Hope this makes sense? To be honest I'm quite certain you can do this in an ABB, I think if anything its either totally not possible, or perhaps I've not quite got the right format variable for converting.


    Apologies if this is long winded. :smiling_face:


    All the best

    Ash

    Edited once, last by Ash ().

  • - You should initialize 'offset' in the loop.

    - It is not possible to use 'symbolic access' during runtime to a variable on the Kuka. The only exception I know is accessing I/O. On I/O you can get the number of the I/O from the name with the function GET_SIG_INF.

  • not quite sure i understand perfectly.

    your string is 6 characters long. first five characters are letters. so the only character in there that could be a number is the 6th one and it could be 0-9. this can be sorted out simpler, without using fancy instructions




    but if you want to use string to integer instruction - you may. all you need to do is remove or skip non-numeric characters before conversion. as stated above, in case of SREAD this means initializing Offset. This has to be initialized anyway. it is telling to SREAD how many characters to skip. but in general case there could be additional trailing characters (letter, numbers or mix).

    1) read pinned topic: READ FIRST...

    2) if you have an issue with robot, post question in the correct forum section... do NOT contact me directly

    3) read 1 and 2

  • Code
    n=s[7]            ; get one character, convert ASCII to INT
    n=n-48            ; assuming it is a digit, adjust value
    if n<0 or n>9     ; then check if out of range
      n=-1            ; it is out of range (that was not a digit)
    endif

    why 48?


    check ASCII table, numbers are starting at 48 (0x30).

    basically this is kind of things that those conversion functions are using.


    1) read pinned topic: READ FIRST...

    2) if you have an issue with robot, post question in the correct forum section... do NOT contact me directly

    3) read 1 and 2

  • - You should initialize 'offset' in the loop.

    - It is not possible to use 'symbolic access' during runtime to a variable on the Kuka. The only exception I know is accessing I/O. On I/O you can get the number of the I/O from the name with the function GET_SIG_INF.

    Yes, Apologies I should have included this in the example. So in the actual program Offset is initialized as 5, So you add iCounter to StringName[]

  • Ok so maybe some more explanation needed. So the idea is, if you have a larger amount of data to process, Its vastly simpler to use a FOR loop. So what im suggesting is you just add the number to the end of the string which represents a variable on the system. Take your average spot welder for example. You might call your variables "Gun1", "Gun2", "Gun3" right?? So are you going to set each of those things individually? OR you can just add an iCount to "GUN" So you can set all your variables in one sweep. Its fairly common practise to my knowledge i just can't see any simple solutions in kuka's.

  • What you seem to be talking about is called arrays.


    DECL GUN_TYPE GUN[3]


    KRL is very simple language. there is not much in terms of variables to choose from.

    there are only 4 basic data types (INT, REAL, BOOL and CHAR), plus two complex types (structure and enumeration), and of course, one can create array of any of those. that's it..

    1) read pinned topic: READ FIRST...

    2) if you have an issue with robot, post question in the correct forum section... do NOT contact me directly

    3) read 1 and 2

  • Here's the example of my program. Basically to set a bunch of interrupts because i have quite a few needed. "In theory" the logic is sound. Its just a kuka'esque way needed to achieve it i guess.


    Edited once, last by Ash ().

  • well, if it works for you then all is good.

    but KUKA does not have normal string type, char arrays are used a substitute and there are various limitations with the data type itself and with associated functions. those tings are usually not mentioned or documented anywhere, or some of documentation is not even right, so it it a lot of trial and error involved...

    1) read pinned topic: READ FIRST...

    2) if you have an issue with robot, post question in the correct forum section... do NOT contact me directly

    3) read 1 and 2

  • well, if it works for you then all is good.

    but KUKA does not have normal string type, char arrays are used a substitute and there are various limitations with the data type itself and with associated functions. those tings are usually not mentioned or documented anywhere, or some of documentation is not even right, so it it a lot of trial and error involved...

    haha Don't i know it :grinning_squinting_face: :loudly_crying_face: :loudly_crying_face: :loudly_crying_face:

  • Did you read my post complete?

    It is not possible to read the value of an integer via the name of it during runtime.

    You should use arrays.

    Oh sorry yes i understand you now. Yes i had to find out the hard way about GET_SIG_INF (Which does work really nice). But its kind of frustrating, there must be a way somehow to read it? :thinking_face:


    I wonder if it would be possible to have a dummy SIGNAL then using GET_SIG_INF you input the string, Output the value and then read it back again? :thinking_face: Sounds feasible haha


    How did you mean use arrays?

  • How did you mean use arrays?

    You could literally simply create an array of STRUCs, like so:

    Code
    STRUC MyStruc CHAR String[], INT InterrupNumber
    
    DECL MyStruc MyArray[10]
    MyArray[1] = {String[] "IntNum1", InterruptNumber 1}
    MyArray[2] = {String[] "IntNum2", InterruptNumber 2}

    And so on. Then, you could FOR loop through the array, using STRCOMP to compare MyArray[Counter].String[] to your desired string, then DO INTERRUPT ON MyArray[Counter].InterruptNumber when STRCOMP returns a TRUE.


    Although, honestly, I'm not sure why your program is so complex. You could literally write an entire subroutine that was just:

    Code
    DEF InterruptSet(InterruptNumber :IN)
        INTERRUPT ON InterrupNumber
    END

    Just what are you trying to accomplish with all that program complexity?

  • ; define some nice names for your interrupts so you don't have to hardcode them

    ; this is easier to remap and makes code more readable

    DECL INT isrCheckForHeight = 13

    DECL INT isrUpdateSomething = 87

    DECL INT isrReceiveData = 120


    ; same goes for I/O, use signals rather than hardcoded IO addresses

    SIGNAL HeightSensor $IN[27]


    ; then program can look like

    INTERRUPT DECL isrCheckForHeight HeightSensor DO StackHeightMeasure()

    INTERRUPT DECL isrReciveData ....

    ;....


    InterruptSet(#ON,isrCheckForHeight ,isrReceiveData,,isrUpdateSomething )


    but using arrays this line would look more like


    DECL INT MyIsr[10]


    MyIsr[1]=isrUpdateSomething

    MyIsr[9]=isrReceiveData

    MyIsr[3]=isrCheckForHeight

    InterruptSet(#ON,MyIsr[])

    The key difference is that you can use index to access each value inside your sub, rather than using FOR loop and all the string circus only to activate/deactivate one ( first) interrupt 10 times.


    using structures... well SkyFire beat me to it

    1) read pinned topic: READ FIRST...

    2) if you have an issue with robot, post question in the correct forum section... do NOT contact me directly

    3) read 1 and 2

  • You could literally simply create an array of STRUCs, like so:

    Code
    STRUC MyStruc CHAR String[], INT InterrupNumber
    
    DECL MyStruc MyArray[10]
    MyArray[1] = {String[] "IntNum1", InterruptNumber 1}
    MyArray[2] = {String[] "IntNum2", InterruptNumber 2}

    And so on. Then, you could FOR loop through the array, using STRCOMP to compare MyArray[Counter].String[] to your desired string, then DO INTERRUPT ON MyArray[Counter].InterruptNumber when STRCOMP returns a TRUE.


    Although, honestly, I'm not sure why your program is so complex. You could literally write an entire subroutine that was just:

    Code
    DEF InterruptSet(InterruptNumber :IN)
        INTERRUPT ON InterrupNumber
    END

    Just what are you trying to accomplish with all that program complexity?

    Ok fair doos and i get where you're coming from, does make sense. Although i didn't really think its that complex. Your method sounds as complex comparatively. Again, more so it wasn't strictly just about the setting interrupts it was the process of using string variables to structure things. Maybe its somewhat of my bias since i come from ABB's originally and their String handling is definitely a lot more on point. :thumbs_up: :smiling_face:

  • Ok nice, some interesting things for me to look at for sure :smiling_face: Cheers buddy. :smiling_face: :thumbs_up:

  • You could literally simply create an array of STRUCs, like so:

    Code
    STRUC MyStruc CHAR String[], INT InterrupNumber
    
    DECL MyStruc MyArray[10]
    MyArray[1] = {String[] "IntNum1", InterruptNumber 1}
    MyArray[2] = {String[] "IntNum2", InterruptNumber 2}

    And so on. Then, you could FOR loop through the array, using STRCOMP to compare MyArray[Counter].String[] to your desired string, then DO INTERRUPT ON MyArray[Counter].InterruptNumber when STRCOMP returns a TRUE.


    Although, honestly, I'm not sure why your program is so complex. You could literally write an entire subroutine that was just:

    Code
    DEF InterruptSet(InterruptNumber :IN)
        INTERRUPT ON InterrupNumber
    END

    Just what are you trying to accomplish with all that program complexity?

    Oh and just to add i actually did initially write the routine as suggested with a huge long switch case. But hey I'm a code snob. Shoot me :winking_face:

  • At the end of the day, programming in robots and PLCs is halfway between CNC machine G-Code, and 1970's-era pre-PC computer programming. Sadly, one must adjust one's standards of code snobbery to fit the programming environment. :bawling:

Advertising from our partners