> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.stereolabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.stereolabs.com/_mcp/server.

# Using the Positional Tracking API

## Positional Tracking Configuration

To configure positional tracking, use `InitParameters` at initialization and `RuntimeParameters` to change specific parameters during use.

**`C++`**

```cpp C++
// Set configuration parameters
InitParameters init_params;
init_params.camera_resolution = RESOLUTION::HD720; // Use HD720 video mode (default fps: 60)
init_params.coordinate_system = COORDINATE_SYSTEM::RIGHT_HANDED_Y_UP; // Use a right-handed Y-up coordinate system
init_params.coordinate_units = UNIT::METER; // Set units in meters
```

**`Python`**

```python Python
# Set configuration parameters
init_params = sl.InitParameters()
init_params.camera_resolution = sl.RESOLUTION.HD720 # Use HD720 video mode (default fps: 60)
init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP # Use a right-handed Y-up coordinate system
init_params.coordinate_units = sl.UNIT.METER # Set units in meters
```

**`C#`**

```csharp C#
// Set configuration parameters
InitParameters init_params = new InitParameters();
init_params.resolution = RESOLUTION.HD720; // Use HD720 video mode (default fps: 60)
init_params.coordinateSystem = COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP; // Use a right-handed Y-up coordinate system
init_params.coordinateUnits = UNIT.METER; // Set units in meters
```

## Enabling Positional Tracking

After opening the camera, enable positional tracking using `enablePositionalTracking()` with default `PositionalTrackingParameters`.

**`C++`**

```cpp C++
// Enable positional tracking with default parameters
sl::PositionalTrackingParameters tracking_parameters;
err = zed.enablePositionalTracking(tracking_parameters);
```

**`Python`**

```python Python
# Enable positional tracking with default parameters
tracking_parameters = sl.PositionalTrackingParameters()
err = zed.enable_positional_tracking(tracking_parameters)
```

**`C#`**

```csharp C#
// Enable positional tracking with default parameters
PositionalTrackingParameters trackingParams = new PositionalTrackingParameters();
zed.EnablePositionalTracking(ref trackingParams);
```

You can disable tracking anytime using `disablePositionalTracking()`.

For more information on positional tracking settings, refer to the [Positional Tracking Settings](/docs/development/zed-sdk/modules/positional-tracking/settings/) page.

## Getting Pose

The camera position gets updated with every new frame.

To retrieve pose data, use `getPosition()` after grabbing a frame.

