This page explains how to connect the SDK to a Staubli CS8 or CS9 controller: the settings of the controller, the connection parameters, the errors and the disconnection. The SDK uses the SOAP server of the controller over TCP/IP. Nothing is installed on the controller.

## Prerequisites

- The PC reaches the controller on the network. Its address is shown in the network settings of the controller, on the pendant.
- The SOAP server of the controller answers on its port, 851 by default. Staubli Robotics Suite uses the same server: if Staubli Robotics Suite connects to the controller, the SDK can connect too.
- A user of the controller, with its password. The rights of this user limit what the SDK can do, as for a person on the pendant.
- To power the arm and move it, the controller must be in remote mode.

## Quick connection

Pass the address of the controller. The other parameters keep their default values.

**C# : ConnectQuick**
```csharp
using UnderAutomation.Staubli;

public class ConnectQuick
{
    static void Main()
    {
        /**/
        var controller = new StaubliController();

        // Default parameters: SOAP port 851, user "default", password "default"
        controller.Connect("192.168.0.254");

        bool connected = controller.Enabled;
        /**/

        controller.Disconnect();
    }
}
```

**Python : ConnectQuick**
```python
from underautomation.staubli.staubli_controller import StaubliController

##
controller = StaubliController()

# Default parameters: SOAP port 851, user "default", password "default"
controller.connect("192.168.0.254")

connected = controller.enabled
##

controller.disconnect()
```

**Matlab : ConnectQuick**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.Staubli.dll'));
import UnderAutomation.Staubli.*

%%
controller = StaubliController();

% Default parameters: SOAP port 851, user "default", password "default"
controller.Connect('192.168.0.254');

connected = controller.Enabled;
%%

controller.Disconnect();
```

`StaubliController` gives access to every function of the SDK, through its `Soap` property.

## Connection parameters

`ConnectionParameters` holds every option. Use it when the controller has another port, user or password.

**C# : Connect**
```csharp
using UnderAutomation.Staubli;
using UnderAutomation.Staubli.Common;

public class Connect
{
    static void Main()
    {
        /**/
        var parameters = new ConnectionParameters("192.168.0.254");

        // Ping the controller first, so an unreachable controller fails in 100 ms
        parameters.PingBeforeConnect = true;

        parameters.Soap.Enable = true;
        parameters.Soap.Port = SoapConnectParameters.DEFAULT_PORT; // 851
        parameters.Soap.User = "default";
        parameters.Soap.Password = "default";

        var controller = new StaubliController();
        controller.Connect(parameters);
        /**/

        controller.Disconnect();
    }
}
```

**Python : Connect**
```python
from underautomation.staubli.staubli_controller import StaubliController
from underautomation.staubli.connection_parameters import ConnectionParameters
from underautomation.staubli.common.soap_connect_parameters import SoapConnectParameters

##
parameters = ConnectionParameters("192.168.0.254")

# Ping the controller first, so an unreachable controller fails in 100 ms
parameters.ping_before_connect = True

parameters.soap.enable = True
parameters.soap.port = SoapConnectParameters.DEFAULT_PORT  # 851
parameters.soap.user = "default"
parameters.soap.password = "default"

controller = StaubliController()
controller.connect(parameters)
##

controller.disconnect()
```

**Matlab : Connect**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.Staubli.dll'));
import UnderAutomation.Staubli.*

%%
parameters = ConnectionParameters('192.168.0.254');

% Ping the controller first, so an unreachable controller fails in 100 ms
parameters.PingBeforeConnect = true;

parameters.Soap.Enable = true;
parameters.Soap.Port = 851;
parameters.Soap.User = 'default';
parameters.Soap.Password = 'default';

controller = StaubliController();
controller.Connect(parameters);
%%

controller.Disconnect();
```

| Parameter           | Default     | Meaning                                                                 |
| ------------------- | ----------- | ----------------------------------------------------------------------- |
| `Address`           | none        | IP address or host name of the controller                               |
| `PingBeforeConnect` | `true`      | Send a ping first. The connection fails if there is no answer in 100 ms |
| `Soap.Enable`       | `true`      | Open the SOAP session                                                   |
| `Soap.Port`         | `851`       | TCP port of the SOAP server (`SoapConnectParameters.DEFAULT_PORT`)      |
| `Soap.User`         | `"default"` | User of the controller                                                  |
| `Soap.Password`     | `"default"` | Password of this user                                                   |

Set `PingBeforeConnect` to `false` when a firewall blocks ICMP between the PC and the controller.

The address `localhost` is replaced by `127.0.0.1`, to avoid a slow name resolution.

## One controller, several robots

