diff --git a/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch b/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch
index 309a20155..f1610995b 100644
--- a/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch
+++ b/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch
@@ -10,10 +10,15 @@
+
-
-
+
+
+
+
+
+
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Camera.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Camera.py
new file mode 100644
index 000000000..26bdc5ebe
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Camera.py
@@ -0,0 +1,59 @@
+import mujoco
+import numpy as np
+
+
+class Camera:
+ """Represents a camera in the MuJoCo simulation, providing image rendering capabilities."""
+
+ def __init__(self, model: mujoco.MjModel, data: mujoco.MjData, name: str, width: int = 800, height: int = 600):
+ self.model: mujoco.MjModel = model
+ self.data: mujoco.MjData = data
+ self.name: str = name
+ self.instance = model.camera(name)
+ self.width: int = width
+ self.height: int = height
+ self.renderer = mujoco.Renderer(self.model, height=self.height, width=self.width)
+
+ @property
+ def fov(self) -> float:
+ """Returns the camera's horizontal field of view in radians."""
+ if (hasattr(self, "_fov") and self._fov is not None):
+ return self._fov
+
+ # MuJoCo uses fovy (vertical field of view in degrees)
+ fovy_deg = (
+ self.instance.fovy[0]
+ if hasattr(self.instance.fovy, "__iter__")
+ else self.instance.fovy
+ )
+ fovy_rad = np.deg2rad(fovy_deg)
+
+ # Convert vertical FOV to horizontal FOV using aspect ratio
+ aspect_ratio = self.width / self.height
+ fovx_rad = 2 * np.arctan(np.tan(fovy_rad / 2) * aspect_ratio)
+
+ self._fov = fovx_rad
+ return self._fov
+
+ def render(self) -> bytes:
+ """
+ Renders and returns the camera image as raw bytes (BGRA format).
+ Returns Raw image data in BGRA8 format for ROS Image messages.
+ """
+ # Update renderer with current scene
+ self.renderer.update_scene(self.data, camera=self.name)
+
+ # Render the image - returns RGB by default
+ rgb_array = self.renderer.render()
+
+ # Convert RGB to BGRA (standard for ROS Image messages)
+ # MuJoCo returns RGB uint8 array of shape (height, width, 3)
+ # We need to add alpha channel and swap R and B
+ height, width, _ = rgb_array.shape
+ bgra_array = np.zeros((height, width, 4), dtype=np.uint8)
+ bgra_array[:, :, 0] = rgb_array[:, :, 2] # B
+ bgra_array[:, :, 1] = rgb_array[:, :, 1] # G
+ bgra_array[:, :, 2] = rgb_array[:, :, 0] # R
+ bgra_array[:, :, 3] = 255 # A (fully opaque)
+
+ return bgra_array.tobytes()
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Joint.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Joint.py
new file mode 100644
index 000000000..04dfb05bb
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Joint.py
@@ -0,0 +1,39 @@
+import mujoco
+
+
+class Joint:
+ """Represents a single controllable joint and associated actuator in the MuJoCo simulation."""
+
+ def __init__(
+ self,
+ model: mujoco.MjModel,
+ data: mujoco.MjData,
+ ros_name: str,
+ name: str | None = None,
+ ):
+ self.model: mujoco.MjModel = model
+ self.data: mujoco.MjData = data
+ self.ros_name: str = ros_name
+ self.name: str = name if name is not None else ros_name
+ self.joint_instance: int = model.joint(self.name)
+ self.actuator_instance: int = model.actuator(self.name)
+
+ @property
+ def position(self) -> float:
+ """Gets the current joint position (angle) in radians."""
+ return self.data.qpos[self.joint_instance.qposadr[0]]
+
+ @position.setter
+ def position(self, value: float) -> None:
+ """Sets the position target for the joint's position actuator."""
+ self.data.ctrl[self.actuator_instance.id] = value
+
+ @property
+ def velocity(self) -> float:
+ """Gets the current joint velocity in rad/s."""
+ return self.data.qvel[self.joint_instance.dofadr[0]]
+
+ @property
+ def effort(self) -> float:
+ """Gets the current effort (force/torque) applied by the position actuator."""
+ return self.data.actuator_force[self.actuator_instance.id]
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Robot.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Robot.py
new file mode 100644
index 000000000..c3e38c699
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Robot.py
@@ -0,0 +1,78 @@
+import mujoco
+
+from bitbots_mujoco_sim.Camera import Camera
+from bitbots_mujoco_sim.Joint import Joint
+from bitbots_mujoco_sim.Sensor import Sensor
+
+
+class Robot:
+ """Represents the robot, holding all its components like the camera, joints, and sensors."""
+
+ def __init__(self, model: mujoco.MjModel, data: mujoco.MjData):
+ self.camera = Camera(model, data, name="head_camera")
+ self.joints = RobotJoints(
+ [
+ # --- Right Leg ---
+ Joint(model, data, ros_name="RHipYaw"),
+ Joint(model, data, ros_name="RHipRoll"),
+ Joint(model, data, ros_name="RHipPitch"),
+ Joint(model, data, ros_name="RKnee"),
+ Joint(model, data, ros_name="RAnklePitch"),
+ Joint(model, data, ros_name="RAnkleRoll"),
+ # --- Left Leg ---
+ Joint(model, data, ros_name="LHipYaw"),
+ Joint(model, data, ros_name="LHipRoll"),
+ Joint(model, data, ros_name="LHipPitch"),
+ Joint(model, data, ros_name="LKnee"),
+ Joint(model, data, ros_name="LAnklePitch"),
+ Joint(model, data, ros_name="LAnkleRoll"),
+ # --- Arms ---
+ Joint(model, data, ros_name="RShoulderPitch"),
+ Joint(model, data, ros_name="RShoulderRoll"),
+ Joint(model, data, ros_name="RElbow"),
+ Joint(model, data, ros_name="LShoulderPitch"),
+ Joint(model, data, ros_name="LShoulderRoll"),
+ Joint(model, data, ros_name="LElbow"),
+ # --- Head ---
+ Joint(model, data, ros_name="HeadPan"),
+ Joint(model, data, ros_name="HeadTilt"),
+ ]
+ )
+ self.sensors = RobotSensors(
+ [
+ # IMU Sensors
+ Sensor(model, data, name="gyro", ros_name="IMU_gyro"),
+ Sensor(model, data, name="accelerometer", ros_name="IMU_accelerometer"),
+ Sensor(model, data, name="orientation", ros_name="IMU_orientation",), # Global orientation quaternion
+ Sensor(model, data, name="position", ros_name="IMU_position"), # Global position vector
+ # Foot Sensors
+ Sensor(model, data, name="l_foot_pos", ros_name="left_foot_position"),
+ Sensor(model, data, name="r_foot_pos", ros_name="right_foot_position"),
+ Sensor(model, data, name="l_foot_global_linvel", ros_name="left_foot_velocity"),
+ Sensor(model, data, name="r_foot_global_linvel", ros_name="right_foot_velocity"),
+ ]
+ )
+
+
+class RobotSensors(list[Sensor]):
+ """A list of Robot Sensors with additional helper methods."""
+
+ def get(self, name: str) -> Joint:
+ """Finds and returns a specific joint by its ROS name."""
+ return next(filter(lambda joint: joint.ros_name == name, self))
+
+ @property
+ def gyro(self) -> Sensor:
+ return self.get("IMU_gyro")
+
+ @property
+ def accelerometer(self) -> Sensor:
+ return self.get("IMU_accelerometer")
+
+
+class RobotJoints(list[Joint]):
+ """A list of Robot Joints with additional helper methods."""
+
+ def get(self, name: str) -> Joint:
+ """Finds and returns a specific joint by its ROS name."""
+ return next(filter(lambda joint: joint.ros_name == name, self))
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Sensor.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Sensor.py
new file mode 100644
index 000000000..e787e541f
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Sensor.py
@@ -0,0 +1,28 @@
+import mujoco
+import numpy as np
+
+
+class Sensor:
+ """Represents a single sensor, providing a clean interface to its value."""
+
+ def __init__(self, model: mujoco.MjModel, data: mujoco.MjData, name: str, ros_name: str):
+ self._data = data
+ self.ros_name: str = ros_name
+ self.instance: int = model.sensor(name)
+ self.id: int = self.instance.id
+
+ @property
+ def data(self) -> np.ndarray:
+ """Gets the current sensor reading from sensordata array."""
+ return self._data.sensordata[self.adr : self.adr + self.dim]
+
+ @property
+ def adr(self) -> int:
+ """Gets the address of the sensor data in sensordata array."""
+ return int(self.instance.adr)
+
+ @property
+ def dim(self) -> int:
+ """Gets the dimension of the sensor data."""
+ return int(self.instance.dim)
+
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Simulation.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Simulation.py
new file mode 100644
index 000000000..e9dae7040
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/Simulation.py
@@ -0,0 +1,160 @@
+import time
+import math
+
+import mujoco
+from ament_index_python.packages import get_package_share_directory
+from mujoco import viewer
+from rclpy.node import Node
+from rclpy.time import Time
+from rosgraph_msgs.msg import Clock
+from sensor_msgs.msg import CameraInfo, Imu, JointState, Image
+
+from bitbots_msgs.msg import JointCommand
+from bitbots_mujoco_sim.Robot import Robot
+
+
+class Simulation(Node):
+ """Manages the MuJoCo simulation state and its components."""
+
+ def __init__(self):
+ super().__init__("sim_interface")
+ package_path = get_package_share_directory("bitbots_mujoco_sim")
+ self.model: mujoco.MjModel = mujoco.MjModel.from_xml_path(package_path + "/xml/adult_field.xml")
+ self.data: mujoco.MjData = mujoco.MjData(self.model)
+ self.robot: Robot = Robot(self.model, self.data)
+
+ self.time = 0.0
+ self.time_message = Time(seconds=0, nanoseconds=0).to_msg()
+ self.timestep = self.model.opt.timestep
+ self.step_number = 0
+ self.clock_publisher = self.create_publisher(Clock, "clock", 1)
+
+ self.js_publisher = self.create_publisher(JointState, "joint_states", 1)
+ self.create_subscription(JointCommand, "DynamixelController/command", self.joint_command_callback, 1)
+
+ self.imu_frame_id = self.get_parameter_or("imu_frame", "imu_frame")
+ self.imu_publisher = self.create_publisher(Imu, "imu/data_raw", 1)
+
+ self.camera_active = True
+ self.camera_optical_frame_id = self.get_parameter_or("camera_optical_frame", "camera_optical_frame")
+ self.camera_publisher = self.create_publisher(Image, "camera/image_proc", 1)
+ self.camera_info_publisher = self.create_publisher(CameraInfo, "camera/camera_info", 1)
+
+ self.events = {
+ "clock": {"frequency": 1, "handler": self.publish_clock_event},
+ "joint_states": {"frequency": 3, "handler": self.publish_ros_joint_states_event},
+ "imu": {"frequency": 3, "handler": self.publish_imu_event},
+ "camera": {"frequency": 24, "handler": self.publish_camera_event},
+ }
+
+ def run(self) -> None:
+ print("Starting simulation viewer...")
+ with viewer.launch_passive(self.model, self.data) as view:
+ while view.is_running():
+ self.step()
+ view.sync()
+
+ def joint_command_callback(self, command: JointCommand) -> None:
+ if len(command.positions) != 0:
+ for i in range(len(command.joint_names)):
+ joint = self.robot.joints.get(command.joint_names[i])
+ joint.position = command.positions[i]
+ #if len(command.velocities) != 0:
+ # joint.velocity = command.velocities[i]
+
+ def step(self) -> None:
+ real_start_time = time.time()
+ self.step_number += 1
+ self.time += self.timestep
+ self.time_message = Time(seconds=int(self.time), nanoseconds=int(self.time % 1 * 1e9)).to_msg()
+
+ mujoco.mj_step(self.model, self.data)
+
+ for event_name, event_config in self.events.items():
+ if self.step_number % event_config["frequency"] == 0:
+ event_config["handler"]()
+
+ real_end_time = time.time()
+ time.sleep(max(0.0, self.timestep - (real_end_time - real_start_time)))
+
+ def publish_clock_event(self) -> None:
+ clock_msg = Clock()
+ clock_msg.clock = self.time_message
+ self.clock_publisher.publish(clock_msg)
+
+ def publish_ros_joint_states_event(self) -> None:
+ js = JointState()
+ js.name = []
+ js.header.stamp = self.time_message
+ js.position = []
+ js.effort = []
+ for joint in self.robot.joints:
+ js.name.append(joint.ros_name)
+ js.position.append(joint.position)
+ js.velocity.append(joint.velocity)
+ js.effort.append(joint.effort)
+ self.js_publisher.publish(js)
+
+ def publish_imu_event(self) -> None:
+ imu = Imu()
+ imu.header.stamp = self.time_message
+ imu.header.frame_id = self.imu_frame_id
+ imu.linear_acceleration.x, imu.linear_acceleration.y, imu.linear_acceleration.z = self.robot.sensors.accelerometer.data
+
+ # make sure that acceleration is not completely zero or we will get error in filter.
+ # Happens if robot is moved manually in the simulation
+ if imu.linear_acceleration.x == 0 and imu.linear_acceleration.y == 0 and imu.linear_acceleration.z == 0:
+ imu.linear_acceleration.z = 0.001
+
+ imu.angular_velocity.x, imu.angular_velocity.y, imu.angular_velocity.z = self.robot.sensors.gyro.data
+
+ self.imu_publisher.publish(imu)
+
+ def publish_camera_event(self) -> None:
+ if not self.camera_active:
+ return
+
+ img = Image()
+ img.header.stamp = self.time_message
+ img.header.frame_id = self.camera_optical_frame_id
+ img.encoding = "bgra8"
+ img.height = self.robot.camera.height
+ img.width = self.robot.camera.width
+ img.step = 4 * self.robot.camera.width
+ img.data = self.robot.camera.render()
+ self.camera_publisher.publish(img)
+
+ cam_info = CameraInfo()
+ cam_info.header = img.header
+ cam_info.height = self.robot.camera.height
+ cam_info.width = self.robot.camera.width
+
+ @staticmethod
+ def focal_length_from_fov(fov: float, resolution: int) -> float:
+ "Calculate focal length from field of view and resolution."
+ return 0.5 * resolution * (math.cos(fov / 2) / math.sin(fov / 2))
+
+ @staticmethod
+ def h_fov_to_v_fov(h_fov: float, height: int, width: int) -> float:
+ "Convert horizontal FOV to vertical FOV based on image aspect ratio."
+ return 2 * math.atan(math.tan(h_fov * 0.5) * (height / width))
+
+ camera = self.robot.camera
+
+ h_fov = camera.fov
+ v_fov = h_fov_to_v_fov(h_fov, camera.height, camera.width)
+
+ f_x, f_y = focal_length_from_fov(h_fov, camera.width), focal_length_from_fov(v_fov, camera.height)
+ cx, cy = camera.width / 2.0, camera.height / 2.0
+ cam_info.k = [
+ f_x, 0.0, cx,
+ 0.0, f_y, cy,
+ 0.0, 0.0, 1.0
+ ]
+ cam_info.p = [
+ f_x, 0.0, cx, 0.0,
+ 0.0, f_y, cy, 0.0,
+ 0.0, 0.0, 1.0, 0.0
+ ]
+
+ self.camera_info_publisher.publish(cam_info)
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/__init__.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/__init__.py
new file mode 100644
index 000000000..2cdb94c9a
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/__init__.py
@@ -0,0 +1,7 @@
+"""BitBots MuJoCo Simulation Package"""
+
+from .Simulation import Simulation
+
+__all__ = [
+ "Simulation",
+]
diff --git a/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/main.py b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/main.py
new file mode 100644
index 000000000..89e3ec586
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/main.py
@@ -0,0 +1,18 @@
+import math
+
+import rclpy
+
+from bitbots_mujoco_sim.Simulation import Simulation
+import threading
+from rclpy.experimental.events_executor import EventsExecutor
+
+def main(args=None):
+ rclpy.init(args=args)
+ simulation = Simulation()
+ executor = EventsExecutor()
+ executor.add_node(simulation)
+ thread = threading.Thread(target=executor.spin, daemon=True)
+ thread.start()
+ simulation.run()
+ simulation.destroy_node()
+ rclpy.shutdown()
diff --git a/bitbots_simulation/bitbots_mujoco_sim/package.xml b/bitbots_simulation/bitbots_mujoco_sim/package.xml
new file mode 100644
index 000000000..ca5137d72
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/package.xml
@@ -0,0 +1,18 @@
+
+
+
+ bitbots_mujoco_sim
+ 0.0.0
+ TODO: Package description
+ 22maschal
+ TODO: License declaration
+
+ ament_copyright
+ ament_flake8
+ ament_pep257
+ python3-pytest
+
+
+ ament_python
+
+
diff --git a/bitbots_simulation/bitbots_mujoco_sim/resource/bitbots_mujoco_sim b/bitbots_simulation/bitbots_mujoco_sim/resource/bitbots_mujoco_sim
new file mode 100644
index 000000000..e69de29bb
diff --git a/bitbots_simulation/bitbots_mujoco_sim/setup.cfg b/bitbots_simulation/bitbots_mujoco_sim/setup.cfg
new file mode 100644
index 000000000..de24bec2b
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/setup.cfg
@@ -0,0 +1,4 @@
+[develop]
+script_dir=$base/lib/bitbots_mujoco_sim
+[install]
+install_scripts=$base/lib/bitbots_mujoco_sim
diff --git a/bitbots_simulation/bitbots_mujoco_sim/setup.py b/bitbots_simulation/bitbots_mujoco_sim/setup.py
new file mode 100644
index 000000000..1ce730972
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/setup.py
@@ -0,0 +1,34 @@
+import glob
+
+from setuptools import find_packages, setup
+
+package_name = "bitbots_mujoco_sim"
+
+
+setup(
+ name=package_name,
+ version="0.0.0",
+ packages=find_packages(exclude=["test"]),
+ data_files=[
+ ("share/ament_index/resource_index/packages", ["resource/" + package_name]),
+ ("share/" + package_name, ["package.xml"]),
+ ("share/" + package_name + "/xml", glob.glob("xml/*.xml")),
+ ("share/" + package_name + "/xml/assets", glob.glob("xml/assets/*.png")),
+ ("share/" + package_name + "/xml/assets", glob.glob("xml/assets/*.stl")),
+ ("share/" + package_name + "/xml/assets/ball", glob.glob("xml/assets/ball/*.png")),
+ ],
+ install_requires=["setuptools"],
+ zip_safe=True,
+ maintainer="22maschal",
+ maintainer_email="22maschal@todo.todo",
+ description="TODO: Package description",
+ license="TODO: License declaration",
+ extras_require={
+ "test": [
+ "pytest",
+ ],
+ },
+ entry_points={
+ "console_scripts": ["sim = bitbots_mujoco_sim.main:main"],
+ },
+)
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/adult_field.xml b/bitbots_simulation/bitbots_mujoco_sim/xml/adult_field.xml
new file mode 100644
index 000000000..71d69326a
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/xml/adult_field.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/adult_field.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/adult_field.png
new file mode 100644
index 000000000..c11ffe335
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/adult_field.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/adult_field_original.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/adult_field_original.png
new file mode 100644
index 000000000..835fa2c48
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/adult_field_original.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ankle.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ankle.stl
new file mode 100644
index 000000000..7ea29289a
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ankle.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/back.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/back.png
new file mode 100644
index 000000000..c01b51714
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/back.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/down.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/down.png
new file mode 100644
index 000000000..49ace5b65
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/down.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/front.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/front.png
new file mode 100644
index 000000000..c18fbf046
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/front.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/left.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/left.png
new file mode 100644
index 000000000..d3b14f7b7
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/left.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/right.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/right.png
new file mode 100644
index 000000000..69965a816
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/right.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/up.png b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/up.png
new file mode 100644
index 000000000..8c729d705
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/ball/up.png differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/baseplate_odroid_xu4_core.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/baseplate_odroid_xu4_core.stl
new file mode 100644
index 000000000..4660be2d7
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/baseplate_odroid_xu4_core.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/basler_ace_gige_c-mount_v01.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/basler_ace_gige_c-mount_v01.stl
new file mode 100644
index 000000000..01531abb9
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/basler_ace_gige_c-mount_v01.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery.stl
new file mode 100644
index 000000000..9cfcaab81
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery_cage.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery_cage.stl
new file mode 100644
index 000000000..6bfb9bbdd
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery_cage.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery_clip.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery_clip.stl
new file mode 100644
index 000000000..6c97c8b9b
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/battery_clip.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_lower_basler_wolfgang_imu_v2.2.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_lower_basler_wolfgang_imu_v2.2.stl
new file mode 100644
index 000000000..b2a928ecc
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_lower_basler_wolfgang_imu_v2.2.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_side_basler_wolfgang_v2.2_left.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_side_basler_wolfgang_v2.2_left.stl
new file mode 100644
index 000000000..74f0de193
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_side_basler_wolfgang_v2.2_left.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_side_basler_wolfgang_v2.2_right.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_side_basler_wolfgang_v2.2_right.stl
new file mode 100644
index 000000000..9e3476d5f
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/camera_side_basler_wolfgang_v2.2_right.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/connector_shoulder.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/connector_shoulder.stl
new file mode 100644
index 000000000..5d9ceaf2e
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/connector_shoulder.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/core.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/core.stl
new file mode 100644
index 000000000..e778fb9be
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/core.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/dummy_speaker.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/dummy_speaker.stl
new file mode 100644
index 000000000..4c9f147f4
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/dummy_speaker.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/flex_stollen.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/flex_stollen.stl
new file mode 100644
index 000000000..21c0952af
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/flex_stollen.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_cover.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_cover.stl
new file mode 100644
index 000000000..d59c6418a
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_cover.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_printed_left.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_printed_left.stl
new file mode 100644
index 000000000..f6d0adddc
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_printed_left.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_printed_right.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_printed_right.stl
new file mode 100644
index 000000000..8826d1214
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/foot_printed_right.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/hand.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/hand.stl
new file mode 100644
index 000000000..c8ea9fdb4
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/hand.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/hip_u_connector.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/hip_u_connector.stl
new file mode 100644
index 000000000..561db981e
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/hip_u_connector.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/imu_holder.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/imu_holder.stl
new file mode 100644
index 000000000..c04c67f34
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/imu_holder.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/knee_connector.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/knee_connector.stl
new file mode 100644
index 000000000..121793261
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/knee_connector.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/knee_spacer.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/knee_spacer.stl
new file mode 100644
index 000000000..247ca07fe
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/knee_spacer.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lense.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lense.stl
new file mode 100644
index 000000000..40d74deaa
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lense.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/load_cell.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/load_cell.stl
new file mode 100644
index 000000000..10a6ded35
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/load_cell.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_arm.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_arm.stl
new file mode 100644
index 000000000..a6ff1783b
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_arm.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_leg.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_leg.stl
new file mode 100644
index 000000000..f251cda1c
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_leg.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_leg_spacer.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_leg_spacer.stl
new file mode 100644
index 000000000..6bda6802f
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/lower_leg_spacer.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/motor_connector.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/motor_connector.stl
new file mode 100644
index 000000000..11930f160
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/motor_connector.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/mx-106_body.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/mx-106_body.stl
new file mode 100644
index 000000000..d52c169f7
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/mx-106_body.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/mx-64-body.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/mx-64-body.stl
new file mode 100644
index 000000000..bc27727c1
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/mx-64-body.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_left_back.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_left_back.stl
new file mode 100644
index 000000000..19d998c09
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_left_back.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_left_front.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_left_front.stl
new file mode 100644
index 000000000..ae2851d5b
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_left_front.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_right_back.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_right_back.stl
new file mode 100644
index 000000000..b127ccabd
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_right_back.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_right_front.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_right_front.stl
new file mode 100644
index 000000000..2911ed855
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_holder_right_front.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_main.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_main.stl
new file mode 100644
index 000000000..773dc5a2d
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/nuc_main.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/sea_connector.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/sea_connector.stl
new file mode 100644
index 000000000..6330b8215
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/sea_connector.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/sea_ninjaflex.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/sea_ninjaflex.stl
new file mode 100644
index 000000000..f133c5361
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/sea_ninjaflex.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/shoulder_connector.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/shoulder_connector.stl
new file mode 100644
index 000000000..a40dfeeed
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/shoulder_connector.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/speaker_holder.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/speaker_holder.stl
new file mode 100644
index 000000000..047963389
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/speaker_holder.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/spring_holder_lower.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/spring_holder_lower.stl
new file mode 100644
index 000000000..799e36c11
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/spring_holder_lower.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/spring_holder_upper.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/spring_holder_upper.stl
new file mode 100644
index 000000000..dfd73887a
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/spring_holder_upper.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/springholder_bottom.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/springholder_bottom.stl
new file mode 100644
index 000000000..058d88c8e
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/springholder_bottom.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/springholder_new.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/springholder_new.stl
new file mode 100644
index 000000000..ba6d42cba
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/springholder_new.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/thrustbearingholder.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/thrustbearingholder.stl
new file mode 100644
index 000000000..37c728c3c
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/thrustbearingholder.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bottom.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bottom.stl
new file mode 100644
index 000000000..229d6e0f6
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bottom.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bumper_left.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bumper_left.stl
new file mode 100644
index 000000000..1abead395
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bumper_left.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bumper_right.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bumper_right.stl
new file mode 100644
index 000000000..96328fe4d
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_bumper_right.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_top.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_top.stl
new file mode 100644
index 000000000..681394317
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/torso_top.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_arm.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_arm.stl
new file mode 100644
index 000000000..6c42126dd
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_arm.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_arm_spacer.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_arm_spacer.stl
new file mode 100644
index 000000000..ee3be5ab4
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_arm_spacer.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_leg.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_leg.stl
new file mode 100644
index 000000000..93698c335
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_leg.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_leg_spacer.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_leg_spacer.stl
new file mode 100644
index 000000000..8472919b7
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/upper_leg_spacer.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/assets/xh-540.stl b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/xh-540.stl
new file mode 100644
index 000000000..5e6fb87b6
Binary files /dev/null and b/bitbots_simulation/bitbots_mujoco_sim/xml/assets/xh-540.stl differ
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/goal.xml b/bitbots_simulation/bitbots_mujoco_sim/xml/goal.xml
new file mode 100644
index 000000000..7b38f97ee
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/xml/goal.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bitbots_simulation/bitbots_mujoco_sim/xml/wolfgang.xml b/bitbots_simulation/bitbots_mujoco_sim/xml/wolfgang.xml
new file mode 100644
index 000000000..357dfdeee
--- /dev/null
+++ b/bitbots_simulation/bitbots_mujoco_sim/xml/wolfgang.xml
@@ -0,0 +1,669 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+