This page shows how to read the position of a Yaskawa Motoman robot with the SDK: the Cartesian position of the tool, the joint positions, the position error and the torque, for the robot, a station or base axes. All these methods only read: they work in any mode.

## Cartesian position

`GetRobotCartesianPosition()` reads the position of the tool center point of the first robot, in mm and degrees.

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

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

        /**/
        RobotPositionCartesianData position = robot.HighSpeedEServer.GetRobotCartesianPosition();

        // Tool center point in mm, orientation in degrees
        Console.WriteLine($"X={position.X} Y={position.Y} Z={position.Z}");
        Console.WriteLine($"Rx={position.Rx} Ry={position.Ry} Rz={position.Rz}");

        // Frame, tool and posture of the position
        Console.WriteLine($"{position.DataType}, tool {position.ToolNumber}, user frame {position.UserCoordinateNumber}");
        Console.WriteLine(position.Form);
        /**/

        robot.Disconnect();
    }
}
```

**Python : PositionCartesian**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters

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

##
p = robot.high_speed_e_server.get_robot_cartesian_position()

# Tool center point in mm, orientation in degrees
print(f"X={p.x} Y={p.y} Z={p.z}")
print(f"Rx={p.rx} Ry={p.ry} Rz={p.rz}")

# Frame, tool and posture of the position
print(f"{p.data_type.name}, tool {p.tool_number}, user frame {p.user_coordinate_number}")
print(p.form)
##

robot.disconnect()
```

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

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

%%
p = robot.HighSpeedEServer.GetRobotCartesianPosition();

% Tool center point in mm, orientation in degrees
xyz = [p.X, p.Y, p.Z];
rxyz = [p.Rx, p.Ry, p.Rz];
fprintf('X=%.3f Y=%.3f Z=%.3f
', xyz);
%%

robot.Disconnect();
```

| Property               | Content                                                                        |
| ---------------------- | ------------------------------------------------------------------------------ |
| `X`, `Y`, `Z`          | Position, in mm                                                                |
| `Rx`, `Ry`, `Rz`       | Orientation, in degrees                                                        |
| `DataType`             | Frame of the values, for example `RobotCoordinateValue`                        |
| `ToolNumber`           | Tool used for the position                                                     |
| `UserCoordinateNumber` | User frame, when `DataType` is `UserCoordinateValue`                           |
| `Form`                 | Posture of the robot, see [Motion](/yaskawa/documentation/hses-motion#posture) |

Keep the `Form` of a position when you send the robot back to it: the same Cartesian position can be reached with several postures.

## Joint positions

`GetRobotJointPosition()` reads the position of each axis of the first robot, in encoder pulses.

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

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

        /**/
        RobotPositionIntData joints = robot.HighSpeedEServer.GetRobotJointPosition();

        // One value per axis, in encoder pulses. Index 0 is the S axis
        int[] pulses = joints.Axes;
        Console.WriteLine(string.Join(", ", pulses));

        // The same values, axis by axis
        Console.WriteLine($"S={joints.Axis1} L={joints.Axis2} U={joints.Axis3} R={joints.Axis4} B={joints.Axis5} T={joints.Axis6}");
        /**/

        robot.Disconnect();
    }
}
```

**Python : PositionJoints**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters

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

##
joints = robot.high_speed_e_server.get_robot_joint_position()

# One value per axis, in encoder pulses. Index 0 is the S axis
pulses = list(joints.axes)
print(pulses)

# The same values, axis by axis
print(f"S={joints.axis1} L={joints.axis2} U={joints.axis3} R={joints.axis4} B={joints.axis5} T={joints.axis6}")
##

robot.disconnect()
```

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

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

%%
joints = robot.HighSpeedEServer.GetRobotJointPosition();

% A .NET int32 array: convert it to a Matlab vector of pulses
pulses = double(joints.Axes);
disp(pulses(1:6));
%%

robot.Disconnect();
```

`Axes` has 8 values. On a 6 axis robot, the indexes 0 to 5 are the axes S, L, U, R, B and T, and the indexes 6 and 7 are `0`. `Axis1` to `Axis8` give the same values. [Axis names](/yaskawa/documentation/hses-system#axis_names) gives the axes of your robot.

The pulses are the unit of the controller for the joints. The number of pulses per degree depends on the axis and on the robot model: it is a parameter of the controller. Send the pulses back to `MoveJoints` as they are, without conversion.

## Position error and torque

`GetPositionError()` reads the difference between the command and the feedback of each axis, in pulses. `GetTorque()` reads the torque of each axis, in percent of the rated torque.

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

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

        /**/
        // Difference between the command and the feedback of each axis, in pulses
        RobotAxisIntData error = robot.HighSpeedEServer.GetPositionError();
        Console.WriteLine(string.Join(", ", error.Axes));

        // Torque of each axis, in percent of the rated torque
        RobotAxisIntData torque = robot.HighSpeedEServer.GetTorque();
        Console.WriteLine(string.Join(", ", torque.Axes));
        /**/

        robot.Disconnect();
    }
}
```

**Python : PositionErrorTorque**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters
from underautomation.yaskawa.high_speed_e_server.robot_control_group import RobotControlGroup

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

##
# The first robot, in pulses
r1 = RobotControlGroup.DefaultRobotPulse

# Difference between the command and the feedback of each axis, in pulses
error = robot.high_speed_e_server.get_position_error(r1)
print(list(error.axes))

# Torque of each axis, in percent of the rated torque
torque = robot.high_speed_e_server.get_torque(r1)
print(list(torque.axes))
##

robot.disconnect()
```

