Good way to slightly change a few positions depending on some $IN[xx]

  • Hi,


    I have used some defined positions in my program

    ...

    PTP TrayLeftUp

    PTP TrayLeftDown

    GripperClose()
    PTP TrayLeftDown2

    PTP TrayUp

    ...


    And now some other tray has slightly different (+5mm in one direction) coordinates ( and need to make the program work with both depending if some input "TrayType2" for example is true or not.


    What is the most elegant way to solve this.

    I could create completely new points for the new tray and use a CASE statement for the different cases - one using the old group of points, and the other using the new ones. But that seems messy.

    I could change the base before these points with an IF statement... and then change the base right back after these points.


    But how would the pro-s do it?

  • Not sure how professionals and even more so, experts, would do it, but that's what I would do:


    If the change of base does not matter to the program (there are no axial moves, base change does not affect status and turn, etc.), then parametrize the trays (turn them into offsets). That way you can easily have more (and there is going to be more; like 5 more). Something like:


    Code
    Decl Frame Trays[7]
    Tray[1] = {x 4, y 4, z 3, a 0, b 0, c 0}
    Tray[2] = {x 9, y 4, z 3, a 0, b 0, c 0}
    
    decl int _UsingTrayNr

    Then before movement:

    Code
    $Base = GetTrayBaseData(_UsingTrayNr)

    Which is just:

    Code
    deffct frame GetTrayBaseData(OffsetNr:in)
        decl int OffsetNr
        return TrayBase:Tray[OffsetNr]
    endfct


    This way I have all the tray info in one place and when I need to add more trays, I don't have to comb through the code for all the ifs and cases for tray related base changes.

    Edited once, last by Mentat: Forgot to declare variable type in function ().

  • Mentat, your approach seems convenient for many trays.

    Let me work through this

    You have a function "GetTrayBaseData" that returns the tray number with predefined offset

    You change the base before the prefefined points... with some SWITCH / CASE statements or IF statements.

    You need to change the base back to the original after these points.



    How do you feel about just modifying the point with a geometric operator ":"

    PTP TrayLeftUp:{X 5,Y 0,Z 0,A 0,B 0,C 0}


    I could then still use an IF statement

    I think its cleaner and easier to understand when I just have two variations.

    Also I am a bit scared to change the BASE and change it back again. I could manually jump around in the program during testing and forget to switch back the base.


    If I would have many more trays, handling them all with offsets in one area would definitely be more professional.

  • One more suggestion:

  • You have a function "GetTrayBaseData" that returns the tray number with predefined offset

    You change the base before the prefefined points... with some SWITCH / CASE statements or IF statements.

    You need to change the base back to the original after these points.

    "GetTrayBaseData" returns base to use depending on which tray number is given to it as parameter.

    For figuring out which tray number to use I would write a separate function and then inside it can use either inputs or global variables or voodoo magic, doesn't matter.

    Before motions in the tray base (which would be in a separate procedure themselves), base would be changed using "GetTrayBaseData".


    How do you feel about just modifying the point with a geometric operator ":"

    PTP TrayLeftUp:{X 5,Y 0,Z 0,A 0,B 0,C 0}


    I could then still use an IF statement


    My approach does use geometric operator:


    Code
    return TrayBase:Tray[OffsetNr]

    $Base = SomeBase:Offset

    ptp Point


    Is functionally the same as

    ptp Offset:Point



    Just that it's used once and the first tray is already considered an offset (even if it were just a nullframe).

    I would also prefer such approach, because if there are more than say 10 motions using tray base, it's less code and if I want to make changes to them (and I were not using global variables for point coordinates), I only have to make the change in one place. Say for example, I want to insert something like "lin_rel {z 10}" in between those motions.


    I think its cleaner and easier to understand when I just have two variations.

    Also I am a bit scared to change the BASE and change it back again. I could manually jump around in the program during testing and forget to switch back the base.


    If I would have many more trays, handling them all with offsets in one area would definitely be more professional.

    IMO, it cleaner and easier to understand when it's just one motion block with variation between bases :D

    You can't forget to switch back the base if you put the tray motions in procedure and get the tray number and change the base at the start of that procedure. As for jumping around with block select inside the procedure, if you are running inputs to determine which tray to use, you can run a check in sps to see if the set tray base and what base should be set for that tray are the same. Show MsgQuit if they are not.


    I don't know your work situation, but if there are very few moves over the trays, the moves/ their order won't ever change and there most definitely will not be some other trays. Your experience may vary, but in mine, requirements change during and after cell development, hence I try to make my code as modular and easy to extend or modify as I deem sane.


    The GetTrayBaseData() function may seem stupid as its implementation is just one actual line of code (others are just syntax), but likely some day the functionality will have to change. Maybe the base witch we are making offsets with will be on asynchronous rail, maybe I will have to hardcode the offsets with a long switch..case. Maybe every time I change base, something else will have to happen (e.g. light a diode).


    However, if your case is straightforward, the off course, keep the code simple. I have never complained about the code being too easy to understand :D

  • Three interesting things I found out, trying to implement this:

    • I have to define all the elements in the geometric operand, apart from Status and Turn.


      • Using only MyPoint:{X 5} gives an error
      • Must be MyPoint:{X 5,Y 0,Z 0,A 0,B 0,C 0}
    • The order of the geometric operand is important.
      • POS:FRAME outputs a FRAME
      • Expert Programming manual says:
        If the left-hand operand has the data type POS, type matching takes place. The position specified by the POS structure is transformed into a frame. That means the system determines the tool frame for this position.
      • This caused my position with the operand to move to the opposite direction because my tool is inverted.
        So MyPoint:{X 200,Y 0,Z 0,A 0,B 0,C 0} did not add 200mm but subtracted
        {X 200,Y 0,Z 0,A 0,B 0,C 0}:MyPoint added the 200mm to the original X component of MyPoint
      • Because if the robot wants to grab something from a table, the coordinate systems of the tool and the position match up. If I dont invert the tool, the robot flange wants to be inside the table. So I have to invert one of them... the point or the tool. There is a lot of points but only one tool... naturally I inverted the tool. I want the Z to point upwards for the things the robot needs to grab.
    • When I used the IF statement I lost my approximation "C_PTP" for the first point inside (EDIT: the point just before) the IF statement. Any cure for that?

    Edited once, last by Koppel ().

  • Three interesting things I found out, trying to implement this:

    • I have to define all the elements in the geometric operand, apart from Status and Turn.
    • The order of the geometric operand is important.
    • When I used the IF statement I lost my approximation "C_PTP" for the first point inside the IF statement. Any cure for that?


    1. Yeah, that's necessary, unless you write a specialized function that would change missing values to zeroes. But that would also make the operation slower.

    2. Indeed, geometric transformation is not commutable. Offset:Position offsets base; Position:Offset offsets tool. You will want {X 200,Y 0,Z 0,A 0,B 0,C 0}:MyPoint variant.

    3. That shouldn't be a problem- if you have something like "IF $in[123] then", that would stop approximation of the movement before it, but not after. Post the offending code segment, maybe it's something else.

    • Helpful

    Several, of course, have to make sure the cure is not worse than the disease :)


    The cause of it is that for approximation the advance pointer has to evaluate at least one motion after the approximated motion. Certain actions (including evaluating inputs) stop the advance pointer- you don't want to check inputs before it's time to.

    Onto the possible solutions:


    1. Precede the if statement with Continue as in:

    Code
     Continue
    If $in[123] then

    This way advance pointer will evaluate the input as soon as it gets there and won't wait for the motion to end. Kind of bad idea, because with large $Advance, it will check the input value several motions before it's due. Which might still be ok, but be wary (especially when modifying code later).


    2. Change the $in[123] for a boolean variable and set it in a procedure with a trigger during the motion before the if statement, like:

    Code
    TRIGGER WHEN DISTANCE=1 DELAY=0 DO SetTrayBase() PRIO=-1
    ptp PointBeforeIf c_ptp
    If IsFirstTraySet then
        ptp {x 5, y 0, z 0, a 0, b 0, c 0}:TrayLeftUp

    I like this better, because the input is checked on time, although here I would change to switch case and have SetTrayBase set a int type variable, which you can initialise with -1 or something else that the SetTrayBase can't set.


    3. A bit like option 2, but instead of trigger you would have SetTrayBase constantly running and updating Tray number in sps. Sort of meh, option 2 seems better to me.


    I suggest reading the expert programing part of the manual- it's unlikely you will learn everything in there perfectly on the first read through (at least I didn't), but you will have a better idea of what can be done and how.

  • careful here, it may look fantastic but inserting CONTINUE before condition that is controlled by something external is a perfect trap and collision magnet if that condition (input value in this case) changes. this can go on for long time before acting up and it is the key reason why I/O are only variable types that get evaluated by main pointer, not advance run pointer. sure as a programmer you can influence/change that behavior by adding CONTINUE and WAIT SEC 0 but without understanding exactly how they work.. this remains a trap!

    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

  • ....


    2. Change the $in[123] for a boolean variable and set it in a procedure with a trigger during the motion before the if statement, like:

    Code
    TRIGGER WHEN DISTANCE=1 DELAY=0 DO SetTrayBase() PRIO=-1
    ptp PointBeforeIf c_ptp
    If IsFirstTraySet then
        ptp {x 5, y 0, z 0, a 0, b 0, c 0}:TrayLeftUp

    I like this better, because the input is checked on time....

    This will NOT work.

    If $Advance is 3:

    At least 2 positions after the If will already be prepared complete when the trigger is executed. A change of the variable isfirsttrayset in the trigger will be too late.

  • correct but i would tweak wording a bit. $ADVANCE sets upper limit for number of motions to prepare, not lower limit. so instead of

    "At least 2 positions after the IF...", i think it would be better to say

    "Up to 3 positions after the IF..."


    Even with advance set to 3, robot will try hard to get at least 1 next motion... but after that, urgency to prepare more points drops of... so actual number of prepared points can vary depending on CPU load. It can be less than 3... but it will not exceed set limit (in this case 3).

    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

  • This will NOT work.

    If $Advance is 3:

    At least 2 positions after the If will already be prepared complete when the trigger is executed. A change of the variable isfirsttrayset in the trigger will be too late.

    You are right, would have to insert trigger way before than what I suggested to for it actually matter, good catch :)

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