How to send and receive data between Python and a UR robot over a TCP/IP socket

Based on contributions by Ihsan, pauladelahoz, Thanusan_Thurairajah, Dave_Vermeulen, How-to.

Use this method when you want to exchange data between a Python program on your PC and a UR robot — for example sending coordinates from a vision script, or sending simple commands and reading back sensor values — without installing the RTDE library. It works by opening a plain TCP socket between the robot controller and your PC.

What you need

Steps

1. Choose an IP address and a port

You already need an IP address for the robot and your PC (see How to find and set the IP address for connecting a PC to a UR robot). You also need a port number: a number between 0 and 65535 that identifies a specific service on that IP address.

  • Ports 0–1023 are reserved for common protocols (HTTP, HTTPS, FTP, SSH, …) — don’t use these.
  • Ports 1024–49151 are registered/assigned ports (IANA).
  • Ports 49151–65535 are free for temporary/private use — the best range to pick a port for your own robot communication.

2. Decide which side is the TCP server

Either side can act as the server (the one that binds and listens for a connection) and either side can be the client (the one that connects out). Most examples in these how-tos use the PC as the server and the robot as the client, since it’s simpler to set up from URScript with socket_open.

3. Set up the Python side (server)

import socket

HOST = "192.168.0.185"  # your PC's IP address
PORT = 5000              # must match the port used by the robot

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))   # port can be anything above 1024, as long as no other process is using it
server_socket.listen(5)
print("Server is listening for connections...")

while True:
    client_socket, address = server_socket.accept()
    print(f"Connection from {address} has been established!")

    while True:
        msg = client_socket.recv(1024)
        if not msg:
            break
        print(msg.decode("utf-8"))

        message_to_send = "(1.2, 1.3, 1.4)"
        client_socket.sendall(bytes(message_to_send, "ascii"))

    client_socket.close()

4. Set up the robot side (URScript client)

port = 5000
ip = "192.168.78.1"  # your PC's IP address
socket_name = "anything"

socket_open(ip, port, socket_name)

while True:
    # receive the expected 3 floating point values
    receive = socket_read_ascii_float(3, socket_name)
    textmsg(receive)

    # send a message back
    socket_send_string("Send your strings here", socket_name)
end

socket_close(socket_name)

Place socket_open and socket_close outside the main program loop — opening the connection on every loop iteration causes performance issues and can overload the network.

5. Send different data types from the robot

The robot has dedicated functions to send single values of different types:

byte_value = 1
socket_send_byte(byte_value)     # send a single byte (0-255)
socket_send_int(2)               # send an integer
socket_send_string("hello")      # send a string

6. Read those values on the Python side

import struct

# Read one byte sent with socket_send_byte
data = client_socket.recv(1)
byte_values = struct.unpack('1B', data)
print(f"Received byte: {byte_values[0]}")

7. Send a list of numbers from Python to the robot

To send a list of integers as raw bytes:

import struct

def send_data(sock, data_list):
    try:
        byte_data = struct.pack(f'{len(data_list)}B', *data_list)
        sock.sendall(byte_data)
        print(f"List sent to the robot: {data_list}")
    except Exception as e:
        print(f"Error sending data: {e}")

data_list = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
send_data(client_socket, data_list)

To send a list of floats, encode them as a comma-separated ASCII string instead:

def send_floats(sock, data_list):
    float_str = ",".join(str(f) for f in data_list)
    sock.sendall(float_str.encode('ascii'))

8. Read a list of numbers on the robot

socket_open("192.168.0.185", 30000)

# Only works if the incoming values are integers
integers = socket_read_byte_list(10)  # adjust the count to the size of the array sent

# Use this if the incoming values are floats, sent as e.g. "(1.2, 1.3, 1.4)"
floats = socket_read_ascii_float(10)  # adjust the count to the size of the array sent

textmsg("Integer value on position 1: ", integers[1])
textmsg("Float value on position 1: ", floats[1])

The float string must be a parenthesized, comma-separated list, e.g. (1.2, 1.3, 1.4). If a read fails, the first element of the returned list is 0, followed by -1 for socket_read_byte_list or nan (“Not a Number”) for socket_read_ascii_float.

9. Worked example: receiving and parsing an “X,Y,Z” string

Some servers (e.g. a vision script) don’t send fixed-size numeric arrays but a single line of text like "-0.45,0.375,0.25". Read it with socket_read_line and parse it manually:

# Constants
SOCKET_HOST = "192.168.0.10"    # IP address of the external vision server (usually your PC)
SOCKET_PORT = 30020
SOCKET_NAME = "vision_socket"
RESPONSE_TIMEOUT = 0.5           # seconds to wait for a response

# Open the connection once, at the start of the program
socket_open(SOCKET_HOST, SOCKET_PORT, SOCKET_NAME)
textmsg("Connection to vision server has been opened.")

# Inside the main processing loop:
socket_send_string("ready\n", SOCKET_NAME)
data = socket_read_line(SOCKET_NAME, timeout=RESPONSE_TIMEOUT)

if data != "":
    coords = data

    comma1 = str_find(coords, ",")               # position of the comma between X and Y
    comma2 = str_find(coords, ",", comma1 + 1)    # position of the comma between Y and Z

    if (comma1 > -1) and (comma2 > -1):
        x_vision = to_num(str_sub(coords, 0, comma1))

        length_y = comma2 - (comma1 + 1)
        y_vision = to_num(str_sub(coords, comma1 + 1, length_y))

        length_z = str_len(coords) - (comma2 + 1)
        z_vision = to_num(str_sub(coords, comma2 + 1, length_z))

# Close the connection once, when the program stops
socket_close(SOCKET_NAME)

x_vision, y_vision and z_vision are now numeric (float) and ready to use as position coordinates in a move command.

Function Type Purpose
str_find String Returns the position of a character within a string
str_sub String Extracts part of a string, given a start position and length
to_num Conversion Converts a string to a numeric (float) value

Troubleshooting / Common mistakes

  • Opening/closing the socket inside the main loop instead of once at the start/end — causes reconnects, performance issues and can overload the network.
  • \n at the end of a sent string is the message delimiter that socket_read_line waits for — forgetting it means the other side blocks until it times out.
  • If socket_read_line/socket_read_ascii_float times out, it returns an empty string / a list starting with 0 — always check for this before parsing.
  • Two programs cannot bind to the same port at the same time on one machine.
  • socket_read_ascii_float expects the numbers formatted in parentheses and separated by commas, e.g. (1.2, 1.3, 1.4) — plain comma-separated text (no parentheses) will not parse correctly; use socket_read_line + manual parsing (step 9) for that instead.

Related


Rewritten and consolidated (Sept 2026) from the original student how-to’s: Create TCP/IP connection between your PC and a Universal robot, How to send and receive information between python and UR5 robot, How to receive coordinates (x, y, z) with the universal robot via TCP/IP communication, How-to Connect a Cobot to your laptop using Python (Complete Guide), Connect a Universal robot to a Python program on a computer.