This page shows how to read the inputs and outputs of a Yaskawa Motoman controller with the SDK, and how to write the network inputs from a PC. No job is needed.

## Signals, groups and bits

A Yaskawa signal has a number of 5 digits, for example `#10013`. The first 4 digits are the group, the last digit is the bit in the group (0 to 7). `#10013` is the bit 3 of the group 1001, the fourth general output.

The SDK reads and writes whole groups: one byte per group, one bit per signal. `IOType` and a group number from `1` give the first group:

| `IOType`              | Signals              | Groups   |
| --------------------- | -------------------- | -------- |
| `GeneralInput`        | `#00010` to `#05127` | 1 to 512 |
| `GeneralOutput`       | `#10010` to `#15127` | 1 to 512 |
| `ExternalInput`       | `#20010` to `#25127` | 1 to 512 |
| `NetworkInput`        | `#27010` to `#29567` | 1 to 256 |
| `ExternalOutput`      | `#30010` to `#35127` | 1 to 512 |
| `NetworkOutput`       | `#37010` to `#39567` | 1 to 256 |
| `SpecificInput`       | `#40010` to `#41607` | 1 to 160 |
| `SpecificOutput`      | `#50010` to `#53007` | 1 to 300 |
| `InterfacePanelInput` | `#60010` to `#60647` | 1 to 64  |
| `AuxiliaryRelay`      | `#70010` to `#79997` | 1 to 999 |
| `RobotControlStatus`  | `#80010` to `#81287` | 1 to 128 |
| `PseudoInput`         | `#82010` to `#82207` | 1 to 20  |

The signals that exist depend on the I/O boards and the settings of your controller.

## Read I/O

`ReadIO(type, group, count)` reads `count` groups from the first group. The count is rounded up to an even number.

**C# : IoRead**
```csharp
using UnderAutomation.Yaskawa;
using UnderAutomation.Yaskawa.HighSpeedEServer;
using UnderAutomation.Yaskawa.Common;

public class IoRead
{
    static void Main()
    {
        var robot = new YaskawaRobot();
        robot.Connect("192.168.0.1");

        /**/
        // 2 groups of general outputs, from group 1: signals #10010 to #10027
        RobotIOData outputs = robot.HighSpeedEServer.ReadIO(IOType.GeneralOutput, 1, 2);

        // One byte per group, one bit per signal: bit 0 is #10010, bit 7 is #10017
        byte group1 = outputs.Value[0];
        bool out10013 = (group1 & (1 << 3)) != 0;

        // The same read, with the number of the first group (1001 for #10010)
        RobotIOData sameOutputs = robot.HighSpeedEServer.ReadIO(1001, 2);

        // 4 groups of general inputs: #00010 to #00047
        RobotIOData inputs = robot.HighSpeedEServer.ReadIO(IOType.GeneralInput, 1, 4);
        /**/

        robot.Disconnect();
    }
}
```

**Python : IoRead**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters
from underautomation.yaskawa.common.io_type import IOType

robot = YaskawaRobot()
robot.connect(ConnectParameters("192.168.0.1"))

##
# 2 groups of general outputs, from group 1: signals #10010 to #10027
outputs = robot.high_speed_e_server.read_io(IOType.GeneralOutput, 1, 2)

# One byte per group, one bit per signal: bit 0 is #10010, bit 7 is #10017
group1 = outputs.value[0]
out10013 = (group1 & (1 << 3)) != 0

# 4 groups of general inputs: #00010 to #00047
inputs = robot.high_speed_e_server.read_io(IOType.GeneralInput, 1, 4)
##

robot.disconnect()
```

**Matlab : IoRead**
```matlab
NET.addAssembly(fullfile(pwd, 'net48', 'UnderAutomation.Yaskawa.dll'));
import UnderAutomation.Yaskawa.*
import UnderAutomation.Yaskawa.HighSpeedEServer.*
import UnderAutomation.Yaskawa.Common.*

robot = YaskawaRobot();
robot.Connect('192.168.0.1');

%%
% 2 groups of general outputs, from group 1: signals #10010 to #10027
outputs = robot.HighSpeedEServer.ReadIO(IOType.GeneralOutput, uint16(1), 2);

% One byte per group, one bit per signal: bit 0 is #10010
bytes = uint8(outputs.Value);
out10013 = bitget(bytes(1), 4);   % bitget counts from 1
%%

robot.Disconnect();
```

`ReadIO(firstGroup, count)` does the same with the number of the first group: `1001` for `#10010`. In Python 2.2.0, only the form with `IOType` exists.

## Test one signal

