11from collections import deque
22
3- import einops
4- import mujoco
53import numpy as np
6- from gymnasium .envs .mujoco .mujoco_rendering import MujocoRenderer
7- from numpy .typing import NDArray
8- from scipy .spatial .transform import Rotation as R
94
105from crazyflow .constants import GRAVITY , MASS
116from crazyflow .sim import Physics , Sim
7+ from crazyflow .sim .visualize import draw_line
128
139
1410def main ():
@@ -18,60 +14,23 @@ def main():
1814 fps = 60
1915 cmd = np .zeros ((sim .n_worlds , sim .n_drones , 4 ))
2016 cmd [..., 0 ] = MASS * GRAVITY * 1.2
17+ rgbas = np .random .default_rng (0 ).uniform (0 , 1 , (n_drones , 4 ))
18+ rgbas [..., 3 ] = 1.0
2119
22- pos = deque (maxlen = 16 )
23- rot = deque (maxlen = 15 )
20+ pos = deque (maxlen = 15 )
2421
2522 for i in range (int (5 * sim .control_freq )):
2623 sim .attitude_control (cmd )
2724 sim .step (sim .freq // sim .control_freq )
2825 if i % 20 == 0 :
2926 pos .append (sim .data .states .pos [0 , :])
30- if len (pos ) > 1 :
31- rot .append (rotation_matrix_from_points (pos [- 2 ], pos [- 1 ]))
3227 if ((i * fps ) % sim .control_freq ) < fps :
33- render_traces (sim .viewer , pos , rot )
28+ lines = np .array (pos )
29+ for i in range (n_drones ):
30+ draw_line (sim , lines [:, i , :], rgbas [i , :], start_size = 0.3 , end_size = 3.0 )
3431 sim .render ()
3532 sim .close ()
3633
3734
38- def render_traces (viewer : MujocoRenderer , pos : deque [NDArray ], rot : deque [R ]):
39- """Render traces of the drone trajectories."""
40- if len (pos ) < 2 or viewer is None :
41- return
42-
43- n_trace , n_drones = len (rot ), len (pos [0 ])
44- pos = np .array (pos )
45- sizes = np .zeros ((n_trace , n_drones , 3 ))
46- rgbas = np .zeros ((n_trace , n_drones , 4 ))
47- sizes [..., 2 ] = np .linalg .norm (pos [1 :] - pos [:- 1 ], axis = - 1 )
48- sizes [..., :2 ] = np .linspace (1.0 , 5.0 , n_trace )[:, None , None ]
49- mats = np .zeros ((n_trace , n_drones , 9 ))
50- for i in range (n_trace ):
51- mats [i , :] = einops .rearrange (rot [i ].as_matrix (), "d n m -> d (n m)" )
52- rgbas = np .zeros ((n_trace , n_drones , 4 ))
53- np .random .seed (0 ) # Ensure consistent colors
54- rgbas [..., :3 ] = np .random .uniform (0 , 1 , (1 , n_drones , 3 ))
55- rgbas [..., 3 ] = np .linspace (0 , 1 , n_trace )[:, None ]
56-
57- for i in range (n_trace ):
58- for j in range (n_drones ):
59- viewer .viewer .add_marker (
60- type = mujoco .mjtGeom .mjGEOM_LINE ,
61- size = sizes [i , j ],
62- pos = pos [i ][j ],
63- mat = mats [i , j ],
64- rgba = rgbas [i , j ],
65- )
66-
67-
68- def rotation_matrix_from_points (p1 : NDArray , p2 : NDArray ) -> R :
69- z_axis = (v := p2 - p1 ) / np .linalg .norm (v , axis = - 1 , keepdims = True )
70- random_vector = np .random .rand (* z_axis .shape )
71- x_axis = (v := np .cross (random_vector , z_axis )) / np .linalg .norm (v , axis = - 1 , keepdims = True )
72- y_axis = np .cross (z_axis , x_axis )
73- return R .from_matrix (np .stack ((x_axis , y_axis , z_axis ), axis = - 1 ))
74-
75-
7635if __name__ == "__main__" :
7736 main ()
0 commit comments