Source code for rofunc.planning_control.lqt.lqt

"""
    Linear Quadratic Tracker

    Refers to https://gitlab.idiap.ch/rli/robotics-codes-from-scratch by Dr. Sylvain Calinon
"""
from math import factorial
from typing import Tuple

import numpy as np
from omegaconf import DictConfig
from tqdm import tqdm

import rofunc as rf
from rofunc.utils.logger.beauty_logger import beauty_print


[docs]class LQT: def __init__(self, all_points, cfg: DictConfig = None): self.cfg = rf.config.utils.get_config("./planning", "lqt") if cfg is None else cfg self.all_points = all_points self.start_point, self.via_points = self._data_process(all_points) def _data_process(self, data): if len(data[0]) == self.cfg.nbVar: all_points = data else: all_points = np.zeros((len(data), self.cfg.nbVar)) all_points[:, :self.cfg.nbVarPos] = data start_point = all_points[0] via_points = all_points[1:] return start_point, via_points
[docs] def get_matrices(self): self.cfg.nbPoints = len(self.via_points) # Control cost matrix R = np.identity((self.cfg.nbData - 1) * self.cfg.nbVarPos, dtype=np.float32) * self.cfg.rfactor tl = np.linspace(0, self.cfg.nbData, self.cfg.nbPoints + 1) tl = np.rint(tl[1:]).astype(np.int64) - 1 idx_slices = [slice(i, i + self.cfg.nbVar, 1) for i in (tl * self.cfg.nbVar)] # Target mu = np.zeros((self.cfg.nbVar * self.cfg.nbData, 1), dtype=np.float32) # Task precision Q = np.zeros((self.cfg.nbVar * self.cfg.nbData, self.cfg.nbVar * self.cfg.nbData), dtype=np.float32) for i in range(len(idx_slices)): slice_t = idx_slices[i] x_t = self.via_points[i].reshape((self.cfg.nbVar, 1)) mu[slice_t] = x_t Q[slice_t, slice_t] = np.diag( np.hstack((np.ones(self.cfg.nbVarPos), np.zeros(self.cfg.nbVar - self.cfg.nbVarPos)))) return mu, Q, R, idx_slices, tl
[docs] def set_dynamical_system(self): A1d = np.zeros((self.cfg.nbDeriv, self.cfg.nbDeriv), dtype=np.float32) B1d = np.zeros((self.cfg.nbDeriv, 1), dtype=np.float32) for i in range(self.cfg.nbDeriv): A1d += np.diag(np.ones(self.cfg.nbDeriv - i), i) * self.cfg.dt ** i * 1 / factorial(i) B1d[self.cfg.nbDeriv - i - 1] = self.cfg.dt ** (i + 1) * 1 / factorial(i + 1) A = np.kron(A1d, np.identity(self.cfg.nbVarPos, dtype=np.float32)) B = np.kron(B1d, np.identity(self.cfg.nbVarPos, dtype=np.float32)) # Build Sx and Su transfer matrices Su = np.zeros((self.cfg.nbVar * self.cfg.nbData, self.cfg.nbVarPos * (self.cfg.nbData - 1))) Sx = np.kron(np.ones((self.cfg.nbData, 1)), np.eye(self.cfg.nbVar, self.cfg.nbVar)) M = B for i in range(1, self.cfg.nbData): Sx[i * self.cfg.nbVar:self.cfg.nbData * self.cfg.nbVar, :] = np.dot( Sx[i * self.cfg.nbVar:self.cfg.nbData * self.cfg.nbVar, :], A) Su[self.cfg.nbVar * i:self.cfg.nbVar * i + M.shape[0], 0:M.shape[1]] = M M = np.hstack((np.dot(A, M), B)) # [0,nb_state_var-1] return Su, Sx
[docs] def get_u_x(self, mu: np.ndarray, Q: np.ndarray, R: np.ndarray, Su: np.ndarray, Sx: np.ndarray, **kwargs) -> \ Tuple[np.ndarray, np.ndarray]: x0 = self.start_point.reshape((self.cfg.nbVar, 1)) # Equ. 18 u_hat = np.linalg.inv(Su.T @ Q @ Su + R) @ Su.T @ Q @ (mu - Sx @ x0) # x= S_x x_1 + S_u u x_hat = (Sx @ x0 + Su @ u_hat).reshape((-1, self.cfg.nbVar)) return u_hat, x_hat
[docs] def solve(self): beauty_print("Planning smooth trajectory via LQT", type='module') mu, Q, R, idx_slices, tl = self.get_matrices() Su, Sx = self.set_dynamical_system() u_hat, x_hat = self.get_u_x(mu, Q, R, Su, Sx) return u_hat, x_hat, mu, idx_slices
[docs]class LQTHierarchical(LQT): def __init__(self, all_points: np.ndarray, cfg: DictConfig = None, interval: int = 3): super().__init__(all_points, cfg) self.interval = interval
[docs] def solve(self): beauty_print("Planning smooth trajectory via LQT hierarchically", type='module') x_hat_lst = [] for i in tqdm(range(0, len(self.all_points), self.interval)): _, self.via_points = self._data_process(self.all_points[i + 1:i + self.interval + 1]) mu, Q, R, idx_slices, tl = self.get_matrices() Su, Sx = self.set_dynamical_system() u_hat, x_hat = self.get_u_x(mu, Q, R, Su, Sx) self.start_point = x_hat[-1] x_hat_lst.append(x_hat) x_hat = np.array(x_hat_lst).reshape((-1, self.cfg.nbVar)) return u_hat, x_hat, mu, idx_slices
[docs]class LQTBi(LQT): def __init__(self, all_points_l: np.ndarray, all_points_r: np.ndarray, cfg: DictConfig = None): self.controller_l = LQT(all_points_l, cfg) self.controller_r = LQT(all_points_r, cfg)
[docs] def solve(self): beauty_print("Planning smooth bimanual trajectory via LQT", type='module') mu_l, Q, R, idx_slices, tl = self.controller_l.get_matrices() Su, Sx = self.controller_l.set_dynamical_system() u_hat_l, x_hat_l = self.controller_l.get_u_x(mu_l, Q, R, Su, Sx) mu_r, Q, R, idx_slices, tl = self.controller_r.get_matrices() Su, Sx = self.controller_r.set_dynamical_system() u_hat_r, x_hat_r = self.controller_r.get_u_x(mu_r, Q, R, Su, Sx) return u_hat_l, u_hat_r, x_hat_l, x_hat_r, mu_l, mu_r, idx_slices