`IoHelpers.ConvertIOGroupToBitAddress(type, group, bit)` gives the number of a signal, to print it as the pendant does. To test a signal, read its group and test its bit.

**C# : IoBits**
```csharp
using UnderAutomation.Yaskawa;
using UnderAutomation.Yaskawa.HighSpeedEServer;
using UnderAutomation.Yaskawa.Common;

public class IoBits
{
    static void Main()
    {
        var robot = new YaskawaRobot();
        robot.Connect("192.168.0.1");

        /**/
        // Signal number of bit 3 of group 1 of the general outputs: 10013
        uint signal = IoHelpers.ConvertIOGroupToBitAddress(IOType.GeneralOutput, 1, 3);
        Console.WriteLine($"#{signal:D5}");

        // Read the group and test the bit
        byte value = robot.HighSpeedEServer.ReadIO(IOType.GeneralOutput, 1, 2).Value[0];
        bool isOn = (value & (1 << 3)) != 0;
        /**/

        robot.Disconnect();
    }
}
```

**Python : IoBits**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters
from underautomation.yaskawa.common.io_type import IOType
from underautomation.yaskawa.common.io_helpers import IoHelpers

robot = YaskawaRobot()
robot.connect(ConnectParameters("192.168.0.1"))

##
# Signal number of bit 3 of group 1 of the general outputs: 10013
signal = IoHelpers.convert_io_group_to_bit_address(IOType.GeneralOutput, 1, 3)
print(f"#{signal:05d}")

# Read the group and test the bit
value = robot.high_speed_e_server.read_io(IOType.GeneralOutput, 1, 2).value[0]
is_on = (value & (1 << 3)) != 0
##

robot.disconnect()
```

## Write the network inputs

A PC can write the network inputs, `#27010` to `#29567`. The jobs and the ladder of the controller read them like other inputs. The other signals are written by the controller itself, and the controller refuses their write.

**C# : IoWrite**
```csharp
using UnderAutomation.Yaskawa;
using UnderAutomation.Yaskawa.HighSpeedEServer;
using UnderAutomation.Yaskawa.Common;

public class IoWrite
{
    static void Main()
    {
        var robot = new YaskawaRobot();
        robot.Connect("192.168.0.1");

        /**/
        // Network inputs are the signals that a PC can write: #27010 to #27017 for group 1.
        // Write an even number of groups: here groups 1 and 2
        robot.HighSpeedEServer.WriteIoNetworkInput(1, new byte[] { 0b0000_0101, 0x00 });

        // The same write, with the I/O type
        robot.HighSpeedEServer.WriteIO(IOType.NetworkInput, 1, new byte[] { 0b0000_0101, 0x00 });
        /**/

        robot.Disconnect();
    }
}
```

**Python : IoWrite**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters
from underautomation.yaskawa.common.io_type import IOType

robot = YaskawaRobot()
robot.connect(ConnectParameters("192.168.0.1"))

##
# Network inputs are the signals that a PC can write: #27010 to #27017 for group 1.
# Write an even number of groups: here groups 1 and 2
robot.high_speed_e_server.write_io_network_input(1, [0b0000_0101, 0x00])

# The same write, with the I/O type
robot.high_speed_e_server.write_io(IOType.NetworkInput, 1, [0b0000_0101, 0x00])
##

robot.disconnect()
```

- Write an even number of groups. To change one group, read the two groups first and write them back with the change.
- A write sets the 8 bits of each group. To change one bit, read the group, change the bit, write the group: see [Read and write I/O](/yaskawa/documentation/how-to-read-write-io).

## Try it in the demo application

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

![Inputs / Outputs page of the Yaskawa SDK demo application](/yaskawa/WinformsScreenshots/Io.jpg)

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

## Reference

**Methods of HighSpeedEServerClientBase**
```csharp
// Reads axis configuration information for the default robot control group. Returns axis type names for each of the 8 possible axes.
RobotAxisConfigData GetConfigurationInformation();

// Reads axis configuration information for a specified control group. Returns axis type names (e.g., "S", "L", "U", "R", "B", "T") for each axis.
RobotAxisConfigData GetConfigurationInformation(RobotControlGroup type);

// Reads information about the currently selected and executing job (program). Returns job name, current line, step, and speed override percentage.
RobotJobData GetExecutingJobInformation();

// Reads the position error (difference between commanded and actual position) for the default robot. Values indicate servo tracking error in pulse units.
RobotAxisIntData GetPositionError();

// Reads the position error for a specified control group. Position error indicates the difference between commanded and actual position.
RobotAxisIntData GetPositionError(RobotControlGroup type);

