Source code for kimodo.motion_rep.feet
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Foot contact detection from joint positions and velocities."""
import torch
from ..tools import ensure_batched
[docs]
@ensure_batched(positions=4, velocity=4)
def foot_detect_from_pos_and_vel(
positions: torch.Tensor,
velocity: torch.Tensor,
skeleton,
vel_thres: float,
height_thresh: float,
) -> torch.Tensor:
"""Compute foot contact labels using heuristics combining joint height and velocities.
Args:
positions (torch.Tensor): [X, T, J, 3] global joint positions
velocity (torch.Tensor): [X, T, J, 3] velocities (already padded correctly), already multiplied by 1 / dt
vel_thres (float): threshold for joint velocity
height_thresh (float): threshold for joint height
Returns:
torch.Tensor: [X, T, 4] contact labels for left and right foot joints
(heel/toe order follows the skeleton joint index definition), where
``1`` denotes contact.
"""
device = positions.device
# Use at most 2 foot joints per side (ankle + toe); SOMA77 defines a
# third end-effector (ToeEnd) that SOMA30 and other skeletons omit.
fid_l = skeleton.left_foot_joint_idx[:2]
fid_r = skeleton.right_foot_joint_idx[:2]
velfactor, heightfactor = (
torch.tensor([vel_thres, vel_thres], device=device),
torch.tensor([height_thresh, height_thresh], device=device),
)
feet_l_v = torch.linalg.norm(velocity[:, :, fid_l], axis=-1)
feet_l_h = positions[:, :, fid_l, 1]
feet_l = torch.logical_and(
feet_l_v < velfactor,
feet_l_h < heightfactor,
).to(positions.dtype)
feet_r_v = torch.linalg.norm(velocity[:, :, fid_r], axis=-1)
feet_r_h = positions[:, :, fid_r, 1]
feet_r = torch.logical_and(
feet_r_v < velfactor,
feet_r_h < heightfactor,
).to(positions.dtype)
foot_contacts = torch.cat((feet_l, feet_r), axis=-1)
return foot_contacts