First Commit

This commit is contained in:
meiqi
2026-03-27 16:10:51 +08:00
commit c45245038f
103 changed files with 10994 additions and 0 deletions

View File

@@ -0,0 +1,178 @@
import numpy as np
from dataclasses import dataclass, field
def rot_x(x: float) -> np.ndarray:
c, s = np.cos(x), np.sin(x)
return np.array([
[1.0, 0.0, 0.0],
[0.0, c, -s ],
[0.0, s, c ],
], dtype=float)
def rot_y(y: float) -> np.ndarray:
c, s = np.cos(y), np.sin(y)
return np.array([
[ c, 0.0, s],
[0.0, 1.0, 0.0],
[-s, 0.0, c],
], dtype=float)
def rot_z(z: float) -> np.ndarray:
c, s = np.cos(z), np.sin(z)
return np.array([
[c, -s, 0.0],
[s, c, 0.0],
[0.0, 0.0, 1.0],
], dtype=float)
def euler_xyz_to_matrix(euler_a: np.ndarray) -> np.ndarray:
# 对应 C++: RotX * RotY * RotZ
return rot_x(euler_a[0]) @ rot_y(euler_a[1]) @ rot_z(euler_a[2])
def clip_vector(v: np.ndarray, lb: float, ub: float) -> np.ndarray:
# 返回裁剪后的新向量(如果你希望原地修改,可用 out=v
return np.clip(v, lb, ub)
def clip_scalar(a: float, lb: float, ub: float) -> float:
return float(min(max(a, lb), ub))
def gait_phase(timer: float,
gait_cycle: float,
left_theta_offset: float,
right_theta_offset: float,
left_phase_ratio: float,
right_phase_ratio: float) -> np.ndarray:
res = np.zeros(6, dtype=float)
left_phase = (timer / gait_cycle + left_theta_offset) - np.floor(timer / gait_cycle + left_theta_offset)
right_phase = (timer / gait_cycle + right_theta_offset) - np.floor(timer / gait_cycle + right_theta_offset)
res[0] = np.sin(2.0 * np.pi * left_phase)
res[1] = np.sin(2.0 * np.pi * right_phase)
res[2] = np.cos(2.0 * np.pi * left_phase)
res[3] = np.cos(2.0 * np.pi * right_phase)
res[4] = left_phase_ratio
res[5] = right_phase_ratio
return res
def fifth_poly(p0: np.ndarray, p0_dot: np.ndarray, p0_dotdot: np.ndarray,
p1: np.ndarray, p1_dot: np.ndarray, p1_dotdot: np.ndarray,
total_time: float, current_time: float):
"""
返回: pd, pd_dot, pd_dotdot
"""
p0 = np.asarray(p0, dtype=float)
p0_dot = np.asarray(p0_dot, dtype=float)
p0_dotdot = np.asarray(p0_dotdot, dtype=float)
p1 = np.asarray(p1, dtype=float)
p1_dot = np.asarray(p1_dot, dtype=float)
p1_dotdot = np.asarray(p1_dotdot, dtype=float)
n = p0.shape[0]
pd = np.zeros(n, dtype=float)
pd_dot = np.zeros(n, dtype=float)
pd_dotdot = np.zeros(n, dtype=float)
t = current_time
time = total_time
if t < total_time:
A = np.array([
[1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 1.0 / 2.0, 0.0, 0.0, 0.0],
[-10.0 / time**3, -6.0 / time**2, -3.0 / (2.0 * time), 10.0 / time**3, -4.0 / time**2, 1.0 / (2.0 * time)],
[15.0 / time**4, 8.0 / time**3, 3.0 / (2.0 * time**2), -15.0 / time**4, 7.0 / time**3, -1.0 / time**2],
[-6.0 / time**5, -3.0 / time**4, -1.0 / (2.0 * time**3), 6.0 / time**5, -3.0 / time**4, 1.0 / (2.0 * time**3)],
], dtype=float)
for i in range(n):
x0 = np.array([
p0[i], p0_dot[i], p0_dotdot[i],
p1[i], p1_dot[i], p1_dotdot[i]
], dtype=float)
a = A @ x0
pd[i] = a[0] + a[1] * t + a[2] * t**2 + a[3] * t**3 + a[4] * t**4 + a[5] * t**5
pd_dot[i] = a[1] + 2.0 * a[2] * t + 3.0 * a[3] * t**2 + 4.0 * a[4] * t**3 + 5.0 * a[5] * t**4
pd_dotdot[i] = 2.0 * a[2] + 6.0 * a[3] * t + 12.0 * a[4] * t**2 + 20.0 * a[5] * t**3
else:
pd = p1.copy()
pd_dot = p1_dot.copy()
pd_dotdot = p1_dotdot.copy()
return pd, pd_dot, pd_dotdot
@dataclass
class LowPassFilter:
cut_off_freq: float
damp_ratio: float
d_time: float
n_filter: int
dT: float = field(init=False)
sigIn_1: np.ndarray = field(init=False)
sigIn_2: np.ndarray = field(init=False)
sigOut_1: np.ndarray = field(init=False)
sigOut_2: np.ndarray = field(init=False)
a2: float = field(init=False)
a1: float = field(init=False)
a0: float = field(init=False)
b2: float = field(init=False)
b1: float = field(init=False)
b0: float = field(init=False)
def __post_init__(self):
self.dT = self.d_time
self.sigIn_1 = np.zeros(self.n_filter, dtype=float)
self.sigIn_2 = np.zeros(self.n_filter, dtype=float)
self.sigOut_1 = np.zeros(self.n_filter, dtype=float)
self.sigOut_2 = np.zeros(self.n_filter, dtype=float)
freq_in_rad = 2.0 * np.pi * self.cut_off_freq
c = 2.0 / self.dT
sqr_c = c * c
sqr_w = freq_in_rad * freq_in_rad
self.b2 = sqr_c + 2.0 * self.damp_ratio * freq_in_rad * c + sqr_w
self.b1 = -2.0 * (sqr_c - sqr_w)
self.b0 = sqr_c - 2.0 * self.damp_ratio * freq_in_rad * c + sqr_w
self.a2 = sqr_w
self.a1 = 2.0 * sqr_w
self.a0 = sqr_w
self.a2 /= self.b2
self.a1 /= self.b2
self.a0 /= self.b2
self.b1 /= self.b2
self.b0 /= self.b2
self.b2 = 1.0
def m_filter(self, sig_in: np.ndarray) -> np.ndarray:
sig_in = np.asarray(sig_in, dtype=float)
sig_out = (
self.a2 * sig_in
+ self.a1 * self.sigIn_1
+ self.a0 * self.sigIn_2
- self.b1 * self.sigOut_1
- self.b0 * self.sigOut_2
)
self.sigIn_2 = self.sigIn_1
self.sigIn_1 = sig_in
self.sigOut_2 = self.sigOut_1
self.sigOut_1 = sig_out
return sig_out