// Reads the current robot Cartesian position (TCP position and orientation). Coordinates are returned in millimeters for X, Y, Z and degrees for Rx, Ry, Rz.
RobotPositionCartesianData GetRobotCartesianPosition();

// Reads the current robot joint position in pulse (encoder) values. Returns raw pulse values for all robot axes.
RobotPositionIntData GetRobotJointPosition();

// Reads position data for a specified control group. Can read robot, base, or station position data depending on the control group specified.
RobotPositionIntData GetRobotPosition(RobotControlGroup type);

// Reads the current operational status of the robot controller. Returns information about mode (teach/play), running state, hold status, alarms, and servo power.
RobotStatusData GetStatusInformation();

// Retrieves system information about the default robot system (R1). Returns software version, robot name, and parameter file information.
RobotSystemInformation GetSystemInformation();

// Retrieves system information for a specific robot system or control group. Use for multi-robot controllers or to query specific axes groups.
RobotSystemInformation GetSystemInformation(RobotSystemTypeData type);

// Reads multiple base position variables (BP variables) from the robot controller. Base position variables define reference coordinate frames for robot operations.
RobotBasePositionVariableData ReadBasePosition(int firstIndex, int count);

// Reads multiple external axis variables (EX variables) from the robot controller. External axis variables store positions for additional axes beyond the main robot arm.
RobotExternalAxisVariableData ReadExternalPosition(int firstIndex, int count);

// Reads multiple I/O bytes from the robot controller starting at a specified index.
RobotIOData ReadIO(int firstIndex, int count);

// Reads multiple I/O bytes from the robot controller using I/O group addressing. The starting byte index is computed from the I/O type and group number.
RobotIOData ReadIO(IOType type, ushort group, int count);

// Reads multiple position variables (P variables) from the robot controller. Position variables store complete robot poses including position, orientation, and configuration.
RobotPositionVariableData ReadPositionVariable(int firstIndex, int count);

// Writes base position variables (BP variables) to the robot controller.
RobotDataHeader WriteBasePosition(int firstIndex, RobotBasePositionData[] data);

// Writes external axis variables (EX variables) to the robot controller using generic type. Provided for backward compatibility with existing code.
RobotDataHeader WriteExternalPosition(int firstIndex, RobotAxisRawData<int>[] data);

// Writes external axis variables (EX variables) to the robot controller.
RobotDataHeader WriteExternalPosition(int firstIndex, RobotExternalAxisData[] data);

// Writes I/O bytes to the robot controller starting at a specified index.
RobotDataHeader WriteIO(int firstIndex, byte[] data);

// Writes I/O bytes to the robot controller using I/O group addressing. By default, only Network Input can be written The starting byte index is computed from the I/O type and group number.
RobotDataHeader WriteIO(IOType type, ushort group, byte[] data);

// Writes network input bytes to the robot controller
RobotDataHeader WriteIoNetworkInput(ushort group, byte[] data);

// Writes position variables (P variables) to the robot controller.
RobotDataHeader WritePositionVariable(int firstIndex, RobotPositionIntData[] data);
```

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

**Members of HighSpeedEServer.RobotIOData**
```csharp
public class RobotIOData : RobotData {
    // Gets the array of I/O byte values read from the robot controller.
    // Each byte represents 8 consecutive I/O points where each bit corresponds to one I/O state.
    public byte[] Value { get; }
}
```

**Members of Common.IOType**
```csharp
public enum IOType {
    // Auxiliary relay signals (#70010–)
    AuxiliaryRelay = 9

    // External input signals (#20010–)
    ExternalInput = 2

    // External output signals (#30010–)
    ExternalOutput = 4

    // Robot user input signals (#00010–)
    GeneralInput = 0

    // Robot user output signals (#10010–)
    GeneralOutput = 1

    // Interface panel input signals (#60010–)
    InterfacePanelInput = 8

    // Network input signals (#27010–)
    NetworkInput = 3

    // Network output signals (#37010–)
    NetworkOutput = 5

    // Pseudo input signals (#82010–)
    PseudoInput = 11

    // Robot control status signals (#80010–)
    RobotControlStatus = 10

    // Robot system input signals (#40010–)
    SpecificInput = 6

    // Robot system output signals (#50010–)
    SpecificOutput = 7
}
```

**Members of Common.IoHelpers**
```csharp
public static class IoHelpers {
    // Converts an I/O group address (type + group + bit) to a flat Yaskawa 5-digit contact number.
    public static uint ConvertIOGroupToBitAddress(IOType type, ushort group, byte bitIndex)
}
```