`robot.Rws.Rapid` is the service of the program the robot runs. This page covers the tasks the program is split into, starting and stopping the execution, and moving the program pointer. The variables of the program are on [RAPID variables & symbols](/abb/documentation/rws-rapid-symbols), the source of the modules on [RAPID modules & program files](/abb/documentation/rws-rapid-modules).

Reading never needs anything special. Every write of this page needs the `Rapid` [mastership](/abb/documentation/rws-mastership), and most of them also need the controller to be in the right operation mode. None of these resources answers while the controller runs in boot mode.

## Tasks

A controller runs one RAPID task per robot, plus the background tasks the system needs. `GetTasks` lists them all, `GetTask` returns everything the controller knows about one of them.

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

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

        /**/
        // Every RAPID task of the controller
        foreach (RapidTaskItem task in robot.Rws.Rapid.GetTasks())
        {
            Console.WriteLine(task.Name);                 // T_ROB1
            Console.WriteLine(task.Type);                 // Normal, Static or SemiStatic
            Console.WriteLine(task.TaskState);            // Linked when the program is ready to run
            Console.WriteLine(task.ExecutionState);       // Started, Stopped, Ready
            Console.WriteLine(task.Active);               // null when the controller did not report it
            Console.WriteLine(task.MotionTask);           // true for the task that drives the robot
        }

        // Everything the controller knows about one task
        RapidTaskInfo info = robot.Rws.Rapid.GetTask("T_ROB1");
        Console.WriteLine(info.ExecutionLevel);           // Normal, Trap, User, None
        Console.WriteLine(info.ExecutionCycle);           // Forever, Once, OnceDone
        Console.WriteLine(info.ExecutionMode);            // Continuous, StepIn, StepOver, ...
        Console.WriteLine(info.ProductionEntryPoint);
        Console.WriteLine(info.Trust);
        /**/

        robot.Disconnect();
    }
}
```

| `RapidTaskType` | What the task is                                                        |
| --------------- | ----------------------------------------------------------------------- |
| `Normal`        | A task holding a program an operator starts and stops                   |
| `Static`        | A task started with the controller and never stopped                    |
| `SemiStatic`    | A task started with the controller and restarted at every program reset |
| `Unknown`       | The controller reported a type the SDK does not know                    |

`TaskState` says whether the task can run. Only `Linked` means that the modules of the task were turned into a runnable program. `Empty` means the task holds nothing, `Loaded` that the modules are there but not linked yet.

| `RapidTaskExecutionState` | Meaning                                     |
| ------------------------- | ------------------------------------------- |
| `Ready`                   | The task is ready to run but is not running |
| `Started`                 | The task is running                         |
| `Stopped`                 | The task was stopped before its end         |
| `Uninitialized`           | The task is not usable yet                  |

### Activate and deactivate a task

A deactivated task is not started when the program starts. The selection panel of the FlexPendant shows the same thing, `GetTaskSelection` reads it. `UserModify` says whether an operator is allowed to change the selection of that task from the pendant.

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

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

        /**/
        // Which tasks the operator panel has selected, and which of them an operator may change
        foreach (RapidTaskSelectionItem item in robot.Rws.Rapid.GetTaskSelection())
        {
            Console.WriteLine(item.Name + " selected=" + item.Selected + " userModify=" + item.UserModify);
        }

        // Activating or deactivating a task is a write, so it needs the mastership
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            robot.Rws.Rapid.ActivateTask("T_ROB1");
            robot.Rws.Rapid.DeactivateTask("T_ROB2");

            // Same thing for every task at once
            robot.Rws.Rapid.ActivateTasks();
            robot.Rws.Rapid.DeactivateTasks();
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

`GetTaskProgramPointerSyncState` and `GetTaskMotionPointerSyncState`, listed below, are described in the program pointer section of this page.



















## Build a task

`BuildTask` links the modules a task holds into a runnable program. The controller accepts the request even when the program does not compile, so read `GetBuildErrors` afterwards and check that the task state became `Linked`.

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

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

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // Link the modules of the task into a runnable program
            robot.Rws.Rapid.BuildTask("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        // The controller does not fail the build request, it reports what it refused afterwards
        foreach (RapidBuildError error in robot.Rws.Rapid.GetBuildErrors("T_ROB1"))
        {
            Console.WriteLine(error.ModuleName + " " + error.Row + "," + error.Column + ": " + error.Error);
        }

        // The task is runnable when its state is Linked
        Console.WriteLine(robot.Rws.Rapid.GetTask("T_ROB1").TaskState);
        /**/

        robot.Disconnect();
    }
}
```

