Skip to content

Update TCP

SUMMARY

update_tcp changes the transform [x, y, z, rx, ry, rz] (m, deg) of an already-registered named TCP frame. If the updated TCP is currently the active TCP, the change is pushed live to the controller when connected - the same push-to-hardware behavior as assigning active_tcp.

UNITS

transform is [x, y, z, rx, ry, rz] - translation in meters, orientation as Euler XYZ degrees, relative to the default TCP frame.

The Skill

python
robot.update_tcp(name="new_tool", transform=[0.0, 0.0, 0.2, 0.0, 0.0, 0.0])

The Code

0:00 / 0:00
python
"""
Registers a custom TCP frame and then updates it.

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

Usage:
    python update_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:
    """Add and update a custom TCP."""

    #===================== 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 ============================================
        new_tcp_pose_in_default_tcp_frame = [0.0, 0.0, 0.1, 0.0, 0.0, 0.0]  # 100 mm along Z-axis
        robot.add_tcp(name="new_tool",
                      transform=new_tcp_pose_in_default_tcp_frame,
                      set_active=True)

        # Get updated Active TCP, transform w.r.t default tcp, and TCP pose
        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()}")

        # Update the TCP
        updated_tcp_pose_in_default_tcp_frame = [0.0, 0.0, 0.2, 0.0, 0.0, 0.0]  # 200 mm along Z-axis
        robot.update_tcp(name="new_tool",
                         transform=updated_tcp_pose_in_default_tcp_frame)

        # Get updated Active TCP, transform w.r.t default tcp, and TCP pose
        logger.info(f"Active TCP after update_tcp(): {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="Add and then update a custom TCP on the robot.")
    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 update_tcp.py
bash
python update_tcp.py --prim_path /World/ur10e
bash
python update_tcp.py --ip 192.168.1.100

For all options:

bash
python update_tcp.py --help

Parameter Configuration

ParameterTypeDefaultDescription
namestrrequiredName of an already-registered custom TCP to update. Must exist in robot.get_tcps() and must not be default_tcp.
transformlist[float] | np.ndarrayrequiredNew 6-element pose [x, y, z, rx, ry, rz] relative to default_tcp. Position in meters, orientation as Euler XYZ in degrees.
set_activeboolTrueIf True, also makes name the active TCP after updating, pushing the change live when connected.

Returns

TypeDescription
Noneupdate_tcp returns nothing - it updates the registered transform as a side effect. Read robot.get_active_tcp_transform() (if the updated TCP is active) or robot.get_tcps() to confirm the new value.

Raises

ExceptionCondition
TypeErrorname is not a string, transform is not a list or np.ndarray, or transform contains non-numeric values
ValueErrorname equals default_tcp, name does not already exist (use Add TCP first), or transform is not a finite 1D 6-element [x, y, z, rx, ry, rz] vector

Where to Use the Skill

  • Live re-calibration - Adjust a TCP offset (e.g. after a tool change or a physical re-mount) without re-registering it under a new name.
  • Iterative tuning - Nudge a TCP's transform between trial runs while keeping the same name referenced elsewhere in the program.

When Not to Use the Skill

  • The TCP doesn't exist yet - use Add TCP to register a new named TCP frame.
  • You just need to switch between existing TCPs - use Change Active TCP, which doesn't change any stored transform.
  • You need to remove a TCP entirely - use Delete TCP instead of updating it.
  • You only need to read the current pose - use Get Cartesian Pose, which already resolves against whichever TCP is currently active.