## 🚀 Introduction

Let's dive into how you can use registers to communicate with external systems like Fieldbus or RTDE clients ,  it's simpler than it sounds, promise! 😉

---

## 🧠 What Are Registers?

UR Cobots offer access to several types of registers you can use to send and receive data between your robot and external systems. Think of them as little data mailboxes 📬 with three types of content:

- **Boolean**: `true` or `false`
- **Float**: 32-bit floating-point numbers
- **Integer**: 32-bit signed integers

Each data type comes in two flavors:

- **Input Registers**: Read-only 🔍 ,  used to _receive_ data from external systems like Fieldbus or RTDE.
- **Output Registers**: Read/write ✍️ ,  used to _send_ data to those systems.

> ⚠️ Note: You can **only write to output registers** using script. Input registers are strictly **read-only** from scripts!

## 🔍 Reading Registers with URScript

| Data Type            | Function                                             | Address Range | Notes                                                                               |
| -------------------- | ---------------------------------------------------- | ------------- | ----------------------------------------------------------------------------------- |
| **Boolean (Input)**  | `read_input_boolean_register(address: int) -> bool`  | `0–127`       | `0–63`: Fieldbus/PLC<br/>`64–127`: RTDE                                             |
| **Boolean (Output)** | `read_output_boolean_register(address: int) -> bool` | `0–127`       | Same ranges as input                                                                |
| **Float (Input)**    | `read_input_float_register(address: int) -> float`   | `0–47`        | `0–23`: Fieldbus/PLC<br/>`24–47`: RTDE                                              |
| **Float (Output)**   | `read_output_float_register(address: int) -> float`  | `0–47`        | Same ranges as input                                                                |
| **Integer (Input)**  | `read_input_integer_register(address: int) -> int`   | `0–47`        | `0–23`: Fieldbus/PLC<br/>`24–47`: RTDE<br/>Range: `[-2,147,483,648, 2,147,483,647]` |
| **Integer (Output)** | `read_output_integer_register(address: int) -> int`  | `0–47`        | Same as above                                                                       |

## ✍️ Writing Registers with URScript

| Data Type            | Function                                                   | Address Range | Value                     |
| -------------------- | ---------------------------------------------------------- | ------------- | ------------------------- |
| **Boolean (Output)** | `write_output_boolean_register(address: int, value: bool)` | `0–127`       | `True` / `False`          |
| **Float (Output)**   | `write_output_float_register(address: int, value: float)`  | `0–47`        | 32-bit float (e.g. `1.5`) |
| **Integer (Output)** | `write_output_integer_register(address: int, value: int)`  | `0–47`        | Signed 32-bit int         |

## 🧪 Handling Registers with the Primary Interface

### ✍️ Writing Output Registers

The Primary Interface allows remote script execution with two key behaviors:

- If you send a raw script line, it will **stop the current program** and execute your line. ⛔➡️▶️
- If the script is sent within a secondary program (a `sec` block), it will run in **parallel** without stopping the main program. 🧵✨

Example: Writing the float register 0 with the value `1.5`:

**C# : PrimaryInterfaceWriteRegisters**
```csharp
using UnderAutomation.UniversalRobots;

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

    robot.Connect("192.168.0.1");

    /**/
    // Pause main program and execute script
    robot.PrimaryInterface.Script.Send("write_output_float_register(0, 1.5)");

    // Send Secondary program that does not stop the main program
    robot.PrimaryInterface.Script.Send(@"
sec secondaryProgram():
  write_output_float_register(0, 1.5)
end
");
    /**/
  }

}
```

### 🕵️ Reading Registers

Technically, you _can_ read registers via the Primary Interface... but it's a bit tricky 😅.

You'd need to execute something like:

```python
global myRegister0 = read_input_float_register(0)
```

Then read `myRegister0` via Primary Interface functions. The catch? You can't write to a global variable from a secondary program. So this requires stopping the current program, which isn't ideal.

🚫 Not recommended ,  use **RTDE** instead for smoother operation.

---

## ⚡ Handling Registers with RTDE

RTDE (Real-Time Data Exchange) is the _go-to_ method for reading and writing registers up to **500Hz** 🔥⚡

To use it:

- Set up registers when configuring the RTDE connection
- Use **OutputSetup** for the data you want to read 📤
- Use **InputSetup** for the data you want to write 📥

💡 Boolean trick:
Booleans from `0–63` are accessed via two 32-bit unsigned integer packets.
From `64–127`, access them bit-by-bit.

### ✍️ Writing Input Registers

