It is not easy to implement an RTDE client using C#. I have done it successfully for my company’s product but won’t be able to share any code.
You will need to follow and truly understand the RTDE specification and the example Python implementation provided at the support site you linked. One significant problem you will face with C# is that CLR on Windows uses small-endian byte order while the RTDE messages need to be in the big-endian (“network”) byte order so you need to do your own marshalling.
I also found it useful to capture packets from the reference Python implementation using Wireshark and compare those with my own implementation. This way I also noticed that the RTDE specification had some errors and missing important information that I reported and have since been corrected.
You have to be careful with UTF8 encoding. Controller expects ASCII codes, and will not recognize multibyte UTF8 encoded characters (or worse, misinterpret them). In production code you should either make sure that no character is encoded as multibyte, or use ASCII encoding.
To quickly connect to RTDE (or even primary interface to receive info and send script), you can take a look at this library that allows you to connect to the robot in a few lines:
using UnderAutomation.UniversalRobots;
using UnderAutomation.UniversalRobots.Common;
using UnderAutomation.UniversalRobots.Rtde;
using UnderAutomation.UniversalRobots.Rtde.Internal;
class Rtde
{
static void Main(string[] args)
{
/**/
var robot = new UR();
var param = new ConnectParameters("192.168.0.1");
// Enable RTDE
param.Rtde.Enable = true;
// Exchange data at 500Hz
param.Rtde.Frequency = 500;
// Select data you want to write in robot controller
param.Rtde.InputSetup.Add(RtdeInputData.StandardAnalogOutput0);
param.Rtde.InputSetup.Add(RtdeInputData.InputIntRegisters, 0);
// Select data you want the robot to send
param.Rtde.OutputSetup.Add(RtdeOutputData.ActualTcpPose);
param.Rtde.OutputSetup.Add(RtdeOutputData.ToolOutputVoltage);
param.Rtde.OutputSetup.Add(RtdeOutputData.OutputDoubleRegisters, 10);
// Connect to robot
robot.Connect(param);
// Be notified at 500Hz when data is received
robot.Rtde.OutputDataReceived += Rtde_OutputDataReceived;
//...
// Get last received data in cache
Pose actualTcpPose = robot.Rtde.OutputDataValues.ActualTcpPose;
int toolOutputVoltage = robot.Rtde.OutputDataValues.ToolOutputVoltage;
double outputDoubleRegisters10 = robot.Rtde.OutputDataValues.OutputDoubleRegisters.X10;
//...
// Write input values in robot
var inputValues = new RtdeInputValues();
inputValues.StandardAnalogOutput0 = 0.2;
inputValues.InputIntRegisters.X0 = 12;
robot.Rtde.WriteInputs(inputValues);
// Disconnect only RTDE communication
robot.Rtde.Disconnect();
/**/
}
/**/
private static void Rtde_OutputDataReceived(object sender, RtdeDataPackageEventArgs e)
{
// Get frequency of received message (OutputSetup contains Timestamp by default)
var realMessageFrequency = e.MeasuredFrequency;
// Get the value of the data you have selected in the setup
Pose actualTcpPose = e.OutputDataValues.ActualTcpPose;
int toolOutputVoltage = e.OutputDataValues.ToolOutputVoltage;
double outputDoubleRegisters10 = e.OutputDataValues.OutputDoubleRegisters.X10;
// Write inputs at 500Hz
var inputValues = new RtdeInputValues();
inputValues.StandardAnalogOutput0 = 0.5;
inputValues.InputIntRegisters.X0 = -10;
(sender as RtdeClientBase)?.WriteInputs(inputValues);
}
/**/
}