Skip to content

Commit fbf3f1e

Browse files
committed
Add synthetic trajectory generator.
1 parent 7802806 commit fbf3f1e

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Artificial flight and walking trajectories for testing and inference."""
2+
3+
import numpy as np
4+
5+
from dm_control import mujoco
6+
7+
from flybody.quaternions import mult_quat
8+
9+
10+
def constant_speed_trajectory(n_steps: int,
11+
speed: float,
12+
yaw_speed: float = 0,
13+
init_pos: tuple[float] = (0, 0, 0.1278),
14+
init_heading: float = 0,
15+
body_rot_angle_y: float = 0.,
16+
body_rot_angle_x: float = 0.,
17+
control_timestep: float = 0.002):
18+
"""Generate a simple constant-speed trajectory, either walking/flying
19+
straight or turning.
20+
21+
Args:
22+
n_steps: Number of timesteps.
23+
speed: Trajectory speed, cm/s.
24+
yaw_speed: Turning speed, can be zero, rad/s.
25+
Positive: counter-clockwise turning about z-axis.
26+
init_pos: Initial xyz position.
27+
init_heading: Angle of initial fly heading, rad.
28+
body_rot_angle_y: Body rotation angle around y-axis, degrees.
29+
Zero: horizontal body. Positive: nose down.
30+
body_rot_angle_x: Body rotation angle around x-axis, degrees.
31+
Zero horizontal wing plane. Positive: right bank.
32+
control_timestep: Environment control timestep, seconds.
33+
34+
Returns:
35+
qpos: Full trajectory qpos, including quaternion, (n_steps, 7).
36+
qvel: Full qvel, including quaternion velocity, (n_steps, 6).
37+
"""
38+
39+
qpos = np.zeros((n_steps, 7))
40+
qvel = np.zeros((n_steps, 6))
41+
qpos[0, :3] = init_pos
42+
qpos[:, 2] = init_pos[2] # Fixed height.
43+
y_angle = np.deg2rad(body_rot_angle_y) # Rotation angle around y-axis.
44+
x_angle = np.deg2rad(body_rot_angle_x) # Rotation angle around x-axis.
45+
# Possible initial y-rotation.
46+
qpos[0, 3:] = [np.cos(y_angle/2), 0., np.sin(y_angle/2), 0.]
47+
# Possible initial x-rotation.
48+
qpos[0, 3:] = mult_quat(
49+
np.array([np.cos(x_angle/2), np.sin(x_angle/2), 0., 0]), qpos[0, 3:])
50+
# Possible initial z-rotation (heading).
51+
dquat = np.array(
52+
[np.cos(init_heading/2), 0, 0, np.sin(init_heading/2)])
53+
qpos[0, 3:] = mult_quat(dquat, qpos[0, 3:])
54+
qvel[0, :2] = speed * np.array(
55+
[np.cos(init_heading), np.sin(init_heading)])
56+
# Quat velocity.
57+
dtheta = yaw_speed * control_timestep
58+
dquat = np.array([np.cos(dtheta/2), 0, 0, np.sin(dtheta/2)])
59+
vel = np.zeros(3)
60+
mujoco.mju_quat2Vel(vel, dquat, 1)
61+
qvel[:, 3:] = vel
62+
63+
M = np.array([[np.cos(dtheta), -np.sin(dtheta)],
64+
[np.sin(dtheta), np.cos(dtheta)]])
65+
for i in range(1, n_steps):
66+
qvel[i, :2] = M @ qvel[i-1, :2]
67+
qpos[i, :2] = qpos[i-1, :2] + qvel[i, :2] * control_timestep
68+
qpos[i, 3:] = mult_quat(dquat, qpos[i-1, 3:])
69+
70+
return qpos, qvel

0 commit comments

Comments
 (0)