The build errors are described in [RAPID modules & program files](/abb/documentation/rws-rapid-modules).



## Load a module

> **Available on** RWS 1.0 (IRC5) : yes | RWS 2.0 (OmniCore) : yes. Only an OmniCore answers with the name of the module that was loaded, an IRC5 returns null.

`LoadModule` loads one module file into a task. The file has to be on the file system of the controller already, so upload it first with the [file system service](/abb/documentation/rws-files). Set `replace` to `true` when a module of the same name is already loaded, otherwise the controller refuses the request.

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

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

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // The file has to be on the controller already. Upload it first with robot.Rws.File.
            // On OmniCore the call answers the name of what was loaded, on IRC5 it answers null.
            string loaded = robot.Rws.Rapid.LoadModule("T_ROB1", "$HOME/mymodule.mod", true);
            Console.WriteLine(loaded);

            robot.Rws.Rapid.UnloadModule("T_ROB1", "mymodule");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

`UnloadModule` takes the name of the module, not the name of the file. A module that was never saved is lost when it is unloaded.

Loading a whole program instead of one module is done with `LoadProgram`, see [RAPID modules & program files](/abb/documentation/rws-rapid-modules).



## Start and stop the program

Starting a program from your application fails when one of these conditions is not met:

1. The controller is in automatic mode, or in manual mode with the enabling device held. The mode is read with the [control panel service](/abb/documentation/rws-panel).
2. The motors are on, `Panel.SetControllerState(ControllerState.MotorsOn)`.
3. The task is active and its state is `Linked`.
4. The program pointer is set, which `ResetProgramPointer` does for every task.
5. Your connection holds the `Rapid` [mastership](/abb/documentation/rws-mastership).

**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();
    }
}
```

`Start` returns as soon as the controller accepts the request, not when the robot moves. Read `GetExecutionState` afterwards to know what really happened.

| `RapidRegainMode` | What the robot does when execution resumes                       |
| ----------------- | ---------------------------------------------------------------- |
| `Continue`        | Resume from the current position, without going back to the path |
| `Regain`          | Move back onto the path first                                    |
| `Clear`           | Drop the path and resume from the current position               |
| `EnterConsume`    | Resume by entering the path already computed                     |

| `RapidExecutionMode` | How far the program advances                                             |
| -------------------- | ------------------------------------------------------------------------ |
| `Continue`           | Run until something stops it                                             |
| `StepIn`             | Enter the routine called by the current instruction                      |
| `StepOver`           | Run the current instruction whole, without entering the routine it calls |
| `StepOut`            | Run until the current routine returns                                    |
| `StepBack`           | Step one instruction backwards                                           |
| `StepLast`           | Step to the last instruction                                             |
| `StepMotion`         | Step to the next motion instruction                                      |

`RapidStartCondition.CallChain` asks the controller to start only when the call chain of the program pointer is still valid, which is a way to refuse a start after the source was edited.

### Cycles and entry point

`SetExecutionCycle` takes `Once` or `Forever`, the other values of the enum are only reported by the controller. `StartFromProductionEntry` starts at the production entry point of the task instead of the current program pointer.

`AbortExecutionLevel` leaves the routine running now and goes back to the level under it. This is how a trap or a service routine started by hand is abandoned without stopping the program below it.

**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();
    }
}
```

### Stop

