This article shows how to start a program of a Universal Robots cobot from a PC, in C# or Python, and follow it until its end. It gives a complete program: check the remote control, power on, release the brakes, load the program, play it.

## Which way to choose

| Way                | Robots                     | What it runs                                        | Follow it with                                |
| ------------------ | -------------------------- | --------------------------------------------------- | --------------------------------------------- |
| Dashboard Server   | CB-Series, e-Series        | A `.urp` program saved on the robot                 | `GetProgramState()`, `IsProgramRunning()`     |
| REST API           | PolyScope X                | A program saved on the robot                        | `GetProgramState()`                           |
| URScript           | All                        | URScript sent by the PC, without a `.urp` file      | `RobotModeData.ProgramRunning`                |

The Dashboard Server and the REST API run the programs made in PolyScope: the operator sees them and can stop them. URScript suits a short sequence generated by the PC. See [Send URScript](/universal-robots/documentation/remote-send-script).

## Prerequisites

- The service `Dashboard Server` is enabled (PolyScope 5), or the robot runs PolyScope X: see [Prepare the robot](/universal-robots/documentation/connect#prepare_the_robot).
- The robot is in remote control.
- The program exists on the robot. To send it from the PC, see [Transfer files and backups](/universal-robots/documentation/how-to-transfer-files).

## Steps

| Step                         | Dashboard Server                   | REST API (PolyScope X)              |
| ---------------------------- | ---------------------------------- | ----------------------------------- |
| Check the remote control     | `IsInRemoteControl()`              |                                     |
| Power on                     | `PowerOn()`, wait for `Idle`       | `PowerOn()`                         |
| Release the brakes           | `ReleaseBrake()`, wait for `Running` | `BrakeRelease()`                  |
| Load the program             | `LoadProgram("name.urp")`          | `LoadProgram("name")`               |
| Play                         | `Play()`                           | `Play()`                            |
| Follow                       | `GetProgramState()`                | `GetProgramState()`                 |
| Pause, stop                  | `Pause()`, `Stop()`                | `Pause()`, `Resume()`, `Stop()`     |

## Example

The program uses the Dashboard Server. For PolyScope X, the same steps are in [REST API](/universal-robots/documentation/rest-api).

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

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

    // Primary Interface and Dashboard Server
    robot.Connect("192.168.0.1");

    // e-Series: the robot must be in remote control
    if (!robot.Dashboard.IsInRemoteControl().Value)
    {
      Console.WriteLine("Switch the robot to remote control on the teach pendant");
      return;
    }

    // Power on, then release the brakes
    robot.Dashboard.PowerOn();
    WaitForMode(robot, RobotModes.Idle);
    robot.Dashboard.ReleaseBrake();
    WaitForMode(robot, RobotModes.Running);

    // Load the program: a path relative to the programs folder, or absolute
    var load = robot.Dashboard.LoadProgram("pick_and_place.urp");
    if (!load.Succeed)
    {
      Console.WriteLine(load.Message);
      return;
    }

    robot.Dashboard.Play();

    // Follow the program until it stops
    while (true)
    {
      ProgramState state = robot.Dashboard.GetProgramState().Value;
      Console.WriteLine(state.Name + ": " + state.State);
      if (state.State == ProgramStates.Stopped) break;
      Thread.Sleep(500);
    }

    robot.Disconnect();
    /**/
  }

  /**/
  static void WaitForMode(UR robot, RobotModes mode)
  {
    var timeout = DateTime.Now.AddSeconds(30);
    while (robot.Dashboard.GetRobotMode().Value != mode)
    {
      if (DateTime.Now > timeout) throw new TimeoutException("Robot mode is not " + mode);
      Thread.Sleep(250);
    }
  }
  /**/
}
```

**Python : HowToRunProgram**
```python
import time
from underautomation.universal_robots.ur import UR
from underautomation.universal_robots.common.robot_modes import RobotModes
from underautomation.universal_robots.dashboard.program_states import ProgramStates

##
def wait_for_mode(robot, mode, timeout=30):
    end = time.monotonic() + timeout
    while robot.dashboard.get_robot_mode().value != mode:
        if time.monotonic() > end:
            raise TimeoutError(f"Robot mode is not {mode}")
        time.sleep(0.25)
##

##
robot = UR()

# Primary Interface and Dashboard Server
robot.connect("192.168.0.1")

# e-Series: the robot must be in remote control
if not robot.dashboard.is_in_remote_control().value:
    raise SystemExit("Switch the robot to remote control on the teach pendant")

# Power on, then release the brakes
robot.dashboard.power_on()
wait_for_mode(robot, RobotModes.Idle)
robot.dashboard.release_brake()
wait_for_mode(robot, RobotModes.Running)

# Load the program: a path relative to the programs folder, or absolute
load = robot.dashboard.load_program("pick_and_place.urp")
if not load.succeed:
    raise SystemExit(load.message)

robot.dashboard.play()

# Follow the program until it stops
while True:
    state = robot.dashboard.get_program_state().value
    print(f"{state.name}: {state.state}")
    if state.state == ProgramStates.Stopped:
        break
    time.sleep(0.5)

robot.disconnect()
##
```

`GetRobotMode()` is polled until the arm is powered (`Idle`), then until the brakes are released (`Running`). The program state is polled every 500 ms until `Stopped`.

## Troubleshooting

- **`LoadProgram` fails:** the path is wrong. A relative path starts in the programs folder of the robot (`/programs`).
- **The commands fail with a message about the remote control:** switch the robot to remote control on the teach pendant.
- **`ReleaseBrake` does nothing:** the arm is not powered, or a protective stop is active. See [Read and reset alarms](/universal-robots/documentation/how-to-read-reset-alarms).
- **The program stops at once:** the installation of the program is not the loaded installation, or a popup waits on the teach pendant.

## What to read next

- [Dashboard Server](/universal-robots/documentation/remote-commands): the list of the commands.
- [Monitor the state of the robot](/universal-robots/documentation/how-to-monitor-state).