Contact Detection
SUMMARY
Contact detection lets you interrupt an asynchronous motion the moment the robot touches something - useful for assembly insertion, surface probing, and collision-aware free-space moves.
start_contact_detection arms the controller's contact detection subsystem.
read_contact_detection polls the current state without disarming - call it in a loop while the robot is moving.
stop_contact_detection disarms detection and returns the definitive final result.
SUPPORTED ROBOTS
Currently supported only on Universal Robots.
UNITS
direction is an optional 3-element Cartesian vector [dx, dy, dz] (unitless - only the direction matters, not magnitude). Returns booleans only.
The Skill
# Arm contact detection (optionally constrained to a direction)
robot.start_contact_detection(direction=[])
# Poll the detection state during motion
contact = robot.read_contact_detection()
# Disarm and retrieve the final result
contact = robot.stop_contact_detection()The Code
Safety first!
A real robot will faithfully do whatever you ask of it - so please take a moment to clear the workspace, keep an E-Stop within reach, and be ready to disconnect.
Operating real hardware is at your own risk.
Example: Move and Detect Contact
Start an asynchronous Cartesian move, arm contact detection, poll at 20 Hz, then disarm.
"""
Contact Detection example for the Synapse SDK.
Shows the full lifecycle: ``start_contact_detection`` arms the watcher,
``read_contact_detection`` polls during motion, and ``stop_contact_detection``
disarms it and returns the final result.
Currently supported only for Universal Robots (UR10e).
Usage:
python contact_detection.py --ip <ROBOT_IP>
"""
import argparse
import time
from loguru import logger
from telekinesis.synapse.robots.manipulators import universal_robots
def main(ip: str):
"""Run an async +Z move with contact detection armed, poll, then stop."""
# Create and connect to the robot
robot = universal_robots.UniversalRobotsUR10E()
robot.connect(ip=ip)
try:
# Get current pose and define a target slightly above in Z
current = robot.get_cartesian_pose()
target = list(current)
target[2] += 0.002
logger.info(f"Will move async toward {target} and watch for contact")
# Start an asynchronous move and arm contact detection
robot.set_cartesian_pose(
cartesian_pose=target,
speed=0.05,
acceleration=0.1,
asynchronous=True,
)
robot.start_contact_detection()
# Poll for contact for up to 1 s
for _ in range(20):
if robot.read_contact_detection():
logger.info("Contact detected!")
break
time.sleep(0.05)
# Disarm contact detection and report the final result
contact = robot.stop_contact_detection()
logger.success(f"Final contact: {contact}")
finally:
robot.disconnect()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Contact Detection Synapse example")
parser.add_argument("--ip", type=str, required=True, help="UR robot IP address")
args = parser.parse_args()
main(ip=args.ip)The Explanation of the Code
start_contact_detection arms the contact detection subsystem on the controller. The optional direction parameter constrains detection to a specific Cartesian direction (3-element vector [dx, dy, dz]); passing an empty list (default) enables omnidirectional detection. This skill is typically paired with an asynchronous move so the Python process can poll while motion continues.
read_contact_detection queries whether contact has been detected since detection was armed. It does not stop detection - the robot continues moving and the subsystem remains armed after the call. Call it in a polling loop at the desired rate.
stop_contact_detection disarms the subsystem and returns the definitive boolean: True if any contact event was recorded during the detection window, False if the move completed without contact. Always call it to cleanly finalize a detection session, even if contact was already observed via read_contact_detection.
How to Tune the Parameters
start_contact_detection
| Parameter | Type | Default | Description |
|---|---|---|---|
direction | list[float] | [] | Optional 3-element Cartesian direction [dx, dy, dz] to limit detection. Empty list enables omnidirectional detection. |
read_contact_detection
This skill takes no input parameters.
stop_contact_detection
This skill takes no input parameters.
Return Value
| Method | Type | Description |
|---|---|---|
start_contact_detection | bool | True if contact detection was successfully armed, False otherwise. |
read_contact_detection | bool | True if contact has been detected, False if no contact has occurred yet. |
stop_contact_detection | bool | True if contact was detected during the detection window, False otherwise. |
Where to Use the Skill
- Assembly insertion - Detect the moment a part makes contact with a mating feature.
- Surface probing - Stop motion when the TCP touches a surface.
- Collision avoidance - React to unexpected contact during free-space moves.
- High-frequency polling loops - Check for contact at 20-125 Hz during asynchronous motion.
When Not to Use the Skill
- You need force-torque data after contact - use Get TCP Force to read wrench values.
- The move is synchronous - contact detection is intended for use with asynchronous moves so the Python process can poll while motion continues.
- You only need contact during a guarded approach - use Move Until Contact for a single guarded move with a built-in stop condition.