Read them in a loop during a move to see the load of each axis, or to detect a collision or a wear in your application.

In Python 2.2.0, these two methods take the control group, as in the code above.

## Other control groups

A controller can drive several robots, base axes (travel tracks) and stations (positioners). `GetRobotPosition(group)`, `GetPositionError(group)` and `GetTorque(group)` read the axes of one control group.

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

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

        /**/
        // Second robot of the controller, in pulses
        var r2 = new RobotControlGroup(ControlGroup.RobotPulseValue, 2);
        RobotPositionIntData r2Joints = robot.HighSpeedEServer.GetRobotPosition(r2);

        // First base axis group (travel track), in pulses
        var b1 = new RobotControlGroup(ControlGroup.BasePulseValue, 1);
        RobotPositionIntData b1Axes = robot.HighSpeedEServer.GetRobotPosition(b1);

        // Torque of the base axes
        RobotAxisIntData b1Torque = robot.HighSpeedEServer.GetTorque(b1);
        /**/

        robot.Disconnect();
    }
}
```

**Python : PositionControlGroup**
```python
from underautomation.yaskawa.yaskawa_robot import YaskawaRobot
from underautomation.yaskawa.connect_parameters import ConnectParameters
from underautomation.yaskawa.high_speed_e_server.robot_control_group import RobotControlGroup
from UnderAutomation.Yaskawa.HighSpeedEServer import ControlGroup

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

##
# Version 2.2.0: ControlGroup comes from the .NET namespace (see the Python page)

# Second robot of the controller, in pulses
r2 = RobotControlGroup(ControlGroup.RobotPulseValue, 2)
r2_joints = robot.high_speed_e_server.get_robot_position(r2)

# First base axis group (travel track), in pulses
b1 = RobotControlGroup(ControlGroup.BasePulseValue, 1)
b1_axes = robot.high_speed_e_server.get_robot_position(b1)

# Torque of the base axes
b1_torque = robot.high_speed_e_server.get_torque(b1)
##

robot.disconnect()
```

| `ControlGroup`    | Axes, unit                                | Number                |
| ----------------- | ----------------------------------------- | --------------------- |
| `RobotPulseValue` | Robot, in pulses                          | `1` to `8` (R1 to R8) |
| `RobotCartesian`  | Robot, Cartesian values of the controller | `1` to `8`            |
| `BasePulseValue`  | Base axes, in pulses                      | `1` to `8` (B1 to B8) |
| `BaseCartesian`   | Base axes, Cartesian values               | `1` to `8`            |

`GetRobotPosition` returns the raw values of the controller. With a Cartesian group, `Axes` holds X, Y, Z in micrometers and Rx, Ry, Rz in 1/10000 degree. `GetRobotCartesianPosition()` does this conversion for the first robot.

`RobotControlGroup.DefaultRobotCartesian` and `RobotControlGroup.DefaultRobotPulse` are the groups of the first robot, in .NET.

## Try it in the demo application

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

![Current position page of the Yaskawa SDK demo application](/yaskawa/WinformsScreenshots/Position.jpg)

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

## Reference

**Methods of HighSpeedEServerClientBase**
```csharp
// 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 torque values for the default robot's servo motors. Torque values indicate motor load as a percentage of rated torque.
RobotAxisIntData GetTorque();

