Starting a RAPID program from C# is `robot.Rws.Rapid.Start(...)`, and stopping it is `robot.Rws.Rapid.Stop(...)`. The call itself is one line. What takes the time is the state the controller has to be in before it accepts to start, and checking afterwards that the program really runs.

> **Available on** RWS 1.0 (IRC5) : yes | RWS 2.0 (OmniCore) : yes.

## What the controller needs before it starts

A start that fails with the HTTP status code 500 almost always means one of these is missing.

| Condition                  | How to get there                                                                 |
| -------------------------- | -------------------------------------------------------------------------------- |
| Automatic mode             | turn the key on the controller, `Panel.GetOperationMode()` tells you where it is |
| Motors on                  | `Panel.SetControllerState(ControllerState.MotorsOn)`                             |
| RAPID mastership           | `Mastership.Request(MastershipDomain.Rapid)`                                     |
| A program loaded and built | `Rapid.GetTask("T_ROB1").TaskState` is `Linked`                                  |
| A program pointer          | `Rapid.ResetProgramPointer()`, or move it where you want                         |

In manual mode a program can also be started, but the operator has to hold the enabling device of the teach pendant. A remote start in manual mode is refused as soon as they release it.

## Operation mode

The mode is set with the physical key, it cannot be changed over the network. What you can do is read it, and acknowledge a change the operator has requested.