In the following example, we extract the pose relative to the [World Frame](/docs/development/zed-sdk/modules/positional-tracking/coordinate-frames/#world-frame) and retrieve the translation and orientation quaternion values using `getTranslation()` and `getOrientation()`.

**`C++`**

```cpp C++
sl::Pose zed_pose;
if (zed.grab() == ERROR_CODE::SUCCESS) {
    // Get the pose of the camera relative to the world frame
    POSITIONAL_TRACKING_STATE state = zed.getPosition(zed_pose, REFERENCE_FRAME::WORLD);
    // Display translation and timestamp
    printf("Translation: tx: %.3f, ty:  %.3f, tz:  %.3f, timestamp: %llu\r",
    zed_pose.getTranslation().tx, zed_pose.getTranslation().ty, zed_pose.getTranslation().tz, zed_pose.timestamp);
    // Display orientation quaternion
    printf("Orientation: ox: %.3f, oy:  %.3f, oz:  %.3f, ow: %.3f\r",
    zed_pose.getOrientation().ox, zed_pose.getOrientation().oy, zed_pose.getOrientation().oz, zed_pose.getOrientation().ow);
}
```

**`Python`**

```python Python
zed_pose = sl.Pose()
if zed.grab(runtime_parameters) == sl.ERROR_CODE.SUCCESS:
    # Get the pose of the camera relative to the world frame
    state = zed.get_position(zed_pose, sl.REFERENCE_FRAME.WORLD)
    # Display translation and timestamp
    py_translation = sl.Translation()
    tx = round(zed_pose.get_translation(py_translation).get()[0], 3)
    ty = round(zed_pose.get_translation(py_translation).get()[1], 3)
    tz = round(zed_pose.get_translation(py_translation).get()[2], 3)
    print("Translation: tx: {0}, ty:  {1}, tz:  {2}, timestamp: {3}\n".format(tx, ty, tz, zed_pose.timestamp))
    #Display orientation quaternion
    py_orientation = sl.Orientation()
    ox = round(zed_pose.get_orientation(py_orientation).get()[0], 3)
    oy = round(zed_pose.get_orientation(py_orientation).get()[1], 3)
    oz = round(zed_pose.get_orientation(py_orientation).get()[2], 3)
    ow = round(zed_pose.get_orientation(py_orientation).get()[3], 3)
    print("Orientation: ox: {0}, oy:  {1}, oz: {2}, ow: {3}\n".format(ox, oy, oz, ow))
```

**`C#`**

```csharp C#
Pose zed_pose = new Pose();
RuntimeParameters runtimeParameters = new RuntimeParameters();
if (zed.Grab(ref runtimeParameters) == ERROR_CODE.SUCCESS) {
    // Get the pose of the camera relative to the world frame
    POSITIONAL_TRACKING_STATE state = zed.GetPosition(ref zed_pose, REFERENCE_FRAME.WORLD);
    // Display translation and timestamp
    Console.WriteLine("Translation: tx: " + zed_pose.translation.X + "ty: " + zed_pose.translation.Y + "tz: " + zed_pose.translation.Z + "Timestamp: " + zed_pose.timestamp);
    Console.WriteLine("Rotation: ox: " + zed_pose.rotation.X + "oy: " + zed_pose.rotation.Y + "oz: " + zed_pose.rotation.Z + "ow: " + zed_pose.rotation.W);
}
```

The class `Pose` is used to store camera position and additional information such as timestamp and confidence. Since position is always relative to a reference, it is important to set the [coordinate frame](/docs/development/zed-sdk/modules/positional-tracking/coordinate-frames/) that will be used as base. To get camera position in real world space, use `REFERENCE_FRAME::WORLD`, otherwise use `REFERENCE_FRAME::CAMERA` to get the change in pose relative to the last position (odometry).

By default, the pose of the left eye of the camera is returned. To get the pose at the center of the camera, see [Frame Transforms](/docs/development/zed-sdk/modules/positional-tracking/coordinate-frames/#frame-transforms). You can also retrieve a translation, orientation or rotation matrix using `getTranslation()`, `getOrientation()` and `getRotation()`.

## Getting Velocity

The velocity gets updated with every new frame. To retrieve velocity data, use `getPosition()` after grabbing a frame. In the following example, we extract the velocity relative to the [Camera Frame](/docs/development/zed-sdk/modules/positional-tracking/coordinate-frames/#camera-frame) and retrieve the linear and angular velocities along the \[x,y,z] axes.

**`C++`**

```cpp C++
sl::Pose zed_pose;
if (zed.grab() == ERROR_CODE::SUCCESS) {
    // Get the pose of the camera relative to the previous camera frame
    POSITIONAL_TRACKING_STATE state = zed.getPosition(zed_pose, REFERENCE_FRAME::CAMERA);
    // Display linear velocity
    printf("Linear Twist: vx: %.3f, vy:  %.3f, vz:  %.3f, timestamp: %llu\r",
    zed_pose.twist[0], zed_pose.twist[1], zed_pose.twist[2], zed_pose.timestamp);
    // Display angular velocity
    printf("Angular Twist: x: %.3f, y:  %.3f, z:  %.3f, timestamp: %llu\r",
    zed_pose.twist[3], zed_pose.twist[4], zed_pose.twist[5], zed_pose.timestamp);
}
```

**`Python`**

```python Python
zed_pose = sl.Pose()
if zed.grab(runtime_parameters) == sl.ERROR_CODE.SUCCESS:
    # Get the pose of the camera relative to the previous camera frame
    state = zed.get_position(zed_pose, sl.REFERENCE_FRAME.CAMERA)
    # Display linear velocity
    vx = zed_pose.twist[0]
    vy = zed_pose.twist[1]
    vz = zed_pose.twist[2]
    print("Translation: vx: {0}, vy:  {1}, vz:  {2}, timestamp: {3}\n".format(vx, vy, vz, zed_pose.timestamp))
    #Display angular velocity
    x = zed_pose.twist[3]
    y = zed_pose.twist[4]
    z = zed_pose.twist[5]
    print("Orientation: x: {0}, y:  {1}, z: {2}\n".format(x, y, z))
```

**`C#`**

```csharp C#
Pose zed_pose = new Pose();
RuntimeParameters runtimeParameters = new RuntimeParameters();
if (zed.Grab(ref runtimeParameters) == ERROR_CODE.SUCCESS) {
    // Get the pose of the camera relative to the previous camera frame
    POSITIONAL_TRACKING_STATE state = zed.GetPosition(ref zed_pose, REFERENCE_FRAME.CAMERA);
    // Display linear and angular velocity
    Console.WriteLine("Linear velocity: vx: " + zed_pose.twist[0] + "vy: " + zed_pose.twist[1] + "z: " + zed_pose.twist[2] + "Timestamp: " + zed_pose.timestamp);
    Console.WriteLine("Angular velocity: x: " + zed_pose.twist[3] + "y: " + zed_pose.twist[4] + "z: " + zed_pose.twist[5]);
}
```

## Saving an Area Map

**`C++`**

```cpp C++
#include <sl/Camera.hpp>
#include <iostream>
#include <thread>

int main(int argc, char **argv) {
    sl::Camera zed;

    sl::InitParameters init_params;
    init_params.depth_mode = sl::DEPTH_MODE::NONE;
    init_params.coordinate_units = sl::UNIT::METER;

    auto status = zed.open(init_params);
    if (status != sl::ERROR_CODE::SUCCESS) {
        std::cout << "Failed to open ZED: " << status << std::endl;
        return -1;
    }

    // Enable GEN_3 Tracking
    sl::PositionalTrackingParameters track_params;
    track_params.enable_area_memory = true;
    track_params.mode = sl::POSITIONAL_TRACKING_MODE::GEN_3;

    status = zed.enablePositionalTracking(track_params);
    if (status != sl::ERROR_CODE::SUCCESS) {
        std::cout << "Failed to enable tracking: " << status << std::endl;
        return -1;
    }

    // Main Capture Loop — record the space
    std::cout << "Move the camera following the mapping procedure..." << std::endl;

    while (true) {
        if (zed.grab() == sl::ERROR_CODE::SUCCESS) {
            sl::Pose pose;
            zed.getPosition(pose);

            // Add your exit condition here
            if (/* exit condition */ false)
                break;
        }
    }

    // Save AREA (ASYNC)
    std::string area_file = "environment.area";
    status = zed.saveAreaMap(area_file.c_str());

    if (status == sl::ERROR_CODE::SUCCESS) {

        sl::AREA_EXPORTING_STATE export_state = zed.getAreaExportState();

        while (export_state == sl::AREA_EXPORTING_STATE::RUNNING) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            export_state = zed.getAreaExportState();
        }

        if (export_state == sl::AREA_EXPORTING_STATE::SUCCESS) {
            std::cout << "Successfully saved area map to " << area_file << std::endl;
        } else {
            std::cout << "Failed to save area map: " 
                      << sl::toString(export_state).c_str() << std::endl;
        }

    } else {
        std::cout << "Failed to start area save: " << status << std::endl;
    }

    zed.disablePositionalTracking();
    zed.close();
}

```

**`Python`**

```python Python
import pyzed.sl as sl
import time

zed = sl.Camera()

# ---- Init ----
init_params = sl.InitParameters()
init_params.depth_mode = sl.DEPTH_MODE.NONE
init_params.coordinate_units = sl.UNIT.METER

status = zed.open(init_params)
if status != sl.ERROR_CODE.SUCCESS:
    print("Failed to open ZED:", status)
    exit(1)

# ---- Tracking GEN_3 ----
track_params = sl.PositionalTrackingParameters()
track_params.enable_area_memory = True
track_params.mode = sl.POSITIONAL_TRACKING_MODE.GEN_3

status = zed.enable_positional_tracking(track_params)
if status != sl.ERROR_CODE.SUCCESS:
    print("Failed to enable tracking:", status)
    exit(1)

print("Move the camera around to record the area...")

# ---- Capture Loop (500 frames example) ----
runtime = sl.RuntimeParameters()
frame_count = 0

# Replace this condition with your own exit condition
while frame_count < 500:
    if zed.grab(runtime) == sl.ERROR_CODE.SUCCESS:
        frame_count += 1  # Just collecting tracking data

# ---- Save AREA ----
output_file = "environment.area"
status = zed.save_area_map(output_file)

if status == sl.ERROR_CODE.SUCCESS:
    print("Saving AREA asynchronously...")

    export_state = zed.get_area_export_state()
    while export_state == sl.AREA_EXPORTING_STATE.RUNNING:
        time.sleep(0.01)
        export_state = zed.get_area_export_state()

    if export_state == sl.AREA_EXPORTING_STATE.SUCCESS:
        print("Successfully saved AREA to", output_file)
    else:
        print("Failed to save AREA:", export_state)
else:
    print("Failed to start AREA save:", status)

zed.disable_positional_tracking()
zed.close()

```

**`C#`**

```csharp C#
using System;
using System.Threading;
using sl;

class Program {
    static void Main(string[] args) {
        Camera zed = new Camera();

        // ---- Init ----
        InitParameters init = new InitParameters();
        init.depthMode = DEPTH_MODE.NONE;
        init.coordinateUnits = UNIT.METER;

        ERROR_CODE status = zed.Open(ref init);
        if (status != ERROR_CODE.SUCCESS) {
            Console.WriteLine("Failed to open ZED: " + status);
            return;
        }

        // ---- Tracking GEN_3 ----
        PositionalTrackingParameters trackParams = new PositionalTrackingParameters();
        trackParams.enableAreaMemory = true;
        trackParams.mode = POSITIONAL_TRACKING_MODE.GEN_3;

        status = zed.EnablePositionalTracking(ref trackParams);
        if (status != ERROR_CODE.SUCCESS) {
            Console.WriteLine("Failed to enable tracking: " + status);
            return;
        }

        Console.WriteLine("Move the camera around to record the area...");

        // ---- Capture Loop (500 frames example) ----
        RuntimeParameters runtime = new RuntimeParameters();
        int frameCount = 0;
        // Replace this condition with your own exit condition
        while (frameCount < 500) {
            if (zed.Grab(ref runtime) == ERROR_CODE.SUCCESS) {
                frameCount++; // Just collecting tracking data
            }
        }

        // ---- Save AREA ----
        string file = "environment.area";
        status = zed.SaveAreaMap(file);

        if (status == ERROR_CODE.SUCCESS) {
            Console.WriteLine("Saving AREA asynchronously...");

            AREA_EXPORT_STATE state = zed.GetAreaExportState();
            while (state == AREA_EXPORT_STATE.AREA_EXPORT_STATE_RUNNING) {
                Thread.Sleep(10);
                state = zed.GetAreaExportState();
            }

            if (state == AREA_EXPORT_STATE.AREA_EXPORT_STATE_SUCCESS) {
                Console.WriteLine("Successfully saved AREA to " + file);
            } else {
                Console.WriteLine("Failed to save AREA: " + state);
            }
        } else {
            Console.WriteLine("Failed to start saving AREA: " + status);
        }

        zed.DisablePositionalTracking();
        zed.Close();
    }
}

```

## Relocalizing within an Area map

**`C++`**

```cpp C++
// Enable positional tracking with default parameters
sl::PositionalTrackingParameters tracking_parameters;
tracking_parameters.area_file_path = "example.area";
err = zed.enablePositionalTracking(tracking_parameters);
```

**`Python`**

```python Python
# Enable positional tracking with default parameters
tracking_parameters = sl.PositionalTrackingParameters()
tracking_parameters.area_file_path = "example.area"
err = zed.enable_positional_tracking(tracking_parameters)
```

**`C#`**

```csharp C#
// Enable positional tracking with default parameters
PositionalTrackingParameters trackingParams = new PositionalTrackingParameters();
trackingParams.areaFilePath = "example.area";
zed.EnablePositionalTracking(ref trackingParams);
```

## Code Example

For code examples, check out the [Tutorial](https://github.com/stereolabs/zed-sdk/tree/master/tutorials/tutorial%204%20-%20positional%20tracking) and [Sample](https://github.com/stereolabs/zed-sdk/tree/master/positional%20tracking) on GitHub.