One tool with two grippers (two TCP): how to define the RAPID tooldata

I have a tool made of two grippers attached to a flange adapter to pick two different pieces with the same robot. How do I define the tool in RAPID tooldata? It should account for both the grippers’ TCP but have a total mass that comprises the grippers and the flange adapter.

Thank you

The Tooldata contains the load for the tool, you should run Loadid two times with one tcp active then the other the second time. Loaddata contains the payload of the carried workpiece and is activated by the GripLoad instruction. Load0 is no payload, then you would need one piece in one gripper, one piece in the other gripper and then with both parts loaded. Each of these scenarios would be defined as a unique loaddata.

Hi…
As @lemster68 commented, the charge must be calculated in all possible cases and must be charged as you alternate between products and quantities.
In the case of TCP, as far as I know, it is unique for each tool, regardless of whether it has 1 or n grip positions. What you can do in this case is move the TCP to the center of the object you are currently manipulating.
I needed to do something similar and I created a method for this, which I share with you, I hope it helps.

MODULE Mod_DoubleGripper
    ! 1. BASE TOOL (Reference)
    ! tframe: Defined at the adapter center (or at Gripper 1 as zero reference)
    ! tload: Total mass (Adapter + Gripper 1 + Gripper 2) and COG of the entire assembly
    PERS tooldata tMasterGripper := [TRUE, [[0,0,150],[1,0,0,0]], [8.5, [10,0,80], [1,0,0,0], 0, 0, 0]];

    ! 2. WORKING TOOL (The one the robot actually uses in MoveL/J commands)
    VAR tooldata tActiveGripper;


	! ====================================================================================================
    ! Author:
    ! ------
    ! - SLSaibel - slsaibel@gmail.com
    !
    ! Description: PROC Main - Main execution block
    ! ====================================================================================================
    PROC Main()
        ! --- OPERATION WITH PART A ---
        ! Assuming Gripper A is offset by +100mm in Y and has a 90° rotation in Z
        EditOffsTCP_v2_1_1 tActiveGripper, tMasterGripper \offsTCPP:=[0,100,50] \rotP:=[0,0,90];
        
        MoveL pPickPointA, v500, z10, tActiveGripper;
        ! Pick part...

        ! --- OPERATION WITH PART B ---
        ! Assuming Gripper B is offset by -100mm in Y (opposite side)
        EditOffsTCP_v2_1_1 tActiveGripper, tMasterGripper \offsTCPP:=[0,-100,50] \rotP:=[0,0,-90];
        
        MoveL pPickPointB, v500, z10, tActiveGripper;
        ! Pick part...
    ENDPROC
	
	
	
	! ====================================================================================================
    ! Author:
    ! ------
    ! - SLSaibel - slsaibel@gmail.com
    !
    ! Description: PROC EditOffsTCP_v2_1_1 - Modifies TCP and Recalculates COG Correctly
    ! ====================================================================================================
    !
    ! Objective:
    ! ---------
    ! Change the position (`.trans`) and, optionally, the orientation (`.rot`) of a `tooldata` TCP,
    ! based on a reference and applying offsets. The routine recalculates the Center of Gravity (COG) 
    ! in a mathematically robust way so that its physical position in space is preserved.
    !
    ! Version History:
    ! ---------------------
    ! - v2.1.1 (2026-02-20)     : Removed mandatory offset parameter 'offsP'. Changed input parameter sequence. - SLS
    ! - v2.1.0 (2026-02-17)     : Included TCP offset parameters for the output tool. If the tool TCP is not exactly at the center, this parameter must be informed. - SLS
    ! - v2.0.0 (2025-06-12)     : [!] Critical Correction - COG calculation logic completely rewritten using the `pose` data type to ensure mathematical correctness in any translation or rotation.
    !                             The routine is now robust and predictable. - SLS
    ! - v1.2.1 (2025-05-28)     : Previous version with non-standard COG calculation logic.
    !
    ! Parameters:
    ! -----------
    !  setToolR  {INOUT tooldata}       : Tool (`tooldata`) to be modified.
    !  globalToolP   {IN tooldata}      : Reference tool, used as the base for calculations.
    !  \offsTCPP {IN \pos}              : Optional. TCP offset for the output tool.
    !  offsP {IN pos}                   : Translational offset (X, Y, Z) to be applied to the TCP.
    !  \rotP {IN \pos}                  : Optional. Rotation (Euler angles Rx, Ry, Rz in degrees) to be applied to the TCP orientation.
    !  \delayP   {IN \num}              : Optional. Wait time in seconds (default: 0.1s).
    !
    ! Dependencies:
    ! -------------
    ! - PoseMult(), PoseInv(), OrientZYX() (RAPID System)
    !
    ! Return:
    ! --------------------------
    !  [None] - Procedure.
    !
    ! Usage Example:
    ! ----------------------
    !  MODULE MOD_Test
    !   ! Necessary attributes
    !   PERS tooldata tBaseG := [TRUE, [[0,0,200],[1,0,0,0]], [1, [0,0,1], [1,0,0,0], 0, 0, 0]];
    !   VAR tooldata tNew;
    !   ! #####################
    !
    !   PROC main()
    !       ! Modifies the TCP applying offset and rotation, preserving the physical position of the COG
    !       EditOffsTCP_v2_1_1 tNew, tBaseG \offsTCPP:=[0,0,50] \rotP:=[0,0,180];
    !   ENDPROC
    !  ENDMODULE
    !
    ! Limitations and Observations:
    ! -------------------------
    ! - Depends on SystemAutenicate_v2_1_0().
    ! - From v2.0.0 onwards, the logic uses the `pose` type to ensure mathematical correctness in any translation or rotation.
    ! - It is necessary to check the path if migrating from versions 1.x.x.
    !
    ! ####################################################################################################
    ! # IMPORTANT  #
    ! ####################################################################################################
    ! # - The behavior of this version (v2.0.0) is DIFFERENT and CORRECT compared to versions 1.x.x.     #
    ! #   Test and validate the new path and the dynamic behavior of the robot after the update.         #
    ! ####################################################################################################
    !
    ! ====================================================================================================
	PROC EditOffsTCP_v2_1_1(INOUT tooldata setToolR,tooldata globalToolP\pos offsTCPP\pos rotP\num delayP)
        ! ## ATTRIBUTES ##############################################################################
        VAR pose poseTcpOriginalL;
        VAR pose poseCogTcpOriginalL;
        VAR pose poseCogGlobalL;
        VAR pose poseOffsetL;
        VAR pose poseNewTcpL;
        VAR pose poseCogNewTcpL;

        VAR pos offsAdjL:=[0,0,0];
        ! ## ATTRIBUTES ##############################################################################


        ! Verifying system authenticity ...
        !IF NOT SystemAutenicate_v2_1_0() EXIT;


        ! 1. CONVERT INPUT DATA TO 'POSE' FORMAT
        !'pose' groups position and orientation, ideal for transformations.
        ! Original TCP Pose relative to the robot flange ...
        poseTcpOriginalL.trans:=globalToolP.tframe.trans;
        poseTcpOriginalL.rot:=globalToolP.tframe.rot;

        ! COG Pose relative to the original TCP (orientation is null as it is a position vector) ...
        poseCogTcpOriginalL.trans:=globalToolP.tload.cog;
        poseCogTcpOriginalL.rot:=[1,0,0,0];


        ! 2. FIND THE PHYSICAL AND ABSOLUTE POSITION OF THE COG
        ! This position in space should not change when the TCP is altered.
        poseCogGlobalL:=PoseMult(poseTcpOriginalL,poseCogTcpOriginalL);


        ! 3. CALCULATE THE NEW TCP POSE
        ! Adds the TCP offset for the gripper ...
        IF Present(offsTCPP) THEN
            Add offsAdjL.x,offsTCPP.x;
            Add offsAdjL.y,offsTCPP.y;
            Add offsAdjL.z,offsTCPP.z;
        ENDIF

        IF Present(rotP) THEN
            IF Abs(rotP.z)=180 THEN
                offsAdjL.z:=-offsAdjL.z;
                ! X remains the same
                ! Y remains the same
            ENDIF
        ENDIF

        ! Define the offset pose to be applied.
        poseOffsetL.trans:=offsAdjL;

        IF Present(rotP) THEN
            ! Converts Euler angles (stored in 'pos') to a quaternion ('orient') ...
            poseOffsetL.rot:=OrientZYX(rotP.z,rotP.y,rotP.x);
        ELSE
            ! No rotation ...
            poseOffsetL.rot:=[1,0,0,0];
        ENDIF

        ! Applies the offset to the original TCP pose to obtain the new TCP pose ...
        poseNewTcpL:=PoseMult(poseTcpOriginalL,poseOffsetL);


        ! 4. CALCULATE THE NEW COG VECTOR (RELATIVE TO THE NEW TCP)
        ! The formula is: NewVector_COG = Inverse(NewPose_TCP) * GlobalPose_COG.
        poseCogNewTcpL:=PoseMult(PoseInv(poseNewTcpL),poseCogGlobalL);


        ! 5. UPDATE THE OUTPUT TOOL
        ! Copies all data from the reference tool (mass, inertia, etc.).
        setToolR:=globalToolP;

        ! Assigns the new calculated TCP frame ...
        setToolR.tframe.trans:=poseNewTcpL.trans;
        setToolR.tframe.rot:=poseNewTcpL.rot;

        ! Assigns the new COG position, now relative to the new TCP ...
        setToolR.tload.cog:=poseCogNewTcpL.trans;

        ! Waits for a period for the settings to be applied ...
        IF Present(delayP) THEN
            WaitTime delayP;
        ELSE
            WaitTime 0.1;
        ENDIF

        RETURN ;
    ERROR
        ! #############################################################################################
        ! HANDLING OF POSSIBLE ERRORS
        ! #############################################################################################

        ! Clears the screen ...
        TPErase;

        ErrWrite "UNHANDLED",EDIT_OFFS_TCP.versionedName
            \RL2:="Unhandled error in TCP/COG calculation."
            \RL3:="Please contact the automation team."
            \RL4:="RAPID Error No: "+ValToStr(ERRNO);

        IF OpMode()<>OP_AUTO THEN
            Stop;
            TRYNEXT;
        ELSE
            ! In AUTO mode, stops the robot immediately to avoid collisions with the wrong TCP.
            Stop;
            Stop;

            ! Propagates the error clearly to the main routine if necessary, or exits the program.
            EXIT;
        ENDIF
    ENDPROC
ENDMODULE

Adapt your reality
Good Job.