Workspace Analyzer Metrics#

The Workspace Analyzer Metrics module provides comprehensive metrics and analysis tools for evaluating robotic workspace characteristics. This module implements various quantitative measures to assess workspace quality, coverage, manipulability, and performance.

Overview#

This module provides three main workspace analysis metrics:

  • ReachabilityMetric: Voxel-based volume and coverage analysis ✅

  • ManipulabilityMetric: Dexterity analysis (heuristic method or with Jacobians) ✅

  • DensityMetric: Point distribution and density analysis ✅

Note: Some advanced features like spatial heatmaps, clustering analysis, and robot-specific helpers are not yet implemented.

Table of Contents#

Metric Types#

1. ReachabilityMetric#

Computes workspace volume and coverage using voxel-based analysis.

import numpy as np
from embodichain.lab.sim.motion.workspace.metrics import ReachabilityMetric

# Basic usage
workspace_points = np.random.uniform(-1, 1, size=(1000, 3))
reachability = ReachabilityMetric()
results = reachability.compute(workspace_points)

print(f"Volume: {results['volume']:.4f} m³")
print(f"Coverage: {results['coverage']:.1f}%")

Returns: volume, coverage percentage, voxel count, bounding box, centroid

2. ManipulabilityMetric#

Computes the Yoshikawa manipulability index sqrt(det(J @ J^T)) from robot Jacobians (or from per-point scores precomputed with embodichain.compute.kinematics.yoshikawa_manipulability). Manipulability cannot be derived from Cartesian points alone, so compute requires either jacobians or manipulability_scores; called with neither it returns {} rather than fabricated statistics.

import numpy as np
from embodichain.lab.sim.motion.workspace.metrics import ManipulabilityMetric

# Provide per-configuration Jacobians (N, 6, dof), e.g. from solver.get_jacobian.
jacobians = np.random.randn(1000, 6, 7)
workspace_points = np.random.uniform(-1, 1, size=(1000, 3))
manipulability = ManipulabilityMetric()
results = manipulability.compute(workspace_points, jacobians=jacobians)

print(f"Mean manipulability: {results['mean_manipulability']:.3f}")
print(f"Valid points: {results['num_valid_points']}")

When the analyzer runs, it computes these scores from the active solver’s Jacobian and stores them as manipulability_scores alongside the results, so callers rarely construct the metric directly.

Returns: mean, std, min, max manipulability; num_valid_points (points above jacobian_threshold); condition-number statistics when isotropy is enabled. If no point clears the threshold, num_valid_points is 0 and the statistics are NaN.

3. DensityMetric#

Computes local point density using radius-based neighborhood analysis.

import numpy as np
from embodichain.lab.sim.motion.workspace.metrics import DensityMetric

# Basic usage
workspace_points = np.random.uniform(-1, 1, size=(1000, 3))
density = DensityMetric()
results = density.compute(workspace_points)

print(f"Mean density: {results['mean_density']:.2f}")

Returns: mean, std, min, max density; distribution histogram (if enabled)

Usage Examples#

Basic Usage#

import numpy as np
from embodichain.lab.sim.motion.workspace.metrics import (
    ReachabilityMetric, ManipulabilityMetric, DensityMetric
)

# Generate sample data
workspace_points = np.random.uniform(-1, 1, size=(5000, 3))
jacobians = np.random.randn(5000, 6, 7)  # per-configuration spatial Jacobians

# Compute all metrics (manipulability requires Jacobians or precomputed scores)
reach_results = ReachabilityMetric().compute(workspace_points)
manip_results = ManipulabilityMetric().compute(workspace_points, jacobians=jacobians)
density_results = DensityMetric().compute(workspace_points)

print(f"Volume: {reach_results['volume']:.4f} m³")
print(f"Mean manipulability: {manip_results['mean_manipulability']:.3f}")
print(f"Mean density: {density_results['mean_density']:.2f}")

With Custom Configuration#

from embodichain.lab.sim.motion.workspace.configs import (
    ReachabilityConfig, DensityConfig
)

# Custom configuration
reach_config = ReachabilityConfig(voxel_size=0.02, compute_coverage=True)
density_config = DensityConfig(radius=0.1, compute_distribution=True)

reachability = ReachabilityMetric(reach_config)
density = DensityMetric(density_config)

reach_results = reachability.compute(workspace_points)
density_results = density.compute(workspace_points)

Configuration#

All metrics can be customized using configuration classes:

from embodichain.lab.sim.motion.workspace.configs import (
    ReachabilityConfig, ManipulabilityConfig, DensityConfig
)

# Reachability configuration
reach_config = ReachabilityConfig(
    voxel_size=0.01,          # Voxel size in meters
    min_points_per_voxel=1,   # Minimum points for occupancy
    compute_coverage=True     # Enable coverage calculation
)

# Manipulability configuration  
manip_config = ManipulabilityConfig(
    jacobian_threshold=0.01,  # Minimum valid manipulability
    compute_isotropy=True     # Enable condition number analysis
)

# Density configuration
density_config = DensityConfig(
    radius=0.05,              # Neighborhood radius
    compute_distribution=True # Enable histogram computation
)

API Reference#

ReachabilityMetric: Returns volume, coverage, num_voxels, bounding_box, centroid

ManipulabilityMetric: Returns mean/std/min/max manipulability, num_valid_points, condition numbers (if available)

DensityMetric: Returns mean/std/min/max density, distribution histogram (if enabled)

Quick Reference#

# Default usage
reachability = ReachabilityMetric()
manipulability = ManipulabilityMetric() 
density = DensityMetric()

# Custom configuration
from embodichain.lab.sim.motion.workspace.configs import ReachabilityConfig
reach_config = ReachabilityConfig(voxel_size=0.02, compute_coverage=True)
reachability = ReachabilityMetric(reach_config)