Skip to content

Change Active TCP

SUMMARY

robot.active_tcp is the single place TCP changes are pushed to hardware. Assigning a new TCP name immediately pushes it to the controller when connected; offline, it refreshes the cached commanded pose via forward kinematics instead.

The Skill

python
robot.active_tcp = "my_tcp"

The Code

A UR10e manipulator with its active TCP switched via active_tcp
python
"""
Registers several TCP frames and switches the active one.

Supports Universal Robots (UR), Epson, virtual, and Isaac Sim.

Usage:
    python change_active_tcp.py [--ip <ROBOT_IP>] [--prim_path <PRIM_PATH>]
"""

import argparse

from loguru import logger

from telekinesis.synapse.robots.manipulators import universal_robots


def main(ip: str | None, prim_path: str | None) -> None:
    """Change the active TCP and observe it before and after each change."""

    #===================== Create Robot ==========================================
    robot = universal_robots.UniversalRobotsUR10E(name='UR10e')

    # ==================== Visualization (Optional) =============================
    robot.visualize_rerun(live=True)

    try:
        #===================== Connect Robot ==========================================
        if ip:
            robot.connect(ip=ip)
        elif prim_path:
            robot.connect(simulation_prim_path=prim_path)
            robot.set_joint_positions(robot.default_joint_configuration)

        # ==================== Run Skill ============================================
        robot.add_tcp(name="camera_tip",
                      transform=[0.0, 0.0, 0.1, 0.0, 0.0, 0.0],  # 100 mm along Z-axis
                      set_active=True)
        robot.add_tcp(name="gripper_tip",
                      transform=[0.0, 0.0, 0.2, 0.0, 0.0, 0.0],
                      set_active=False)
        robot.add_tcp(name="laser_tip",
                      transform=[0.0, 0.0, 0.3, 0.0, 0.0, 0.0],
                      set_active=False)

        logger.info(f"Active TCP after add_tcp(): {robot.active_tcp}"
                    f" \nActive TCP transform: {robot.get_active_tcp_transform()}"
                    f" \n TCP pose: {robot.get_cartesian_pose()}")

        robot.active_tcp = "gripper_tip"

        logger.info(f"Active TCP after changing active TCP: {robot.active_tcp}"
                    f" \nActive TCP transform: {robot.get_active_tcp_transform()}"
                    f" \n TCP pose: {robot.get_cartesian_pose()}")

        robot.active_tcp = "laser_tip"

        logger.info(f"Active TCP after changing active TCP again: {robot.active_tcp}"
                    f" \nActive TCP transform: {robot.get_active_tcp_transform()}"
                    f" \n TCP pose: {robot.get_cartesian_pose()}")
    except (ConnectionError, OSError) as e:
        logger.error(f"Error occurred: {e}")
    finally:
        robot.disconnect()
        robot.shutdown()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Register several TCPs on the robot and switch the active one.")
    parser.add_argument("--ip", type=str, default=None,
                         help="UR robot IP address for real hardware, e.g. 192.168.1.100")
    parser.add_argument("--prim_path", type=str, default=None,
                         help='Isaac Sim articulation prim path, e.g. "/World/ur10e"')
    args = parser.parse_args()

    main(ip=args.ip, prim_path=args.prim_path)

Running the Example

bash
python change_active_tcp.py
bash
python change_active_tcp.py --prim_path /World/ur10e
bash
python change_active_tcp.py --ip 192.168.1.100

For all options:

bash
python change_active_tcp.py --help

Parameter Configuration

ParameterTypeDefaultDescription
namestrrequiredName of an already-registered TCP frame to make active. Must already exist (see Get TCPs).

Returns

TypeDescription
strThe active_tcp getter returns the name of the currently active TCP frame.
NoneAssigning to active_tcp returns nothing - it is a property setter with a side effect (pushes to hardware when connected).

Raises

ExceptionCondition
ValueErrorname is not found in the kinematic model's frames
ConnectionError / OSErrorThe connection to the physical controller fails or drops while pushing the new active TCP (Universal Robots only)

Where to Use the Skill

  • Tool changes - Switch TCP when a different tool (gripper, sensor, custom end-effector) becomes active on the flange.
  • Multi-frame workflows - Register several TCPs up front with Add TCP (e.g. "camera_tcp", "gripper_tcp") and switch between them as a task progresses.
  • Live re-calibration - Update an existing TCP offset with Update TCP and have the change take effect immediately without a separate push call.

When Not to Use the Skill

  • You just need to read the current pose - use Get Cartesian Pose, which already resolves against whichever TCP is currently active.
  • You need a one-off pose in a different frame - pass frame_name to Forward Kinematics instead of switching the active TCP.
  • The TCP isn't registered yet - use Add TCP first; active_tcp can only be assigned a name that already exists (see Get TCPs to list what's registered).