Only **input-type** registers (bool, int, float) can be written via RTDE. To write **output-type** registers, use Primary Interface.
Here's an example:

**C# : RtdeWriteRegisters**
```csharp
using UnderAutomation.UniversalRobots;
using UnderAutomation.UniversalRobots.Rtde;

class RtdeWriteRegisters
{
  static void Main()
  {
    /**/
    var robot = new UR();

    var param = new ConnectParameters("192.168.0.1");

    // Enable RTDE
    param.Rtde.Enable = true;

    // Exchange data at 500Hz
    param.Rtde.Frequency = 500;

    // Select data you want to write in robot controller
    param.Rtde.InputSetup.Add(RtdeInputData.InputBtRegisters0To31);
    param.Rtde.InputSetup.Add(RtdeInputData.InputBtRegisters32To63);
    param.Rtde.InputSetup.Add(RtdeInputData.InputBitRegisters, 64);
    param.Rtde.InputSetup.Add(RtdeInputData.InputIntRegisters, 0);
    param.Rtde.InputSetup.Add(RtdeInputData.InputDoubleRegisters, 0);

    // Connect to robot
    robot.Connect(param);

    //...

    // Write input values in robot
    var inputValues = new RtdeInputValues();
    inputValues.InputBtRegisters0To31 = 0xff;
    inputValues.InputBtRegisters32To63 = 0xCA;
    inputValues.InputBitRegisters.X64 = true;
    inputValues.InputIntRegisters.X0 = 2;
    inputValues.InputDoubleRegisters.X0 = 3.14;

    robot.Rtde.WriteInputs(inputValues);

  }

}
```

### 🔍 Reading Registers

All registers are available for reading! Here's how you can do it:

**C# : RtdeReadRegisters**
```csharp
using UnderAutomation.UniversalRobots;
using UnderAutomation.UniversalRobots.Rtde;

class RtdeReadRegisters
{
  static void Main()
  {
    /**/
    var robot = new UR();

    var param = new ConnectParameters("192.168.0.1");

    // Enable RTDE
    param.Rtde.Enable = true;

    // Exchange data at 500Hz
    param.Rtde.Frequency = 500;

    // Select data you want the robot to send
    // Read input registers
    param.Rtde.OutputSetup.Add(RtdeOutputData.InputBitRegisters0To31); // 32 bits integer
    param.Rtde.OutputSetup.Add(RtdeOutputData.InputBitRegisters32To63);// 32 bits integer
    param.Rtde.OutputSetup.Add(RtdeOutputData.InputBitRegisters, 64); // one by one access of registers 64-127 from FW 3.9.0 / 5.3.0
    param.Rtde.OutputSetup.Add(RtdeOutputData.InputDoubleRegisters, 0); // floating point
    param.Rtde.OutputSetup.Add(RtdeOutputData.InputIntRegisters, 0); // integer

    // Read output registers
    param.Rtde.OutputSetup.Add(RtdeOutputData.OutputBitRegisters0To31);
    param.Rtde.OutputSetup.Add(RtdeOutputData.OutputBitRegisters32To63);
    param.Rtde.OutputSetup.Add(RtdeOutputData.OutputBitRegisters, 64);
    param.Rtde.OutputSetup.Add(RtdeOutputData.OutputDoubleRegisters, 0);
    param.Rtde.OutputSetup.Add(RtdeOutputData.OutputIntRegisters, 0);

    // Connect to robot
    robot.Connect(param);

    // Be notified at 500Hz when data is received
    robot.Rtde.OutputDataReceived += Rtde_OutputDataReceived;

    /**/
  }

  /**/
  private static void Rtde_OutputDataReceived(object sender, RtdeDataPackageEventArgs e)
  {
    // Read input registers
    bool bit0 = e.OutputDataValues.InputBitRegisters.X64;
    uint bit0To31 = e.OutputDataValues.InputBitRegisters0To31;
    uint bit32To63 = e.OutputDataValues.InputBitRegisters32To63;

    int int0 = e.OutputDataValues.InputIntRegisters.X0;

    double double0 = e.OutputDataValues.InputDoubleRegisters.X0;

    // Read output registers
    bool outputBit0 = e.OutputDataValues.OutputBitRegisters.X64;
    uint outputBit0To31 = e.OutputDataValues.OutputBitRegisters0To31;
    uint outputBit32To63 = e.OutputDataValues.OutputBitRegisters32To63;

    int outputInt0 = e.OutputDataValues.OutputIntRegisters.X0;

    double outputDouble0 = e.OutputDataValues.OutputDoubleRegisters.X0;
  }
  /**/
}
```