Source code for rlightning.humanoid.formatter.kinematic_formatter
import torch
import dataclasses
import numpy as np
from rlightning.utils.logger import get_logger
from rlightning.utils.config import Config
from rlightning.humanoid.utils.kinematics_model import KinematicsModel
from .base import Formatter
logger = get_logger(__name__)
[docs]
class KinematicFormatter(Formatter):
[docs]
@dataclasses.dataclass
class Motion:
fps: float
root_pos: np.ndarray
root_rot: np.ndarray
dof_pos: np.ndarray
[docs]
class FormatterCfg(Config):
robot_xml_path: str
height_adjust: bool = False
root_offset: bool = False
quat_order: str = "xyzw"
kinematic_model_device: str = "cpu"
cfg: FormatterCfg
def __init__(self, config: FormatterCfg = None, **kwargs):
super().__init__()
if config is None:
config = self.FormatterCfg(**kwargs)
self.cfg = config
self.quat_order = config.quat_order
self.kinematic_model_device = config.kinematic_model_device
self.kinematic_model = KinematicsModel(
file_path=config.robot_xml_path, device=self.kinematic_model_device
)
self.height_adjust = config.height_adjust
logger.info(f"[Formatter] height_adjust: {self.height_adjust}")
self.root_offset = config.root_offset
logger.info(f"[Formatter] root offset: {config.root_offset}")
[docs]
def format(self, qpos_list, extras):
root_pos = qpos_list[:, :3]
root_rot = qpos_list[:, 3:7] # wxyz
if self.quat_order == "xyzw":
root_rot[:, [0, 1, 2, 3]] = root_rot[:, [1, 2, 3, 0]]
dof_pos = qpos_list[:, 7:]
# num_frames = root_pos.shape[0]
body_pos, _ = self.kinematic_model.forward_kinematics(
torch.from_numpy(root_pos).float().to(self.kinematic_model_device),
torch.from_numpy(root_rot).float().to(self.kinematic_model_device),
torch.from_numpy(dof_pos).float().to(self.kinematic_model_device),
)
if self.height_adjust:
ground_offset = 0.0
lowest_height = torch.min(body_pos[..., 2]).item()
root_pos[:, 2] = root_pos[:, 2] - lowest_height + ground_offset
if self.root_offset:
root_pos[:, :2] -= root_pos[0, :2]
return self.Motion(extras["fps"], root_pos, root_rot, dof_pos)