**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();
    }
}
```

| `RapidStopMode` | How the program stops                              |
| --------------- | -------------------------------------------------- |
| `Cycle`         | At the end of the current cycle                    |
| `Instruction`   | At the end of the current instruction              |
| `Stop`          | As soon as the robot can decelerate along its path |
| `QuickStop`     | As fast as the robot can, leaving the path         |

`RapidTaskScope.Normal` stops the normal tasks only, `AllTasks` also stops the static and semi static ones. `Stop` returns before the robot has stopped, so wait until `GetExecutionState` reports `Stopped`.

### Hold-to-run

In manual mode the program only runs while a client keeps saying that the hold-to-run control is held. Send `Press`, then `Held` about every two seconds. The controller stops the program as soon as it stops hearing from your application.

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

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

        /**/
        // Manual mode only. Press, then keep sending Held, the controller stops the
        // program as soon as it stops hearing from your application.
        robot.Rws.Rapid.SetHoldToRun(RapidHoldToRunState.Press);

        robot.Rws.Rapid.Start(RapidRegainMode.Continue, RapidExecutionMode.Continue);

        for (int i = 0; i < 10; i++)
        {
            robot.Rws.Rapid.SetHoldToRun(RapidHoldToRunState.Held);
            System.Threading.Thread.Sleep(1000);
        }

        robot.Rws.Rapid.SetHoldToRun(RapidHoldToRunState.Release);
        /**/

        robot.Disconnect();
    }
}
```

This is only honoured by a virtual controller, and only for a client the controller considers local. A real cabinet expects the physical device.

A complete example, with the checks around it, is given in [Start & stop a RAPID program](/abb/documentation/start-stop-rapid-program).





















## Execution trace

The controller can write every instruction it runs into a file. It is the fastest way to find out why a program took a branch it should not have. The two calls take the mastership by themselves, your code does not have to.

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

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

        /**/
        // The trace names every instruction the controller runs. No mastership needed,
        // the controller takes it by itself for these two calls.
        robot.Rws.Rapid.StartSpy("$HOME/trace.log");

        Console.WriteLine(robot.Rws.Rapid.GetSpyStatus());   // Logging or NotLogging

        System.Threading.Thread.Sleep(5000);

        robot.Rws.Rapid.StopSpy();

        // Then download the file with the file service
        string trace = robot.Rws.File.GetFileAsText("$HOME/trace.log");
        Console.WriteLine(trace);
        /**/

        robot.Disconnect();
    }
}
```

The file is written on the controller, download it afterwards with the [file system service](/abb/documentation/rws-files). A trace grows fast, do not leave it running.





## Program pointer and motion pointer

Each task has two pointers. The program pointer says which instruction runs next, the motion pointer which one the robot is really executing. They drift apart because the controller plans the path ahead of the movement.

**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();
    }
}
```

> **Available on** RWS 1.0 (IRC5) : yes | RWS 2.0 (OmniCore) : yes. An IRC5 needs the module and the routine name, an OmniCore works them out from the position alone.

`SetProgramPointerToRoutine` takes a module name and `SetProgramPointerToCursor` a routine name. An IRC5 refuses the request without them, an OmniCore ignores them and finds the routine by itself. Pass them in both cases, your code then works on the two generations.

A few things to know before moving the pointer:

- Moving the pointer needs the `Rapid` [mastership](/abb/documentation/rws-mastership), and the program has to be stopped.
- `SetProgramPointerToNextInstruction` and `SetProgramPointerToPreviousInstruction` are refused outside automatic mode.
- A service routine has to be entered at user level, so pass `true` for `userLevel`. `GetServiceRoutines` gives the paths `SetProgramPointerToRoutineUrl` takes.
- `GetProgramCounterPosition` is refused when the task has no program pointer at all. Reset it or start the program first.
- `GetProgram` returns the name of the program the task holds and the routine `ResetProgramPointer` goes back to.

### Synchronization and change counters

