Source code for concepts.simulator.sapien2.controllers.joint_trajectory_controller

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File   : joint_trajectory_controller.py
# Author : Jiayuan Mao
# Email  : maojiayuan@gmail.com
# Date   : 07/29/2024
#
# This file is part of Project Concepts.
# Distributed under terms of the MIT license.

import numpy as np
from sapien.core import Actor
from concepts.math.rotationlib_wxyz import quat_diff_in_axis_angle


[docs] class JointTrajectoryProportionalController(object):
[docs] def __init__( self, actor: Actor, p_array: np.ndarray, q_array: np.ndarray, gain: float, coef: float = 1 ): self.actor = actor self.p_array = p_array self.q_array = q_array self.target_quat_wxyz = actor.get_pose().q self.gain = gain self.coef = coef self.num_steps = len(p_array) - 1 self.current_t = 0
[docs] def get_projection_t(self, current_p, current_q) -> int: current_p = np.array(current_p) current_q = np.array(current_q) start = max(self.current_t - 5, 0) end = min(self.current_t + 6, self.num_steps) p_dist = np.sum((self.p_array[start:end] - current_p)**2, axis=1) # TODO: find a more reasonable way to calculate q_dist q_dist = np.sum((self.q_array[start:end] - current_q)**2, axis=1) idx = np.argmin(p_dist + self.coef * q_dist) # print(p_dist[idx], q_dist[idx]) t = idx + start return t
[docs] def get_desired_velocities(self, t=None) -> tuple[np.ndarray, np.ndarray]: current_p = self.actor.get_pose().p current_q = self.actor.get_pose().q if t is None: t = self.get_projection_t(current_p, current_q) self.current_t = t target_t = np.maximum(0, np.minimum(t + 1, self.num_steps)) current_target_position = self.p_array[target_t] current_target_orientation = self.q_array[target_t] velocity = self.gain * (current_target_position - current_p) angular_velocity = self.gain * quat_diff_in_axis_angle(current_target_orientation, current_q) return velocity, angular_velocity
[docs] def set_velocities(self, contact=None): velocity, angular_velocity = self.get_desired_velocities() if contact is not None: contact_point = contact['point'] contact_normal = contact['normal'] actor_center = self.actor.get_pose().p velocity, angular_velocity = self.get_desired_velocities(t=self.current_t + 1) vel_contact_point = velocity + _cross(angular_velocity, contact_point - actor_center) vel_contact_normal = np.dot(vel_contact_point, contact_normal) * contact_normal print(velocity, vel_contact_point, vel_contact_normal) velocity = velocity - vel_contact_normal print(velocity) self.actor.set_velocity(velocity) self.actor.set_angular_velocity(angular_velocity)
[docs] def get_current_t(self) -> int: return self.get_projection_t(self.actor.get_pose().p, self.actor.get_pose().q)
def _cross(x: np.ndarray, y: np.ndarray) -> np.ndarray: # Workaround for the bug in PyCharm type hinting return np.cross(x, y)