DIM-1842 drone simulator using MuJoCo simulator and Crazyflie 2#2046
DIM-1842 drone simulator using MuJoCo simulator and Crazyflie 2#2046Shreyas0812 wants to merge 17 commits into
Conversation
…s ReplanningAStar (Same as g1) for planning -- yet to be tested
…drone_rerun_blueprint instead of g1 -- Inspired from unitree_g1_primitive_no_nav
…eded, will decided to remove later
…ing the file, updating imports, continuing mujoco_connection for drone
…l -- will create one later if required
…g now. Ran test all blueprints for populating all_blueprints. Added the bitcraze_crazyflie_2 in model and a new class in policy
…e.start(self) -- need to verify if this is temporary solution, refactoring might be needed
…ode -- added drone to mujoco_process -- fixed Drone Controller policy
…merge (same as g1)
Greptile SummaryAdds a MuJoCo-backed Crazyflie 2 drone simulator by introducing
Confidence Score: 3/5The blueprint wiring and shared-memory plumbing look solid, but the drone control law may be fundamentally wrong for the menagerie actuator layout, causing the drone to crash on first simulation run. The DroneController sets only one of the four ctrl slots to the hover thrust value. If the cf2 model uses per-rotor thrusts (the standard menagerie layout), the other three rotors receive near-zero thrust and the drone flips immediately. This needs to be verified against the actual XML before the simulation can be tested at all. dimos/simulation/mujoco/policy.py — the hover thrust and moment assignment logic in DroneController.get_control needs validation against the cf2 actuator layout. Important Files Changed
Reviews (1): Last reviewed commit: "vis moved to vis_module in main merge --..." | Re-trigger Greptile |
| from dimos.robot.unitree.mujoco_connection import MujocoConnection | ||
|
|
||
| self.connection = MujocoConnection(self.config.g) |
There was a problem hiding this comment.
The
MujocoConnection is imported at the module level (line 23) and again with a redundant local import inside start(). The local import serves no purpose since the top-level import is unconditional, and having two imports of the same name in the same scope can silently shadow the outer binding if the inner one ever changes. Remove the duplicate.
| from dimos.robot.unitree.mujoco_connection import MujocoConnection | |
| self.connection = MujocoConnection(self.config.g) | |
| self.connection = MujocoConnection(self.config.g) |
| class DroneController(): | ||
| def __init__( | ||
| self, | ||
| input_controller: InputController, | ||
| **kwargs: Any, | ||
| ) -> None: | ||
| self._input_controller = input_controller | ||
|
|
||
| def get_obs(self, model: mujoco.MjModel, data: mujoco.MjData) -> np.ndarray[Any, Any]: | ||
| command = self._input_controller.get_command() | ||
| return command.astype(np.float32) | ||
|
|
||
| def get_control(self, model: mujoco.MjModel, data: mujoco.MjData) -> None: | ||
| command = self._input_controller.get_command() | ||
| forward = float(command[0]) | ||
| lateral = float(command[1]) | ||
| yaw = float(command[2]) | ||
| data.ctrl[0] = _DRONE_HOVER_THRUST | ||
| data.ctrl[1] = lateral * _DRONE_MOMENT_SCALE # x_moment (roll) | ||
| data.ctrl[2] = -forward * _DRONE_MOMENT_SCALE # y_moment (pitch) | ||
| data.ctrl[3] = -yaw * _DRONE_MOMENT_SCALE # z_moment (yaw) No newline at end of file |
There was a problem hiding this comment.
DroneController does not inherit from OnnxController, but load_model annotates the policy variable as OnnxController. The case "bitcraze_crazyflie_2" branch then assigns a DroneController instance to that annotated variable, which is a static type error. A strict type checker (mypy/pyright) will flag this. Consider having DroneController inherit from an abstract base that both OnnxController and DroneController satisfy, or introduce a Protocol for get_control/get_obs.
| ReplanningAStarPlanner.blueprint(), | ||
| ) | ||
|
|
||
| __all__ = ["drone_basic_sim"] No newline at end of file |
| ) | ||
| ) | ||
|
|
||
| __all__ = ["drone_primitive_no_nav"] No newline at end of file |
| ip: str = Field(default_factory=lambda m: m["g"].robot_ip) | ||
|
|
There was a problem hiding this comment.
DroneSimConfig.ip is declared but never read anywhere in DroneSimConnection — the sim connection passes self.config.g (the GlobalConfig) directly to MujocoConnection, and robot_ip is only used by MAVLink-based hardware connections. If the field is intentionally reserved for future use, a comment would help; otherwise it can be removed to avoid confusion.
| def get_control(self, model: mujoco.MjModel, data: mujoco.MjData) -> None: | ||
| command = self._input_controller.get_command() | ||
| forward = float(command[0]) | ||
| lateral = float(command[1]) | ||
| yaw = float(command[2]) | ||
| data.ctrl[0] = _DRONE_HOVER_THRUST | ||
| data.ctrl[1] = lateral * _DRONE_MOMENT_SCALE # x_moment (roll) | ||
| data.ctrl[2] = -forward * _DRONE_MOMENT_SCALE # y_moment (pitch) | ||
| data.ctrl[3] = -yaw * _DRONE_MOMENT_SCALE # z_moment (yaw) No newline at end of file |
There was a problem hiding this comment.
Only
data.ctrl[0] receives the full hover thrust, while data.ctrl[1:3] are assigned the raw moment-scale values (lateral * 0.005, -forward * 0.005, -yaw * 0.005). If the bitcraze_crazyflie_2 MuJoCo model exposes four independent per-rotor thrust actuators (which is the default layout in the MuJoCo Menagerie), then all four ctrl entries need the base hover thrust, and the moments are applied as differential offsets on top. With the current code, rotors 1–3 receive near-zero thrust at idle, causing the drone to flip immediately.
Problem
No way to test drone software stack without physical hardware. Adds a simulation connection for the Bitcraze Crazyflie 2 using MuJoCo, mirroring the existing Unitree Go1/G1 sim path.
Closes DIM-1842
Solution
How to Test
dimos --simulation run drone-basic-sim
Use WASD to move the drone. W/S = forward/back, A/D = left/right, Q/E = yaw.
Closes DIM-1842