A controller can drive more than one arm. The methods that concern an arm take a `robot` argument: `0` is the first robot of `GetRobots()`. With one arm, always pass `0`. See [Controller and robots](/staubli/documentation/soap-controller).

## Standalone SOAP client

`SoapClient` opens a SOAP session without `StaubliController`. The methods are then directly on the client: `soap.GetRobots()` instead of `controller.Soap.GetRobots()`.

**C# : ConnectStandalone**
```csharp
using UnderAutomation.Staubli.Common;
using UnderAutomation.Staubli.Soap;

public class ConnectStandalone
{
    static void Main()
    {
        /**/
        // A SOAP client without StaubliController
        var soap = new SoapClient();
        soap.Connect("192.168.0.254", "default", "default", SoapConnectParameters.DEFAULT_PORT);

        // The services are directly on the client
        double[] joints = soap.GetCurrentJointPosition(robot: 0);

        soap.Disconnect();
        /**/
    }
}
```

**Python : ConnectStandalone**
```python
from underautomation.staubli.soap.soap_client import SoapClient
from underautomation.staubli.common.soap_connect_parameters import SoapConnectParameters

##
# A SOAP client without StaubliController
soap = SoapClient()
soap.connect("192.168.0.254", "default", "default", SoapConnectParameters.DEFAULT_PORT)

# The services are directly on the client
joints = soap.get_current_joint_position(0)

soap.disconnect()
##
```

## Errors

**C# : ConnectErrors**
```csharp
using System.Net;
using UnderAutomation.Staubli;
using UnderAutomation.Staubli.License;
using UnderAutomation.Staubli.Soap.Errors;

public class ConnectErrors
{
    static void Main()
    {
        var controller = new StaubliController();

        /**/
        try
        {
            controller.Connect("192.168.0.254");
            controller.Soap.TaskKill("myTask", "Disk://myProject/myProject.pjx");
        }
        catch (InvalidLicenseException ex)
        {
            // No valid license: the trial is over, or the key is wrong
            Console.WriteLine(ex.LicenseInfo);
        }
        catch (CustomSoapException ex) when (ex.ErrorCode == SoapErrorCode.InvalidCredentials)
        {
            Console.WriteLine("Wrong user or password");
        }
        catch (CustomSoapException ex)
        {
            // The controller refused the request
            Console.WriteLine($"{ex.ErrorCode} : {ex.Description}");
        }
        catch (WebException ex)
        {
            // No answer on the SOAP port
            Console.WriteLine(ex.Message);
        }
        catch (Exception ex)
        {
            // For example, no answer to the ping
            Console.WriteLine(ex.Message);
        }
        /**/
    }
}
```

**Python : ConnectErrors**
```python
from underautomation.staubli.staubli_controller import StaubliController
from UnderAutomation.Staubli.License import InvalidLicenseException
from UnderAutomation.Staubli.Soap.Errors import CustomSoapException, SoapErrorCode
from System.Net import WebException

controller = StaubliController()

##
# The exceptions come from the .NET runtime, so their members keep their original names
try:
    controller.connect("192.168.0.254")
    controller.soap.task_kill("myTask", "Disk://myProject/myProject.pjx")
except InvalidLicenseException as ex:
    # No valid license: the trial is over, or the key is wrong
    print(ex.LicenseInfo)
except CustomSoapException as ex:
    if ex.ErrorCode == SoapErrorCode.InvalidCredentials:
        print("Wrong user or password")
    else:
        # The controller refused the request
        print(f"{ex.ErrorCode} : {ex.Description}")
except WebException as ex:
    # No answer on the SOAP port
    print(ex.Message)
except Exception as ex:
    # For example, no answer to the ping
    print(ex)
##
```

| Exception                   | When                                                                                                       |
| --------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `InvalidLicenseException`   | `Connect` is called without a valid license. See [Licensing](/staubli/documentation/license)               |
| `CustomSoapException`       | The controller refused the request. `ErrorCode` gives the reason, `Description` the text of the controller |
| `WebException`              | No answer on the SOAP port, or a network error                                                             |
| `InvalidOperationException` | A method is called before `Connect`, or after `Disconnect`                                                 |
| `Exception`                 | No answer to the ping                                                                                      |

Frequent values of `CustomSoapException.ErrorCode`:

| `SoapErrorCode`        | Meaning                                                      |
| ---------------------- | ------------------------------------------------------------ |
| `InvalidCredentials`   | Wrong user or password                                       |
| `InvalidSessionIdCode` | The session has expired: connect again                       |
| `InvalidRobotIdCode`   | The `robot` argument does not match a robot of `GetRobots()` |
| `WriteAccessErrorCode` | The user has no right to change this                         |
| `ApplicationNotFound`  | No VAL 3 application with this name                          |
| `TaskNotFound`         | No task with this name and this creator                      |