**C# : PanelOperationMode**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class PanelOperationMode
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        OperationMode mode = robot.Rws.Panel.GetOperationMode();

        switch (mode)
        {
            case OperationMode.Automatic:
                Console.WriteLine("Automatic mode, a program can be started remotely");
                break;

            case OperationMode.ManualReducedSpeed:
            case OperationMode.ManualFullSpeed:
                Console.WriteLine("Manual mode, the operator holds the enabling device");
                break;

            case OperationMode.AutomaticChangeRequest:
                // The key was turned to automatic, the change waits for a confirmation
                robot.Rws.Panel.AcknowledgeOperationMode(OperationModeAcknowledgement.Automatic);
                break;

            case OperationMode.ManualFullSpeedChangeRequest:
                robot.Rws.Panel.AcknowledgeOperationMode(OperationModeAcknowledgement.ManualFullSpeed);
                break;
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : PanelOperationMode**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.operation_mode import OperationMode
from underautomation.abb.rws.data.operation_mode_acknowledgement import OperationModeAcknowledgement

robot = AbbController()
robot.connect("192.168.0.1")

##
mode = robot.rws.panel.get_operation_mode()

if mode == OperationMode.Automatic:
    print("Automatic mode, a program can be started remotely")
elif mode == OperationMode.ManualReducedSpeed or mode == OperationMode.ManualFullSpeed:
    print("Manual mode, the operator holds the enabling device")
elif mode == OperationMode.AutomaticChangeRequest:
    # The key was turned to automatic, the change waits for a confirmation
    robot.rws.panel.acknowledge_operation_mode(OperationModeAcknowledgement.Automatic)
elif mode == OperationMode.ManualFullSpeedChangeRequest:
    robot.rws.panel.acknowledge_operation_mode(OperationModeAcknowledgement.ManualFullSpeed)
##

robot.disconnect()
```

## Motors on

The state change is not immediate. Ask for it, then wait until the controller reports it.

**C# : PanelMotors**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class PanelMotors
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        ControllerState state = robot.Rws.Panel.GetControllerState();
        Console.WriteLine($"Controller state : {state}");

        if (state == ControllerState.MotorsOff)
        {
            // The robot can move once the motors are on
            robot.Rws.Panel.SetControllerState(ControllerState.MotorsOn);
        }

        // The state change is not immediate, wait for the controller to report it
        while (robot.Rws.Panel.GetControllerState() != ControllerState.MotorsOn)
        {
            Thread.Sleep(200);
        }
        /**/

        /**/
        // Motors off puts the robot back in standby, it cannot move any more
        robot.Rws.Panel.SetControllerState(ControllerState.MotorsOff);
        /**/

        robot.Disconnect();
    }
}
```

**Python : PanelMotors**
```python
import time

from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.controller_state import ControllerState

robot = AbbController()
robot.connect("192.168.0.1")

##
state = robot.rws.panel.get_controller_state()
print(f"Controller state : {state}")

if state == ControllerState.MotorsOff:
    # The robot can move once the motors are on
    robot.rws.panel.set_controller_state(ControllerState.MotorsOn)

# The state change is not immediate, wait for the controller to report it
while robot.rws.panel.get_controller_state() != ControllerState.MotorsOn:
    time.sleep(0.2)
##

##
# Motors off puts the robot back in standby, it cannot move any more
robot.rws.panel.set_controller_state(ControllerState.MotorsOff)
##

robot.disconnect()
```

## The program pointer

The program starts from where the program pointer stands, not from the beginning. `ResetProgramPointer()` puts the pointer of every task back on its entry point, usually `main`. To start somewhere else, move the pointer to a routine or to a position in the source.

**C# : RapidProgramPointer**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidProgramPointer
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Where the two pointers of the task stand
        RapidPointers pointers = robot.Rws.Rapid.GetPointers("T_ROB1");

        if (pointers.ProgramPointer.Available)
        {
            Console.WriteLine(pointers.ProgramPointer.Module + "/" + pointers.ProgramPointer.Routine);
            Console.WriteLine(pointers.ProgramPointer.BeginRow + "," + pointers.ProgramPointer.BeginColumn);
        }

        // The motion pointer is behind the program pointer, the controller plans the path
        // ahead of the movement. It is not available in a task that has not moved yet.
        Console.WriteLine(pointers.MotionPointer.Available);

        // The piece of source the program pointer covers. The controller refuses the request
        // when the task has no program pointer, reset it or start the program first.
        RapidProgramCounterPosition position = robot.Rws.Rapid.GetProgramCounterPosition("T_ROB1");
        Console.WriteLine(position.Module + " " + position.StartLine + "," + position.StartColumn);

        // Moving the pointer is a write, it needs the RAPID mastership
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // To the beginning of a routine. The module name is used by an IRC5 only,
            // an OmniCore looks the routine up in the whole task.
            robot.Rws.Rapid.SetProgramPointerToRoutine("T_ROB1", "MainModule", "main");

            // To a service routine, which has to be entered at user level
            robot.Rws.Rapid.SetProgramPointerToRoutineUrl("T_ROB1", "RAPID/T_ROB1/BASEFUN/LoadIdentify", true);

            // To one position of the source. The routine name is used by an IRC5 only,
            // an OmniCore works it out from the position itself.
            robot.Rws.Rapid.SetProgramPointerToCursor("T_ROB1", "MainModule", "main", 12, 1);

            // One instruction forward or backward, automatic mode only
            robot.Rws.Rapid.SetProgramPointerToNextInstruction("T_ROB1");
            robot.Rws.Rapid.SetProgramPointerToPreviousInstruction("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidProgramPointer**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
# Where the two pointers of the task stand
pointers = robot.rws.rapid.get_pointers("T_ROB1")

if pointers.program_pointer.available:
    print(pointers.program_pointer.module + "/" + pointers.program_pointer.routine)
    print(f"{pointers.program_pointer.begin_row},{pointers.program_pointer.begin_column}")

# The motion pointer is behind the program pointer, the controller plans the path
# ahead of the movement. It is not available in a task that has not moved yet.
print(pointers.motion_pointer.available)

# The piece of source the program pointer covers. The controller refuses the request
# when the task has no program pointer, reset it or start the program first.
position = robot.rws.rapid.get_program_counter_position("T_ROB1")
print(f"{position.module} {position.start_line},{position.start_column}")

# Moving the pointer is a write, it needs the RAPID mastership
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # To the beginning of a routine. The module name is used by an IRC5 only,
    # an OmniCore looks the routine up in the whole task.
    robot.rws.rapid.set_program_pointer_to_routine("T_ROB1", "MainModule", "main")

    # To a service routine, which has to be entered at user level
    robot.rws.rapid.set_program_pointer_to_routine_url("T_ROB1", "RAPID/T_ROB1/BASEFUN/LoadIdentify", True)

    # To one position of the source. The routine name is used by an IRC5 only,
    # an OmniCore works it out from the position itself.
    robot.rws.rapid.set_program_pointer_to_cursor("T_ROB1", "MainModule", "main", 12, 1)

    # One instruction forward or backward, automatic mode only
    robot.rws.rapid.set_program_pointer_to_next_instruction("T_ROB1")
    robot.rws.rapid.set_program_pointer_to_previous_instruction("T_ROB1")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

## Start

`Start` takes six arguments. The defaults suit a normal production start: resume the path, run continuously, forever, on the normal tasks only.

**C# : RapidStartProgram**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidStartProgram
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // 1. The controller has to be in automatic mode
        if (robot.Rws.Panel.GetOperationMode() != OperationMode.Automatic)
            throw new Exception("Turn the key of the controller to automatic mode");

        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // 2. Motors on
            robot.Rws.Panel.SetControllerState(ControllerState.MotorsOn);

            // 3. Program pointer back to the entry point of every task
            robot.Rws.Rapid.ResetProgramPointer();

            // 4. Start
            robot.Rws.Rapid.Start(RapidRegainMode.Continue,
                                  RapidExecutionMode.Continue,
                                  RapidExecutionCycle.Forever,
                                  RapidStartCondition.None,
                                  false,   // do not stop at breakpoints
                                  false);  // normal tasks only
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        // 5. Check that it really started, the call above only means the request was accepted
        RapidExecutionInfo execution = robot.Rws.Rapid.GetExecutionState();
        Console.WriteLine(execution.State);   // Running or Stopped
        Console.WriteLine(execution.Cycle);   // Forever, Once, OnceDone
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidStartProgram**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.controller_state import ControllerState
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.operation_mode import OperationMode
from underautomation.abb.rws.data.rapid_execution_cycle import RapidExecutionCycle
from underautomation.abb.rws.data.rapid_execution_mode import RapidExecutionMode
from underautomation.abb.rws.data.rapid_regain_mode import RapidRegainMode
from underautomation.abb.rws.data.rapid_start_condition import RapidStartCondition

robot = AbbController()
robot.connect("192.168.0.1")

##
# 1. The controller has to be in automatic mode
if robot.rws.panel.get_operation_mode() != OperationMode.Automatic:
    raise Exception("Turn the key of the controller to automatic mode")

robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # 2. Motors on
    robot.rws.panel.set_controller_state(ControllerState.MotorsOn)

    # 3. Program pointer back to the entry point of every task
    robot.rws.rapid.reset_program_pointer()

    # 4. Start
    robot.rws.rapid.start(RapidRegainMode.Continue_,
                          RapidExecutionMode.Continue_,
                          RapidExecutionCycle.Forever,
                          RapidStartCondition.None_,
                          False,   # do not stop at breakpoints
                          False)   # normal tasks only
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)

# 5. Check that it really started, the call above only means the request was accepted
execution = robot.rws.rapid.get_execution_state()
print(execution.state)  # Running or Stopped
print(execution.cycle)  # Forever, Once, OnceDone
##

robot.disconnect()
```

| Argument              | What it decides                                                                              |
| --------------------- | -------------------------------------------------------------------------------------------- |
| `regain`              | what the robot does about the distance between where it stands and where the path expects it |
| `executionMode`       | how far the program advances before stopping again, `Continue` or one of the step modes      |
| `cycle`               | `Forever`, or `Once` for a single cycle                                                      |
| `condition`           | `CallChain` makes the controller check the call chain before starting                        |
| `stopAtBreakpoint`    | whether execution stops on the breakpoints of the program                                    |
| `allTasksBySelection` | start every task enabled in the selection panel, not only the normal tasks                   |

## Check that it really started

`Start` returns as soon as the controller accepted the request. It does not mean the program runs: the controller can still refuse it, or stop it on the first error. Poll the execution state until it reports `Running`, with a timeout.

**C# : HowToWaitRapidStarted**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class HowToWaitRapidStarted
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Start returns as soon as the controller accepted the request. It does not mean the
        // program runs : the controller can still refuse it, or stop it on the first error.
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            robot.Rws.Rapid.Start(RapidRegainMode.Continue, RapidExecutionMode.Continue,
                                  RapidExecutionCycle.Forever, RapidStartCondition.None, false, false);
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        if (!WaitRunning(robot, 5000))
            throw new Exception("The program did not start, look at the event log of the controller");

        // The task that drives the robot has its own state, more precise than the global one
        RapidTaskInfo task = robot.Rws.Rapid.GetTask("T_ROB1");
        Console.WriteLine(task.ExecutionState);     // Started
        Console.WriteLine(task.ExecutionType);      // what kind of code is running now

        // Where the program pointer stands, so you can tell a running program from a blocked one
        RapidPointers pointers = robot.Rws.Rapid.GetPointers("T_ROB1");
        Console.WriteLine(pointers.ProgramPointer);
        /**/

        robot.Disconnect();
    }

    /**/
    // Polls the execution state until the program runs, or the timeout expires
    static bool WaitRunning(AbbController robot, int timeoutMs)
    {
        DateTime limit = DateTime.UtcNow.AddMilliseconds(timeoutMs);

        while (DateTime.UtcNow < limit)
        {
            if (robot.Rws.Rapid.GetExecutionState().State == RapidExecutionState.Running)
                return true;

            Thread.Sleep(200);
        }

        return false;
    }
    /**/
}
```

**Python : HowToWaitRapidStarted**
```python
import time

from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.rapid_execution_cycle import RapidExecutionCycle
from underautomation.abb.rws.data.rapid_execution_mode import RapidExecutionMode
from underautomation.abb.rws.data.rapid_execution_state import RapidExecutionState
from underautomation.abb.rws.data.rapid_regain_mode import RapidRegainMode
from underautomation.abb.rws.data.rapid_start_condition import RapidStartCondition

robot = AbbController()
robot.connect("192.168.0.1")


##
# Polls the execution state until the program runs, or the timeout expires
def wait_running(robot, timeout_ms):
    limit = time.time() + timeout_ms / 1000.0

    while time.time() < limit:
        if robot.rws.rapid.get_execution_state().state == RapidExecutionState.Running:
            return True

        time.sleep(0.2)

    return False
##


##
# start returns as soon as the controller accepted the request. It does not mean the
# program runs : the controller can still refuse it, or stop it on the first error.
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    robot.rws.rapid.start(RapidRegainMode.Continue_, RapidExecutionMode.Continue_,
                          RapidExecutionCycle.Forever, RapidStartCondition.None_, False, False)
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)

if not wait_running(robot, 5000):
    raise Exception("The program did not start, look at the event log of the controller")

# The task that drives the robot has its own state, more precise than the global one
task = robot.rws.rapid.get_task("T_ROB1")
print(task.execution_state)  # Started
print(task.execution_type)   # what kind of code is running now

# Where the program pointer stands, so you can tell a running program from a blocked one
pointers = robot.rws.rapid.get_pointers("T_ROB1")
print(pointers.program_pointer)
##

robot.disconnect()
```

`GetExecutionState()` covers the whole controller. `GetTask("T_ROB1")` is more precise, it gives the state, the execution level and the kind of code each task is running.

## Run once instead of forever

The number of cycles can also be set before starting, and read back per task.

**C# : RapidExecutionCycles**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidExecutionCycles
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // Only Once and Forever are accepted here
            robot.Rws.Rapid.SetExecutionCycle(RapidExecutionCycle.Once);

            // Start from the production entry point instead of the current program pointer
            robot.Rws.Rapid.StartFromProductionEntry();

            // Leave the routine that is running now and go back to the level below it.
            // This is how a trap or a service routine is abandoned without stopping the program under it.
            robot.Rws.Rapid.AbortExecutionLevel("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidExecutionCycles**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.rapid_execution_cycle import RapidExecutionCycle

robot = AbbController()
robot.connect("192.168.0.1")

##
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # Only Once and Forever are accepted here
    robot.rws.rapid.set_execution_cycle(RapidExecutionCycle.Once)

    # Start from the production entry point instead of the current program pointer
    robot.rws.rapid.start_from_production_entry()

    # Leave the routine that is running now and go back to the level below it.
    # This is how a trap or a service routine is abandoned without stopping the program under it.
    robot.rws.rapid.abort_execution_level("T_ROB1")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

## Stop

`Stop` takes a stop mode and a scope. Stopping needs no mastership.

**C# : RapidStopProgram**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidStopProgram
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Stop at the end of the current instruction, normal tasks only
        robot.Rws.Rapid.Stop(RapidStopMode.Stop, RapidTaskScope.Normal);

        // Let the robot finish the cycle it is in, then stop
        robot.Rws.Rapid.Stop(RapidStopMode.Cycle, RapidTaskScope.Normal);

        // Stop everything at once, including the static and semi static tasks
        robot.Rws.Rapid.Stop(RapidStopMode.QuickStop, RapidTaskScope.AllTasks);

        // Wait until the controller confirms the program is stopped
        while (robot.Rws.Rapid.GetExecutionState().State != RapidExecutionState.Stopped)
            System.Threading.Thread.Sleep(200);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidStopProgram**
```python
import time

from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.rapid_execution_state import RapidExecutionState
from underautomation.abb.rws.data.rapid_stop_mode import RapidStopMode
from underautomation.abb.rws.data.rapid_task_scope import RapidTaskScope

robot = AbbController()
robot.connect("192.168.0.1")

##
# Stop at the end of the current instruction, normal tasks only
robot.rws.rapid.stop(RapidStopMode.Stop, RapidTaskScope.Normal)

# Let the robot finish the cycle it is in, then stop
robot.rws.rapid.stop(RapidStopMode.Cycle, RapidTaskScope.Normal)

# Stop everything at once, including the static and semi static tasks
robot.rws.rapid.stop(RapidStopMode.QuickStop, RapidTaskScope.AllTasks)

# Wait until the controller confirms the program is stopped
while robot.rws.rapid.get_execution_state().state != RapidExecutionState.Stopped:
    time.sleep(0.2)
##

robot.disconnect()
```

| `RapidStopMode` | Effect                                     |
| --------------- | ------------------------------------------ |
| `Cycle`         | finish the current cycle, then stop        |
| `Instruction`   | finish the current instruction, then stop  |
| `Stop`          | stop at the end of the current instruction |
| `QuickStop`     | stop as fast as the program allows         |

`RapidTaskScope.Normal` stops the normal tasks. `AllTasks` also stops the static and semi static tasks, which usually run all the time and are not meant to be stopped by an application.

A stop is not an emergency stop. The emergency stop is a hardware circuit, it is not something an application on the network can trigger.

## Going further

- [RAPID tasks & program execution](/abb/documentation/rws-rapid-tasks), the complete reference
- [Control panel & operation mode](/abb/documentation/rws-panel)
- [Mastership](/abb/documentation/rws-mastership)
- [Read & write RAPID variables](/abb/documentation/read-write-rapid-variables), to pass parameters to the program before starting it

**Methods of RapidService**
```csharp
// Abandons the routine the task is currently running and returns to the level below it (synchronous) This is how a trap or a service routine started by hand is left without stopping the program underneath it.
void AbortExecutionLevel(string task);

// Gets whether the controller is executing RAPID code, and how many cycles it is set to run (synchronous)
RapidExecutionInfo GetExecutionState();

// Sets how many times the program runs before stopping (synchronous)
void SetExecutionCycle(RapidExecutionCycle cycle);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidExecutionInfo**
```csharp
public class RapidExecutionInfo {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidExecutionInfo" data-throw-if-not-resolved="false"></xref> class
    public RapidExecutionInfo()

    // Number of cycles the program is set to run
    public RapidExecutionCycle Cycle { get; set; }

    // Whether RAPID code is currently running
    public RapidExecutionState State { get; set; }

    // Returns a string representation of this execution state
    public override string ToString()
}
```

**Members of Rws.Data.RapidExecutionCycle**
```csharp
public enum RapidExecutionCycle {
    // The cycle currently configured is left untouched
    AsIs = 2

    // The program runs again every time it reaches its end
    Forever = 1

    // The program runs once and stops at its end
    Once = 3

    // The program was asked to run once and has finished doing so
    OnceDone = 4

    // The controller reported a cycle this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidStopMode**
```csharp
public enum RapidStopMode {
    // Stop when the current cycle ends
    Cycle = 0

    // Stop when the current instruction ends
    Instruction = 1

    // Stop as fast as the robot can, leaving the path
    QuickStop = 3

    // Stop as soon as the robot can decelerate along its path
    Stop = 2
}
```

**Members of Rws.Data.ControllerState**
```csharp
public enum ControllerState {
    // The robot is stopped because the emergency stop was activated
    EmergencyStop = 5

    // The robot is ready to leave the emergency stop state: the emergency stop is no longer activated,
    // but the state transition is not confirmed yet.
    EmergencyStopReset = 6

    // The robot is stopped because the safety runchain is opened, for instance because a door of its cell is open
    GuardStop = 4

    // The robot is starting up. It will shift to <xref href="UnderAutomation.ABB.Rws.Data.ControllerState.MotorsOff" data-throw-if-not-resolved="false"></xref> once it has started.
    Init = 1

    // The robot is in a standby state where there is no power to its motors.
    // The state has to be shifted to <xref href="UnderAutomation.ABB.Rws.Data.ControllerState.MotorsOn" data-throw-if-not-resolved="false"></xref> before the robot can move.
    MotorsOff = 2

    // The robot is ready to move, either by jogging or by running programs
    MotorsOn = 3

    // The robot is in a system failure state and requires a restart
    SystemFailure = 7

    // The state could not be determined
    Unknown = 0
}
```