Skip to content

About

πŸš€πŸ Python library for seamless communication with your Universal Robots cobot. Supports RTDE, URScript execution, Dashboard Server, SFTP, SSH, and more!

Topics

Resources

Stars

15 stars

Watchers

2 watching

Forks

Latest commit

Β 

History

44 Commits

Folders and files

Repository files navigation

Universal Robots Communication SDK for Python

UnderAutomation Universal Robots SDK

PyPI PyPI downloads Python Platforms License

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.

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.
  • REST API (PolyScope X): control the robot state and the programs over HTTP.
  • 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_received event.
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 and the PolyScope version.
  • Show and close popups on the teach pendant.
  • Set the operational mode (manual or automatic) for remote control.
  • Add messages to the log of the controller.
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.

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)

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 .urp programs and the .installation files.
  • 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)

Support

About

πŸš€πŸ Python library for seamless communication with your Universal Robots cobot. Supports RTDE, URScript execution, Dashboard Server, SFTP, SSH, and more!

Topics

Resources

Stars

15 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages