Universal Robots real-time data exchange (RTDE) using C#

Universal Robots real-time data exchange (RTDE) using C##

Background

A colleague and me wanted to find a C# library for controlling a Universal Robots UR3 robot arm with an OnRobot RG2 gripper for using in an industrial programming-related course.

At the end we could not find an open source-based solution and went for licensing the non-free library by UnderAutomation. In the following I wrote down my results.

I have used the following libraries:

  • sdurobotics/ur_rtde: A high-quality open-source C++ library from SDU with Python bindings. It can automatically load the control script for the robot and even restart it after a safety lock.

  • RyanPaulMcKenna/onRobot: A low-quality Python library, but it is the only one that I could find that can interface with the UR robot. It can get the gripper width and apply width along with force.

Using the two above I could successfully move the gripper to a pose in base coordinates and open & close the gripper.

Other libraries I stumbled upon but did not use:

  • https://sourceforge.net/p/firsttestfchaxel/code/HEAD/tree/trunk/Ur_Rtde: An undocumented C# library, which lacks functions like automatic loading of control script and inverse kinematics for controlling the gripper in base coordinates.

  • takuya-ki/onrobot-rg: Python library for some OnRobot grippers. Can only interface the control box of the gripper directly.

  • RoboDK: Commercial simulator and programmer with support for most industrial robot arms. Features a C# API. This solution is non-free and probably abstract too much for a C# programming course.

  • UniversalRobots: A high-quality commercial C# library for RTDE that must be licensed. They provide an academic license with ~40% off at 594 EUR. According to UnderAutomation it is a perpetual license independent of how many students or robots.

Failure at wrapping C++ code for using in C#:#

I tried to wrap ur_rtde for using in the .NET environment, but could not manage it in an acceptable time frame. In the following you find my notes.

In the following I assume that you downloaded and compiled ur_rtde.

Using SWIG#

ur_rtde is based on C++ and the easiest solution to create a C# wrapper is to use SWIG, which in ideal case does not require any manual code. Unfortunately, ur_rtde uses C++ keywords that SWIG could not parse, e.g., RTDE_EXPORT. Removing these attributes solves the problem.

Another problem is typing mismatches between C++ and C#, e.g., std:vector<double> does not have a direct correspondence in C#, so the user must provide a manual mapping.

Using CppSharp#

I tried to create a wrapper using:

dotnet new console -n test
cd test
dotnet add package cppsharp

Then used the following program to parse ur_rtde headers following the tutorial:

Program.cs:

using CppSharp;
using CppSharp.AST;
using CppSharp.Generators;

public class URRTDELibrary : ILibrary
{
    public void Setup(Driver driver)
    {
        // Define the options for the driver
        var options = driver.Options;
        options.GeneratorKind = GeneratorKind.CSharp;
        var module = options.AddModule("ur_rtde");
        module.IncludeDirs.Add("include");
        module.Headers.Add("ur_rtde/rtde_control_interface.h");
        module.LibraryDirs.Add("lib");
        module.Libraries.Add("librtde.so"); // Or librtde.dll for Windows

    }
public void SetupPasses(Driver driver) { }
    public void Preprocess(Driver driver, ASTContext ctx) { }
    public void Postprocess(Driver driver, ASTContext ctx) { }
}

class Program
{
    static void Main(string[] args)
    {
        ConsoleDriver.Run(new URRTDELibrary());
    }
}

Then run it:

$ dotnet build && dotnet run
Parsing libraries...
 Parsed 'librtde.so'
 Parsing code...
 Parsed 'ur_rtde/rtde_control_interface.h'
 Processing code...
 Generating code...
 Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
    at CppSharp.AST.ClassExtensions.HasDependentValueFieldInLayout(Class class, IEnumerable`1 specializations)

I have the hunch this error is due to unsupported datatypes like std:vector<double>. I had a similar error in SWIG.

Manual wrapping methods#

There are two other wrapping methods:

Both methods require manually creating a wrapper between the native C++ code and the managed C# code. ur_rtde comprises dozens of functions, so this could take days. I believe SWIG and CppSharp use one of these methods under the hood.