Guides

Tutorial

Complete walkthrough of motion retargeting from C3D data to joint angles and outputs.

This tutorial walks you through the complete workflow of taking a C3D motion capture file and retargeting it onto a 3D character using the MyoSapiens Python SDK.

Prerequisites

Before starting, make sure you have:

If you're new to Myo, read the Introduction first to understand key concepts like assets and jobs.

Step 1: Initialize the Client

Start by importing the SDK and initializing the client. Make sure you have your API key set as an environment variable (see Installation Guide):

Python
import os
from myosdk import Client

# Initialize the client
client = Client(api_key=os.getenv("MYO_API_KEY"))

Step 2: Run a Retarget Job (Simplest Path)

The simplest way to retarget is to pass file paths directly. The SDK uploads them, runs the job, and waits for completion:

Python
# One call: upload, process, wait, and optionally download
result = client.retarget(
    tracker="path/to/your/motion.c3d",
    markerset="path/to/your/markerset.xml",
    export_glb=True,       # Optional: get motion as GLB
    stream_status=True,    # Optional: print status updates
    output_dir="out/",     # Optional: auto-download when complete
)

print(f"Job completed! Processing time: {result.processing_time_seconds}s")

If you didn't use output_dir, download the outputs:

Python
# Download all outputs to a directory
result.download_all("out/")

# Or download individual files
result.download_qpos("out/qpos.parquet")
result.download_xpos("out/xpos.parquet")
result.download_model("out/model.mjb")
result.download_motion("out/motion.glb")  # Only if export_glb=True

See File Formats for details on each output (qpos = joint angles, xpos = joint positions in 3D space, model = MuJoCo model, motion = GLB).

Step 3: Alternative — More Control with create_retarget_job

If you want to stream status or manage the job manually:

Python
# Block by default but stream status
result = client.create_retarget_job(
    tracker="path/to/motion.c3d",
    markerset="path/to/markerset.xml",
    export_glb=True,
    stream_status=True,
    on_status=lambda e: print(f"Status: {e.status}"),
)
result.download_all("out/")

Non-blocking (manual control):

Python
job = client.create_retarget_job(
    tracker="path/to/motion.c3d",
    markerset="path/to/markerset.xml",
    export_glb=True,
    block_until_complete=False,
)

for event in job.stream():
    print(f"Status: {event.status}")

result = job.wait(timeout=600)
result.download_all("out/")

Step 4: Use the Outputs

The outputs are Parquet (qpos, xpos), MuJoCo binary (model), and optionally GLB (motion). Example with Parquet:

Python
import pandas as pd

# Load qpos (joint angles)
qpos_df = pd.read_parquet("out/qpos.parquet")
print(f"qpos: {qpos_df.shape}")

# Load xpos (joint positions in 3D space)
xpos_df = pd.read_parquet("out/xpos.parquet")
print(f"xpos: {xpos_df.shape}")

See File Formats for full details on output structure and usage.

Complete Example with Error Handling

Here's the full script with error handling:

Python
import os
from myosdk import Client
from myosdk.exceptions import ApiError, InsufficientCreditsError

client = Client(api_key=os.getenv("MYO_API_KEY"))

try:
    print("Creating retarget job...")
    result = client.retarget(
        tracker="motion.c3d",
        markerset="markerset.xml",
        export_glb=True,
        stream_status=True,
    )
    print(f"Job completed! Processing time: {result.processing_time_seconds}s")

    print("Downloading outputs...")
    result.download_all("out/")
    print("Done! Outputs saved to out/")

except InsufficientCreditsError as e:
    print(f"Insufficient credits: {e}")
except ApiError as e:
    print(f"API error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")
finally:
    client.close()

Next Steps

Now that you've completed your first retargeting: