Universal Robots Communication SDK for Python
UnderAutomation.UniversalRobots is a Python package that communicates with Universal Robots cobots (CB-Series, e-Series and the newer models, PolyScope and PolyScope X) through the standard interfaces of the controller: RTDE, Dashboard Server, REST API, Primary Interface, SFTP, sockets and XML-RPC. It also computes the forward and inverse kinematics offline. No URCap and no option is needed on the robot.
It works with real robots and with the URSim simulator.
- Product page: underautomation.com/universal-robots
- Documentation: underautomation.com/universal-robots/documentation/get-started-python
- Also available for .NET, LabVIEW and Unity
What you can do
- RTDE: read the robot data at up to 500 Hz (TCP pose, joint angles, forces, I/O, registers) and write inputs and registers.
- Dashboard Server (PolyScope): load, play and stop programs, power on and off, release the brakes, read the robot mode and the safety mode.
- REST API (PolyScope X): control the robot state and the programs over HTTP, read the robot and safety modes, list, upload and download the program files.
- Primary Interface: receive the data packets of the robot and send URScript commands.
- SFTP: list, download and upload programs and files over SSH.
- Kinematics: offline forward and inverse kinematics for every UR model, without connection.
- Socket communication: exchange messages between Python and a URScript program.
- License: trial, registration and state of the license.
How it works
The package wraps the .NET library UnderAutomation.UniversalRobots.dll with
pythonnet. The DLL is inside the package: pip install installs
everything, including pythonnet.
-
Windows: the DLL runs on the .NET Framework 4.x of Windows. Nothing else to install.
-
Linux and macOS: install the .NET runtime (for example .NET 8), then tell pythonnet to use it before you start Python:
# Debian and Ubuntu, for example sudo apt-get install -y dotnet-runtime-8.0 export PYTHONNET_RUNTIME=coreclr
Without this variable, pythonnet uses Mono, its default runtime on Linux and macOS. You can also choose the runtime in your code, before the first import of the package:
from pythonnet import load load("coreclr")
Installation
Python 3.7 to 3.13 is supported (the limit of pythonnet 3.0.5). Install the package in a virtual environment:
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux and macOS
source .venv/bin/activate
pip install UnderAutomation.UniversalRobots
Or install it from the sources of this repository:
git clone https://github.com/underautomation/UniversalRobots.py.git
cd UniversalRobots.py
pip install -e .
Getting started
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.connect_parameters import ConnectParameters
from underautomation.universal_robots.rtde.rtde_output_data import RtdeOutputData
from underautomation.universal_robots.rtde.rtde_input_data import RtdeInputData
# The SDK runs in trial mode for 30 days. Register your key to remove the trial limit.
# UR.register_license("Your Company", "your-license-key")
robot = UR()
params = ConnectParameters("192.168.0.1")
# Dashboard Server: load, play and stop programs, robot state
params.dashboard.enable = True
# Primary Interface: data packets, URScript
params.primary_interface.enable = True
# RTDE: robot data at up to 500 Hz
params.rtde.enable = True
params.rtde.frequency = 10
params.rtde.output_setup.add(RtdeOutputData.ActualTcpPose)
params.rtde.output_setup.add(RtdeOutputData.ActualQ)
params.rtde.input_setup.add(RtdeInputData.InputIntRegisters, 24)
# SFTP file transfer over SSH
params.ssh.enable = True
params.ssh.enable_sftp = True
params.ssh.username = "ur"
params.ssh.password = "easybot"
robot.connect(params)
# Read the TCP pose with RTDE
@robot.rtde.output_data_received
def on_rtde(sender, event):
pose = robot.rtde.output_data_values.actual_tcp_pose
print(f"TCP: x={pose[0]:.3f} y={pose[1]:.3f} z={pose[2]:.3f}")
# Send a URScript command
robot.primary_interface.script.send('popup("Hello from Python!", blocking=False)')
# Dashboard: load and start a program
robot.dashboard.load_program("my_program.urp")
robot.dashboard.play()
# SFTP: list the programs of the controller
for program in robot.sftp.enumerate_programs():
print(program)
robot.disconnect()
From .NET names to Python names
The Python API is the .NET API with Python names. The .NET documentation applies to Python.
| .NET | Python |
|---|---|
Method robot.Dashboard.LoadProgram("my_program.urp") |
robot.dashboard.load_program("my_program.urp") |
Property parameters.Rtde.Frequency |
params.rtde.frequency |
Static method UR.RegisterLicense(...) |
UR.register_license(...) |
Enum value RtdeOutputData.ActualTcpPose |
RtdeOutputData.ActualTcpPose |
Event robot.Rtde.OutputDataReceived |
decorator @robot.rtde.output_data_received |
Array double[] |
list-like object, use list(...) to copy it |
Each type is in the module named after it, in snake case:
UnderAutomation.UniversalRobots.Rtde.RtdeOutputData is
underautomation.universal_robots.rtde.rtde_output_data.RtdeOutputData.
Examples
The folder examples contains scripts ready to run, one folder per interface.
| File | Role |
|---|---|
examples/launcher.py |
Menu to browse and run every example |
examples/__init__.py |
Shared helpers: robot address, SSH credentials, license |
examples/robot_config.json |
Saved settings (ignored by git): robot address, credentials and license key |
The first run asks the address of the robot and saves it. Run a script from the root of the repository, or open the launcher:
python examples/dashboard/dashboard_get_robot_state.py
python examples/launcher.py
Dashboard Server, PolyScope (port 29999)
| Script | What it does |
|---|---|
| dashboard_get_robot_state.py | Reads the robot mode, the loaded program, the program state and the PolyScope version |
| dashboard_load_play_program.py | Loads a .urp program and starts it |
| dashboard_power_on_release_brakes.py | Powers on the arm and releases the brakes |
| dashboard_popup_message.py | Shows a popup on the teach pendant, then closes it |
REST API, PolyScope X (port 80)
| Script | What it does |
|---|---|
| rest_get_robot_state.py | Reads the robot state and the program state |
| rest_load_play_program.py | Loads and starts a program |
| rest_power_on_brake_release.py | Powers on the robot and releases the brakes |
RTDE (port 30004)
| Script | What it does |
|---|---|
| rtde_read_tcp_pose.py | Reads the TCP pose (x, y, z, rx, ry, rz) and the joint angles |
| rtde_read_digital_io.py | Reads the digital inputs and outputs and shows their changes |
| rtde_read_write_registers.py | Reads output integer registers and writes input integer registers |
SFTP (port 22)
| Script | What it does |
|---|---|
| sftp_list_programs.py | Lists the .urp programs and browses the file system of the robot |
| sftp_download_program.py | Downloads a .urp program from the controller |
| sftp_upload_program.py | Uploads a local .urp program to the controller |
Primary Interface (port 30001)
| Script | What it does |
|---|---|
| primary_interface_read_telemetry.py | Receives the robot mode, the joint data and the Cartesian data |
| primary_interface_send_urscript.py | Sends URScript commands to the controller |
| primary_interface_global_variables.py | Reads the global variables of the loaded program |
Kinematics (no connection)
| Script | What it does |
|---|---|
| kinematics_forward_inverse.py | Selects a UR model, computes the forward kinematics, then every inverse kinematics solution |
License
| Script | What it does |
|---|---|
| license_info_example.py | Shows the license state, registers a license and shows its properties |
Interfaces
RTDE
RTDE sends the robot data at up to 500 Hz on port 30004. You choose the outputs to read and the inputs to write.
- Read any set of outputs: TCP pose, joint positions, forces, I/O, temperatures, voltages...
- Write inputs: digital and analog outputs, integer, double and boolean registers.
- Choose the frequency, from 1 to 500 Hz (RTDE version 2).
- Handle each new sample in the
output_data_receivedevent. - Read the software version, the control box type and the tool flange type of the controller
(
software_version,control_box_type,tool_flange_type), on PolyScope 5.26.3 or later and PolyScope X 10.15 or later.
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.connect_parameters import ConnectParameters
from underautomation.universal_robots.rtde.rtde_output_data import RtdeOutputData
from underautomation.universal_robots.rtde.rtde_input_data import RtdeInputData
from underautomation.universal_robots.rtde.rtde_input_values import RtdeInputValues
robot = UR()
params = ConnectParameters("192.168.0.1")
params.rtde.enable = True
params.rtde.frequency = 125
params.rtde.output_setup.add(RtdeOutputData.ActualTcpPose)
params.rtde.output_setup.add(RtdeOutputData.ActualTcpForce)
params.rtde.output_setup.add(RtdeOutputData.ActualDigitalOutputBits)
params.rtde.input_setup.add(RtdeInputData.InputIntRegisters, 24)
robot.connect(params)
@robot.rtde.output_data_received
def on_data(sender, event):
values = robot.rtde.output_data_values
pose = values.actual_tcp_pose
force = values.actual_tcp_force
print(f"x={pose[0]:.3f} Fx={force[0]:.2f} N")
# Write to the robot
inputs = RtdeInputValues()
inputs.input_int_registers.x24 = 42
robot.rtde.write_inputs(inputs)
robot.disconnect()
Dashboard Server (PolyScope)
The Dashboard Server listens on port 29999. It controls the programs and the robot state, on CB-Series and e-Series robots.
- Load, play, stop and pause programs.
- Power the arm on and off, release the brakes.
- Read the robot mode, the safety status, the safety mode and the PolyScope version.
- Show and close popups on the teach pendant.
- Set the operational mode (manual or automatic) for remote control. Read the user role.
- Add messages to the log of the controller, save the log, generate flight reports and support files.
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.connect_parameters import ConnectParameters
robot = UR()
params = ConnectParameters("192.168.0.1")
params.dashboard.enable = True
robot.connect(params)
robot.dashboard.power_on()
robot.dashboard.release_brake()
robot.dashboard.load_program("my_program.urp")
robot.dashboard.play()
mode = robot.dashboard.get_robot_mode()
print(f"Robot mode: {mode.value}")
robot.disconnect()
REST API (PolyScope X)
The REST API exists on PolyScope X robots. It controls the robot and the programs over HTTP.
- Power the arm on and off, release the brakes, unlock a protective stop, restart the safety.
- Load, play, pause, resume and stop programs.
- Read the robot mode, the safety mode, the operational mode, the remote control state and the PolyScope X version.
- Show and close popups on the teach pendant.
- List, upload, replace and download the program files.
robot.rest has the same method names as robot.dashboard, so one function controls both families.
Only the brakes differ: brake_release() on robot.rest, release_brake() on robot.dashboard.
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.connect_parameters import ConnectParameters
robot = UR()
params = ConnectParameters("192.168.0.1")
params.rest.enable = True
robot.connect(params)
robot.rest.power_on()
robot.rest.brake_release()
robot.rest.load_program("my_program")
robot.rest.play()
state = robot.rest.get_program_state()
print(state.value)
print(robot.rest.get_safety_mode().value)
for program in robot.rest.get_programs().value:
print(program.name)
robot.rest.download_program_to_file("my_program", "my_program.urpx")
robot.disconnect()
Primary Interface
The Primary Interface (port 30001) sends data packets about 10 times per second and accepts URScript commands.
- Receive the robot mode, the joint data, the TCP position, the tool data, the safety data and more.
- Send URScript programs or commands, executed at once.
- Read the global variables of the loaded program.
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.connect_parameters import ConnectParameters
robot = UR()
params = ConnectParameters("192.168.0.1")
params.primary_interface.enable = True
robot.connect(params)
@robot.primary_interface.cartesian_info_received
def on_cartesian(sender, event):
c = robot.primary_interface.cartesian_info
print(f"x={c.x:.3f} y={c.y:.3f} z={c.z:.3f}")
robot.primary_interface.script.send('set_digital_out(0, True)')
robot.disconnect()
SFTP
SFTP gives access to the file system of the controller over SSH (port 22). The default user is ur, with
the password easybot.
- List, download and upload files.
- List the
.urpprograms and the.installationfiles. - Create and delete folders.
params.ssh.enable = True
params.ssh.enable_sftp = True
params.ssh.username = "ur"
params.ssh.password = "easybot"
robot.connect(params)
programs = robot.sftp.enumerate_programs()
robot.sftp.download_file("/programs/my_prog.urp", "C:/backup/my_prog.urp")
robot.sftp.upload_file("C:/new_prog.urp", "/programs/new_prog.urp")
Kinematics
The SDK computes the forward and inverse kinematics offline, with the factory Denavit-Hartenberg parameters of every UR model: UR3, UR5, UR10, UR3e, UR5e, UR7e, UR10e, UR12e, UR16e, UR8 Long, UR15, UR18, UR20 and UR30. No connection and no license are needed.
import math
from underautomation.universal_robots.kinematics.kinematics_utils import KinematicsUtils
from underautomation.universal_robots.common.robot_models_extended import RobotModelsExtended
dh = KinematicsUtils.get_dh_parameters_from_model(RobotModelsExtended.UR10e)
# Forward kinematics: joint angles to TCP pose
angles_rad = [math.radians(a) for a in [0, -90, 0, -90, 0, 0]]
result = KinematicsUtils.forward_kinematics(angles_rad, dh)
T = result.tool_transform # 4x4 homogeneous matrix (flat list of 16 floats)
# Inverse kinematics: TCP pose to every joint solution
solutions = KinematicsUtils.inverse_kinematics(T, dh)
nearest = KinematicsUtils.get_nearest_solution(solutions, angles_rad)
print([math.degrees(v) for v in nearest])
Compatibility
- Python: 3.7 to 3.13, with pythonnet 3.0.5.
- Operating systems: Windows (.NET Framework), Linux and macOS (.NET runtime and
export PYTHONNET_RUNTIME=coreclr). - Robots: CB-Series (CB3), e-Series and the newer models, PolyScope and PolyScope X, and URSim.
License
This SDK needs a commercial license. A 30-day trial starts at the first use, no key needed. After the trial, register your key in your code:
from underautomation.universal_robots.ur import UR
license_info = UR.register_license("Your Company", "your-license-key")
print(license_info)
- License agreement: underautomation.com/universal-robots/eula and License.md
- New trial period by email: underautomation.com/license
- Prices and order: underautomation.com/order
Support
- Documentation: underautomation.com/universal-robots/documentation
- Issues: GitHub Issues
- Contact: underautomation.com/contact
Metadata
Release files for UnderAutomation.UniversalRobots 9.5.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| underautomation_universalrobots-9.5.0.1.tar.gz | 584.5 kB | Without provenance | Details for underautomation_universalrobots-9.5.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| underautomation_universalrobots-9.5.0.1-py3-none-any.whl | Python 3 | none | any | Details for underautomation_universalrobots-9.5.0.1-py3-none-any.whl |
Total release size: 1.3 MB
Release files / underautomation_universalrobots-9.5.0.1.tar.gz
| Download URL | underautomation_universalrobots-9.5.0.1.tar.gz |
|---|---|
| Size | 584.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
587187fe56e1ac5e81e1b2cc8ae560fd0eff72407c997c50a5b317da7415a0a5
|
|
BLAKE2b-256 checksum How to use checksums |
1ad4caa98b415285e67697159697b26d8ecc6e4e4876b946928ff45fbf0a3c23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / underautomation_universalrobots-9.5.0.1-py3-none-any.whl
| Download URL | underautomation_universalrobots-9.5.0.1-py3-none-any.whl |
|---|---|
| Size | 710.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e4cfc7ee641105c876474850b902a935a661b5f45629e7c9858fe8b4b0edfb9
|
|
BLAKE2b-256 checksum How to use checksums |
8c73af68225254876232c80d94195901b15306051fb6f0b0920147994c1cd3b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for UnderAutomation.UniversalRobots 9.5.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.