With XML-RPC, a program that runs on a Universal Robots cobot calls a function of your application and uses its answer: a position computed by a vision system, a number, a text. This page shows how to answer these calls with the SDK. The SDK is the server: it listens on a port of the PC, 50000 by default.

## How it works

1. The robot program creates a connection to the PC with `rpc_factory`.
2. It calls a function of this connection. The robot waits for the answer.
3. The SDK raises `XmlRpcServerRequest` with the name of the function and its arguments. Your code sets `Answer`.
4. The robot assigns the answer to its variable, and the program continues.

URScript of the robot, where `192.168.0.10` is the address of the PC:

```ruby
rpc := rpc_factory("xmlrpc", "http://192.168.0.10:50000")

pose := rpc.get_pose()
text := rpc.say_hello("UR5e")
total := rpc.sum([1, 3.5, -2])
```

See [XML-RPC communication](https://www.universal-robots.com/articles/ur/interface-communication/xml-rpc-communication/) by Universal Robots. The address of the PC on the network of the robot is also in `robot.PrimaryInterface.LocalEndPoint`.

## Example

The XML-RPC server is disabled by default: set `XmlRpc.Enable` in `ConnectParameters`.

**C# : XmlRpc**
```csharp
using UnderAutomation.UniversalRobots;
using UnderAutomation.UniversalRobots.Common;
using UnderAutomation.UniversalRobots.XmlRpc;

class XmlRpc
{
  static void Main(string[] args)
  {
    /**/
    var robot = new UR();

    var parameters = new ConnectParameters("192.168.0.1");

    // The XML-RPC server is disabled by default
    parameters.XmlRpc.Enable = true;
    parameters.XmlRpc.Port = 50000;

    robot.Connect(parameters);

    // Raised for each call of the robot program
    robot.XmlRpc.XmlRpcServerRequest += OnRequest;
    /**/
  }

  /**/
  // The robot program connects with:
  //   rpc := rpc_factory("xmlrpc", "http://192.168.0.10:50000")
  // where 192.168.0.10 is the address of this PC
  static void OnRequest(object sender, XmlRpcEventArg request)
  {
    Console.WriteLine(request.EndPoint.Address + " calls " + request.MethodName);

    switch (request.MethodName)
    {
      // URScript: answer := rpc.get_pose()
      case "get_pose":
        request.Answer = new Pose(0.4, -0.1, 0.3, 0, 3.14, 0); // m and rad
        break;

      // URScript: answer := rpc.say_hello("UR5e")
      case "say_hello":
        request.Answer = "Hello " + request.Arguments[0];
        break;

      // URScript: answer := rpc.sum([1, 3.5, -2])
      case "sum":
        double[] values = request.Arguments[0];
        request.Answer = values.Sum();
        break;

      // Without an answer, the variable of the robot is not assigned
      default:
        break;
    }
  }
  /**/
}
```

**Python : XmlRpc**
```python
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.connect_parameters import ConnectParameters
from underautomation.universal_robots.common.pose import Pose
from underautomation.universal_robots.xml_rpc.xml_rpc_event_arg import XmlRpcEventArg
from underautomation.universal_robots.xml_rpc.xml_rpc_pose_value import XmlRpcPoseValue
from underautomation.universal_robots.xml_rpc.xml_rpc_string_value import XmlRpcStringValue

##
robot = UR()

parameters = ConnectParameters("192.168.0.1")

# The XML-RPC server is disabled by default
parameters.xml_rpc.enable = True
parameters.xml_rpc.port = 50000

robot.connect(parameters)

# The robot program connects with:
#   rpc := rpc_factory("xmlrpc", "http://192.168.0.10:50000")
# where 192.168.0.10 is the address of this PC
def on_request(sender, e):
    request = XmlRpcEventArg(e._instance)
    print(request.end_point, "calls", request.method_name)

    # URScript: answer := rpc.get_pose()
    if request.method_name == "get_pose":
        request.answer = XmlRpcPoseValue(Pose(0.4, -0.1, 0.3, 0, 3.14, 0))  # m and rad

    # URScript: answer := rpc.say_hello("UR5e")
    elif request.method_name == "say_hello":
        request.answer = XmlRpcStringValue("Hello " + str(request.arguments[0]))

    # Without an answer, the variable of the robot is not assigned

# Raised for each call of the robot program
robot.xml_rpc.xml_rpc_server_request(on_request)
##
```

The same server works without `UR`:

**C# : XmlRpcDirect**
```csharp
using UnderAutomation.UniversalRobots.XmlRpc;

class XmlRpcDirect
{
  static void Main(string[] args)
  {
    /**/
    // An XML-RPC server, without a UR instance
    var server = new XmlRpcServer();

    server.XmlRpcServerRequest += (sender, request) =>
    {
      if (request.MethodName == "get_counter")
        request.Answer = 42;
    };

    server.Start(50000);

    // ...

    server.Stop();
    /**/
  }
}
```

**Python : XmlRpcDirect**
```python
from underautomation.universal_robots.xml_rpc.xml_rpc_server import XmlRpcServer
from underautomation.universal_robots.xml_rpc.xml_rpc_event_arg import XmlRpcEventArg
from underautomation.universal_robots.xml_rpc.xml_rpc_integer_value import XmlRpcIntegerValue

##
# An XML-RPC server, without a UR instance
server = XmlRpcServer()

def on_request(sender, e):
    request = XmlRpcEventArg(e._instance)
    if request.method_name == "get_counter":
        request.answer = XmlRpcIntegerValue(42)

server.xml_rpc_server_request(on_request)

server.start(50000)

# ...

server.stop()
##
```

Allow the port of the server in the firewall of the PC.

## Values

`Answer` and `Arguments` are `XmlRpcValue`. In C#, implicit conversions accept and return the native types: `request.Answer = 12`, `= 3.5`, `= true`, `= "text"`, `= new Pose(...)`, `= new double[] {...}`, and `double[] values = request.Arguments[0]`.

| URScript type | .NET class            | Python class                                    |
| ------------- | --------------------- | ----------------------------------------------- |
| integer       | `XmlRpcIntegerValue`  | `XmlRpcIntegerValue(12)`                        |
| float         | `XmlRpcDoubleValue`   | `XmlRpcDoubleValue(3.5)`                        |
| boolean       | `XmlRpcBooleanValue`  | `XmlRpcBooleanValue(True)`                      |
| string        | `XmlRpcStringValue`   | `XmlRpcStringValue("text")`                     |
| pose          | `XmlRpcPoseValue`     | `XmlRpcPoseValue(Pose(x, y, z, rx, ry, rz))`    |
| array         | `XmlRpcArrayValue`    | `XmlRpcArrayValue`                              |
| struct        | `XmlRpcStructValue`   | `XmlRpcStructValue`                             |

A value that the SDK cannot read is an `XmlRpcUnknownValue`: its `AdditionalInformation` says why.

Without an answer, the function returns nothing to the robot and its variable is not assigned.

## Example programs

### PolyScope

[xml_rpc_sample.urp](https://github.com/underautomation/UniversalRobots.NET/raw/main/UnderAutomation.UniversalRobots.Showcase.Forms/Samples/xml_rpc_sample.urp) calls several functions. The demo application shows each call and lets you choose the answer.

![XML-RPC program in PolyScope](/universal-robots/xml_rpc_sample.jpg)

![Answer of the demo application](/universal-robots/xml_rpc_winforms.jpg)

### LabVIEW

The LabVIEW example answers `GetPose()` with the position of its front panel, and a text to the other functions:

![LabVIEW front panel](/universal-robots/xmlrpc_labview_frontpanel.jpg)

![LabVIEW diagram](/universal-robots/xmlrpc_labview_diagram.jpg)

![LabVIEW callback VI](/universal-robots/xmlrpc_labview_callback.jpg)

## Try it in the demo application

Everything on this page can be tried without writing code, in the **Remote procedure call (XML-RPC)** page of the [demo application](/universal-robots/documentation/demo-app).

![Remote procedure call (XML-RPC) page of the Universal Robots SDK demo application](/universal-robots/WinformsScreenshots/XmlRpc.jpg)

Its C# source is [XmlRpcControl.cs](https://github.com/underautomation/UniversalRobots.NET/blob/main/UnderAutomation.UniversalRobots.Showcase.Forms/Components/XmlRpcControl.cs).

## Reference

**Members of XmlRpc.XmlRpcEventArg**
```csharp
public class XmlRpcEventArg : EventArgs {
    // Response to be provided to the robot by the user
    public XmlRpcValue Answer

    // The arguments of the method called
    public readonly XmlRpcValue[] Arguments

    // IP address of the robot
    public readonly IPEndPoint EndPoint

    // The method called by the robot
    public readonly string MethodName

    // Returns a string describing the method name and argument count.
    public override string ToString()

    // The XML document received via HTTP
    public readonly XDocument XmlRequest
}
```

**Members of XmlRpc.XmlRpcValue**
```csharp
public abstract class XmlRpcValue {
    protected XmlRpcValue()

    // Returns the XML string representation of this value.
    public override string ToString()

    // Determines the class of this message
    public abstract XmlRpcType Type { get; }

    // The XML description of the message that has been received from the robot or will be sent to the robot
    public XElement Xml { get; }

    // Implicitly converts a <xref href="System.Boolean" data-throw-if-not-resolved="false"></xref> to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcBooleanValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(bool value)

    // Implicitly converts a <xref href="System.Boolean" data-throw-if-not-resolved="false"></xref> array to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcArrayValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(bool[] value)

    // Implicitly converts a <xref href="System.Double" data-throw-if-not-resolved="false"></xref> to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcDoubleValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(double value)

    // Implicitly converts a <xref href="System.Double" data-throw-if-not-resolved="false"></xref> array to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcArrayValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(double[] value)

    // Implicitly converts an <xref href="System.Int32" data-throw-if-not-resolved="false"></xref> to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcIntegerValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(int value)

    // Implicitly converts an <xref href="System.Int32" data-throw-if-not-resolved="false"></xref> array to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcArrayValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(int[] value)

    // Implicitly converts a <xref href="System.String" data-throw-if-not-resolved="false"></xref> to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcStringValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(string value)

    // Implicitly converts a <xref href="System.String" data-throw-if-not-resolved="false"></xref> array to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcArrayValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(string[] value)

    // Implicitly converts a <xref href="UnderAutomation.UniversalRobots.Common.Pose" data-throw-if-not-resolved="false"></xref> to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcPoseValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(Pose value)

    // Implicitly converts a <xref href="UnderAutomation.UniversalRobots.Common.Pose" data-throw-if-not-resolved="false"></xref> array to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcArrayValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(Pose[] value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="System.Boolean" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator bool(XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="System.Boolean" data-throw-if-not-resolved="false"></xref> array.
    public static implicit operator bool[](XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="System.Double" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator double(XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="System.Double" data-throw-if-not-resolved="false"></xref> array.
    public static implicit operator double[](XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to an <xref href="System.Int32" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator int(XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to an <xref href="System.Int32" data-throw-if-not-resolved="false"></xref> array.
    public static implicit operator int[](XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="System.String" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator string(XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="System.String" data-throw-if-not-resolved="false"></xref> array.
    public static implicit operator string[](XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="UnderAutomation.UniversalRobots.Common.Pose" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator Pose(XmlRpcValue value)

    // Implicitly converts an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to a <xref href="UnderAutomation.UniversalRobots.Common.Pose" data-throw-if-not-resolved="false"></xref> array.
    public static implicit operator Pose[](XmlRpcValue value)

    // Implicitly converts an array of <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcValue" data-throw-if-not-resolved="false"></xref> to an <xref href="UnderAutomation.UniversalRobots.XmlRpc.XmlRpcArrayValue" data-throw-if-not-resolved="false"></xref>.
    public static implicit operator XmlRpcValue(XmlRpcValue[] value)
}
```

## What to read next

- [Socket communication](/universal-robots/documentation/socket-communication): exchange your own messages with the robot program.
- [Read and write registers](/universal-robots/documentation/registers): exchange numbers with the robot program, without waiting.