## Disconnect

`Disconnect` closes the session on the controller. Call it when your application ends, or when it no longer needs the controller.

**C# : ConnectDisconnect**
```csharp
using UnderAutomation.Staubli;

public class ConnectDisconnect
{
    static void Main()
    {
        var controller = new StaubliController();
        controller.Connect("192.168.0.254");

        /**/
        try
        {
            double[] joints = controller.Soap.GetCurrentJointPosition(robot: 0);
        }
        finally
        {
            // Close the session on the controller
            controller.Disconnect();
        }
        /**/
    }
}
```

**Python : ConnectDisconnect**
```python
from underautomation.staubli.staubli_controller import StaubliController

controller = StaubliController()
controller.connect("192.168.0.254")

##
try:
    joints = controller.soap.get_current_joint_position(0)
finally:
    # Close the session on the controller
    controller.disconnect()
##
```

`Enabled` is `true` while the session is open.

## Try it in the demo application

Everything on this page can be tried without writing code, in the **Connection** page of the [demo application](/abb/documentation/demo-app).

![Connection page of the ABB SDK demo application](/abb/WinformsScreenshots/Connect.jpg)

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

## Reference

**Members of ConnectionParameters**
```csharp
public class ConnectionParameters {
    // Instanciate a new connection parameters
    public ConnectionParameters()

    // Instanciate a new connection parameters with a specified address
    public ConnectionParameters(string address)

    // Address of the robot (IP or host name)
    public string Address { get; set; }

    public override bool Equals(object obj)

    public override int GetHashCode()

    // Send a ping command before initializing any connections
    public bool PingBeforeConnect { get; set; }

    // Soap connection parameters
    public SoapConnectParameters Soap { get; set; }

    public override string ToString()
}
```

**Members of Common.SoapConnectParameters**
```csharp
public class SoapConnectParameters : SoapConnectParametersBase {
    public SoapConnectParameters()

    // Default port for SOAP service
    public const int DEFAULT_PORT = 851

    // Should use this service (default: true)
    public bool Enable { get; set; }
}
```

**Members of Soap.Internal.SoapConnectParametersBase**
```csharp
public class SoapConnectParametersBase {
    public SoapConnectParametersBase()

    // Password for the SOAP service (default: default)
    public string Password { get; set; }

    // Port of the SOAP service (default: 851)
    public int Port { get; set; }

    // Username for the SOAP service (default: default)
    public string User { get; set; }
}
```

**Members of Soap.Errors.CustomSoapException**
```csharp
public class CustomSoapException : Exception, ISerializable {
    // A human-readable description of the error, providing additional context about the failure.
    public string Description { get; }

    // The error code as an enum value, parsed from the ErrorCodeText.
    public SoapErrorCode ErrorCode { get; }

    // The error code text as received from the SOAP response, formatted as a kebab-case string.
    public string ErrorCodeText { get; }

    // Gets the error message that describes the current exception.
    public override string Message { get; }
}
```

**Members of Soap.Errors.SoapErrorCode**
```csharp
public enum SoapErrorCode {
    // The specified application was not found.
    ApplicationNotFound = 7

    // Cannot start the application.
    CannotStartApplication = 14

    // A client is already connected.
    ClientAlreadyConnected = 15

    // Client communication error.
    ClientCommunicationError = 17

    // The provided credentials are invalid.
    InvalidCredentials = 0

    // The specified robot ID is invalid.
    InvalidRobotIdCode = 20

    // The session ID is invalid or expired.
    InvalidSessionIdCode = 12

    // I/O write access error.
    IoWriteAccessErrorCode = 16

    // I/O write access validation error.
    IoWriteAccessErrorValidation = 18

    // I/O write access error due to working mode.
    IoWriteAccessErrorWorkingMode = 19

    // Mismatched code error.
    MismatchedCode = 2

    // The specified program line was not found.
    ProgramLineNotFound = 9

    // The specified program was not found.
    ProgramNotFound = 3

    // Read access error.
    ReadAccessErrorCode = 10

    // Scheduling mode error.
    SchedulingModeError = 6

    // Cannot set position outside simulation mode.
    SetPosNotSimulCode = 11

    // SIN return code indicates failure.
    SinReturnCodeNok = 5

    // The specified stack frame was not found.
    StackFrameNotFound = 8

    // The task is already locked by another client.
    TaskAlreadyLocked = 4

    // The specified task was not found.
    TaskNotFound = 1

    // Unknown or unrecognized error code.
    Unknown = -1

    // Write access error.
    WriteAccessErrorCode = 13
}
```