WindShape

WindTrack

Python interface to Interact with the Tracking

Motion Tracking

The WindSuite supports Optitrack and Vicon motion capture systems for tracking objects.

All the tracked objects can be accessed via the tracking module of the SDK, which provides a unified interface to access the tracking data regardless of the underlying motion capture system.

Callback

To access the Tracking data, users can register a callback function.

The given function will automatically be called each time a new Tracking data is available, with the new data passed as an argument to the function.

Note the type hint indicating that the callback function is passed a dictionary mapping object names to their tracking data. This lets you iterate over all tracked objects and access their data in a structured way.
output
=== Tracking Data (2 objects) ===
Object: windprobe
  Timestamp: 1770394277.5759277s
  Position (world): (0.309, 0.040, 0.300) m
  Rotation (world): w=0.983, x=-0.128, y=-0.130, z=-0.011
  Velocity (world): (X:0.00, Y:0.00, Z:0.00) m/s | Norm : 0.00 m/s
Object: windshaper
  Timestamp: 1770394277.5759277s
  Position (world): (0.000, 0.000, 0.000) m
  Rotation (world): w=1.000, x=0.000, y=0.000, z=0.000
  Velocity (world): (X:0.00, Y:0.00, Z:0.00) m/s | Norm : 0.00 m/s
read_tracking.py
import os
import threading

from dotenv import load_dotenv
from windsuite_sdk import TrackingData, WindsuiteSDK

load_dotenv()

SERVER_IP_ADDRESS = os.getenv("SERVER_IP_ADDRESS", default="localhost")

def on_tracking_data(data: dict[str, TrackingData]) -> None:
    """
    Callback for tracking data.

    Args:
        data: Dictionary mapping object names to their tracking data.

    """
    print(f"=== Tracking Data ({len(data)} objects) ===")

    for object_name, tracking_data in data.items():
        print(f"Object: {object_name}")
        print(f"  Timestamp: {tracking_data.timestamp}s")

        # Position
        pos = tracking_data.position_meters_world_ref
        print(f"  Position (world): ({pos.x:.3f}, {pos.y:.3f}, {pos.z:.3f}) m")

        # Rotation (quaternion)
        rot = tracking_data.rotation_world_ref
        print(
            f"  Rotation (world): w={rot.w:.3f}, x={rot.x:.3f}, y={rot.y:.3f}, z={rot.z:.3f}"
        )

        vel = tracking_data.velocity_mps_world_ref
        norm = (vel.x**2 + vel.y**2 + vel.z**2) ** 0.5
        print(
            f"  Velocity (world): (X:{vel.x:.2f}, Y:{vel.y:.2f}, Z:{vel.z:.2f}) m/s | Norm : {norm:.2f} m/s"
        )

    print()


stop_event = threading.Event()


def main() -> None:
    """Main function to run the WindSuite SDK example."""
    base_url = f"http://{SERVER_IP_ADDRESS}"

    print(f"Connecting to WindSuite server at {base_url}")

    sdk = WindsuiteSDK(base_url=base_url)

    sdk.register_tracking_callback(callback=on_tracking_data)

    sdk.start_communication()

    try:
        freq_hz = 25

        while not stop_event.wait(timeout=(1.0 / freq_hz)):
            # ! DO WHATEVER
            pass

    except KeyboardInterrupt:
        print("\nShutting down...")
        stop_event.set()
    finally:
        sdk.fan_controller.set_intensity(0).apply()

        sdk.cleanup()
        print("SDK stopped")


if __name__ == "__main__":
    main()