// Reads the current torque values for a specified control group's servo motors. Torque values indicate motor load as a percentage of rated torque.
RobotAxisIntData GetTorque(RobotControlGroup type);
```

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

**Members of HighSpeedEServer.RobotPositionCartesianData**
```csharp
public class RobotPositionCartesianData : RobotData {
    // Gets the position data type indicating the coordinate system used.
    public RobotPositionDataType DataType { get; }

    // Gets the robot posture (form) data defining the kinematic configuration.
    public RobotPosture Form { get; }

    // Gets the rotation around X axis (Rx) in degrees.
    public double Rx { get; }

    // Gets the rotation around Y axis (Ry) in degrees.
    public double Ry { get; }

    // Gets the rotation around Z axis (Rz) in degrees.
    public double Rz { get; }

    // Gets the tool number (TCP) used for this position.
    public int ToolNumber { get; }

    // Gets the user coordinate system number used for this position.
    public int UserCoordinateNumber { get; }

    // Gets the X coordinate in millimeters.
    public double X { get; }

    // Gets the Y coordinate in millimeters.
    public double Y { get; }

    // Gets the Z coordinate in millimeters.
    public double Z { get; }
}
```

**Members of HighSpeedEServer.RobotPositionIntData**
```csharp
public class RobotPositionIntData : RobotPositionData<int> {
    // Creates a blank instance of RobotPositionIntData
    public RobotPositionIntData()

    // Creates a new instance of RobotPositionIntData with the specified header information.
    public RobotPositionIntData(RobotDataHeader header)
}
```

**Members of HighSpeedEServer.RobotAxisIntData**
```csharp
public class RobotAxisIntData : RobotAxisRawData<int> {

}
```

**Members of HighSpeedEServer.RobotControlGroup**
```csharp
public class RobotControlGroup {
    // Creates a new RobotControlGroup with the specified group type and index.
    public RobotControlGroup(ControlGroup group, int index)

    // The combined byte value sent to the robot controller (Group + Index).
    public readonly byte ByteValue

    // Default control group for Cartesian position of robot 1.
    public static readonly RobotControlGroup DefaultRobotCartesian

    // Default control group for pulse position of robot 1.
    public static readonly RobotControlGroup DefaultRobotPulse

    // The control group type (robot, base, station).
    public readonly ControlGroup Group

    // The index within the control group (e.g., robot number 1-8).
    public readonly int Index
}
```

**Members of HighSpeedEServer.ControlGroup**
```csharp
public enum ControlGroup {
    // Base axes in Cartesian coordinates. Valid index: 1-8.
    BaseCartesian = 110

    // Base axes in pulse values. Valid index: 1-8.
    BasePulseValue = 10

    // Robot axes in Cartesian coordinates. Valid index: 1-8.
    RobotCartesian = 100

    // Robot axes in pulse (encoder) values. Valid index: 1-8.
    RobotPulseValue = 0

    // Station axes in pulse values. Valid index: 1-44.
    StationPulseValue = 21
}
```

**Members of HighSpeedEServer.RobotPositionDataType**
```csharp
public enum RobotPositionDataType {
    // Position in base coordinate system (world frame, value 16).
    BaseCoordinateValue = 16

    // Position in encoder pulse values (joint space).
    PulseValue = 0

    // Position in robot coordinate system (robot base frame, value 17).
    RobotCoordinateValue = 17

    // Position in tool coordinate system (value 18).
    ToolCoordinateValue = 18

    // Position in user-defined coordinate system (value 19).
    UserCoordinateValue = 19
}
```