`GetProgramPointerSyncState` and `GetMotionPointerSyncState` say whether the pointers of the tasks are synchronized with each other, for the whole controller or for one task. `GetStructuralChangeCount` returns two counters that only move when something changed in the task, which is cheaper than downloading the modules again to find out that nothing moved.

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

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

        /**/
        // For the whole controller
        RapidPointerSyncState program = robot.Rws.Rapid.GetProgramPointerSyncState();
        RapidPointerSyncState motion = robot.Rws.Rapid.GetMotionPointerSyncState();
        Console.WriteLine(program + " / " + motion);   // On or Off

        // For one task
        Console.WriteLine(robot.Rws.Rapid.GetTaskProgramPointerSyncState("T_ROB1"));
        Console.WriteLine(robot.Rws.Rapid.GetTaskMotionPointerSyncState("T_ROB1"));

        // Two counters that say whether anything changed in the task, cheaper than
        // downloading the modules again to find out that nothing moved
        RapidStructuralChangeCount counters = robot.Rws.Rapid.GetStructuralChangeCount("T_ROB1");
        Console.WriteLine(counters.ChangeCount);
        Console.WriteLine(counters.StructuralChangeCount);
        /**/

        robot.Disconnect();
    }
}
```















## Call stack

`GetActivationRecord` reads one frame of the call stack. Frame 1 holds the program pointer, and the number grows towards the entry point of the program. The controller refuses the request when the task has no program pointer, or when the stack is not that deep.

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

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

        /**/
        // Frame 1 is the one holding the program pointer, the number grows towards the entry point
        for (int frame = 1; frame <= 5; frame++)
        {
            RapidActivationRecord record = robot.Rws.Rapid.GetActivationRecord("T_ROB1", frame);

            Console.WriteLine(record.RoutineUrl);
            Console.WriteLine(record.BeginRow + "," + record.BeginColumn);
            Console.WriteLine(record.ExecutionLevel);
        }

        // The routines the program pointer may be moved to, service routines included
        foreach (RapidServiceRoutineItem routine in robot.Rws.Rapid.GetServiceRoutines("T_ROB1"))
        {
            Console.WriteLine(routine.Name + " -> " + routine.Url + " service=" + routine.IsServiceRoutine);
        }
        /**/

        robot.Disconnect();
    }
}
```

| `RapidExecutionLevel` | Where execution stands                                  |
| --------------------- | ------------------------------------------------------- |
| `Normal`              | In the program itself                                   |
| `Trap`                | In a trap routine                                       |
| `User`                | In a routine started by hand, such as a service routine |
| `None`                | Nothing is running at this level                        |
| `Unknown`             | The controller reported a level the SDK does not know   |









## Answer an operator dialogue

A RAPID program can stop and ask the operator something. The controller then reports one pending instruction, and the program waits until it is answered. `GetActiveUiInstruction` returns `null` when nothing is pending.

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

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

        /**/
        // Null when the program is not asking the operator for anything right now
        RapidUiInstruction question = robot.Rws.Rapid.GetActiveUiInstruction();

        if (question != null)
        {
            Console.WriteLine(question.Instruction);   // name of the RAPID instruction waiting
            Console.WriteLine(question.Message);
            Console.WriteLine(question.Event);         // Send, Post or Abort

            // What the program passed in, and what it is waiting for. The names of the
            // parameters depend on the instruction, so read them before writing one.
            foreach (RapidUiInstructionParameter parameter in
                     robot.Rws.Rapid.GetUiInstructionParameters(question.StackUrl))
            {
                Console.WriteLine(parameter.Name + " = " + parameter.Value);
            }

            // Answering is a write, so it needs the mastership
            robot.Rws.Mastership.Request(MastershipDomain.Rapid);
            try
            {
                // Write the parameter carrying the answer, then the one marking it as completed
                robot.Rws.Rapid.SetUiInstructionParameter(question.StackUrl, "TPCompleted", "TRUE");
            }
            finally
            {
                robot.Rws.Mastership.Release(MastershipDomain.Rapid);
            }

            Console.WriteLine(robot.Rws.Rapid.GetUiInstructionParameter(question.StackUrl, "TPCompleted"));
        }
        /**/

        robot.Disconnect();
    }
}
```

The names of the parameters depend on the instruction the program used, so read them with `GetUiInstructionParameters` before writing one. The answer is written first, then the parameter marking the dialogue as completed. Writing a parameter needs the `Rapid` mastership, and fails when the instruction is no longer pending.









## Signals renamed by the program

A RAPID program can give another name to an I/O signal. `GetAliasIo` lists these names as long as the program declaring them is loaded. The signals themselves are read and written with the [I/O service](/abb/documentation/rws-io).

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

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

        /**/
        // The signals a loaded program gave another name to. Empty when no program declares any.
        foreach (RapidAliasIoItem alias in robot.Rws.Rapid.GetAliasIo())
        {
            Console.WriteLine(alias.AliasName + " -> " + alias.SignalName + " (" + alias.Type + ")");
        }
        /**/

        robot.Disconnect();
    }
}
```





## Position of the robot

The position of the robot, its mechanical units and the external axes of a task are read from the [motion system service](/abb/documentation/rws-motion).