Inertial Measurement Unit (IMU)#
Inertial Measurement Units (IMUs) are a type of sensor for measuring the acceleration of an object. These sensors are traditionally designed report linear accelerations and angular velocities, and function on similar principles to that of a digital scale: They report accelerations derived from net force acting on the sensor.
A naive implementation of an IMU would report a negative acceleration due to gravity while the sensor is at rest in some local gravitational field. This is not generally needed for most practical applications, and so most real IMU sensors often include a gravity bias and assume that the device is operating on the surface of the Earth. The IMU we provide in Isaac Lab includes a similar bias term, which defaults to +g. This means that if you add an IMU to your simulation, and do not change this bias term, you will detect an acceleration of \(+ 9.81 m/s^{2}\) anti-parallel to gravity acceleration.
Consider a simple environment with an Anymal Quadruped equipped with an IMU on each of its two front feet.
from isaaclab.sensors import ImuCfg
from isaaclab.utils.configclass import configclass
##
# Pre-defined configs
##
from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort: skip
@configclass
class ImuSensorSceneCfg(InteractiveSceneCfg):
"""Design the scene with IMU sensors on the robot."""
# ground plane
ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_utils.GroundPlaneCfg())
# lights
dome_light = AssetBaseCfg(
prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
)
# robot
robot = ANYMAL_C_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
imu_RF = ImuCfg(prim_path="{ENV_REGEX_NS}/Robot/LF_FOOT")
Here we have explicitly removed the bias from one of the sensors, and we can see how this affects the reported values by visualizing the sensor when we run the sample script
Notice that the right front foot explicitly has a bias of (0,0,0). In the visualization, you should see that the arrow indicating the acceleration from the right IMU rapidly changes over time, while the arrow visualizing the left IMU points constantly along the vertical axis.
Retrieving values from the sensor is done in the usual way
def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
.
.
.
# Simulate physics
while simulation_app.is_running():
.
.
.
# print information from the sensors
print("-------------------------------")
print(scene["imu_LF"])
print("Received linear velocity: ", scene["imu_LF"].data.lin_vel_b)
print("Received angular velocity: ", scene["imu_LF"].data.ang_vel_b)
print("Received linear acceleration: ", scene["imu_LF"].data.lin_acc_b)
print("Received angular acceleration: ", scene["imu_LF"].data.ang_acc_b)
print("-------------------------------")
print(scene["imu_RF"])
print("Received linear velocity: ", scene["imu_RF"].data.lin_vel_b)
print("Received angular velocity: ", scene["imu_RF"].data.ang_vel_b)
print("Received linear acceleration: ", scene["imu_RF"].data.lin_acc_b)
print("Received angular acceleration: ", scene["imu_RF"].data.ang_acc_b)
The oscillations in the values reported by the sensor are a direct result of how the sensor calculates the acceleration, which is through a finite difference approximation between adjacent ground truth velocity values as reported by the sim. We can see this in the reported result (pay attention to the linear acceleration) because the acceleration from the right foot is small, but explicitly zero.
Imu sensor @ '/World/envs/env_.*/Robot/LF_FOOT':
view type : <class 'omni.physics.tensors.api.RigidBodyView'>
update period (s) : 0.0
number of sensors : 1
Received linear velocity: tensor([[ 0.0203, -0.0054, 0.0380]], device='cuda:0')
Received angular velocity: tensor([[-0.0104, -0.1189, 0.0080]], device='cuda:0')
Received linear acceleration: tensor([[ 4.8344, -0.0205, 8.5305]], device='cuda:0')
Received angular acceleration: tensor([[-0.0389, -0.0262, -0.0045]], device='cuda:0')
-------------------------------
Imu sensor @ '/World/envs/env_.*/Robot/RF_FOOT':
view type : <class 'omni.physics.tensors.api.RigidBodyView'>
update period (s) : 0.0
number of sensors : 1
Received linear velocity: tensor([[0.0244, 0.0077, 0.0431]], device='cuda:0')
Received angular velocity: tensor([[ 0.0122, -0.1360, -0.0042]], device='cuda:0')
Received linear acceleration: tensor([[-0.0018, 0.0010, -0.0032]], device='cuda:0')
Received angular acceleration: tensor([[-0.0373, -0.0050, -0.0053]], device='cuda:0')
-------------------------------
Code for imu_sensor.py
1# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
2# All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""Launch Isaac Sim Simulator first."""
7
8import argparse
9
10from isaaclab.app import AppLauncher
11
12# add argparse arguments
13parser = argparse.ArgumentParser(description="Example on using the IMU sensor.")
14parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to spawn.")
15parser.add_argument(
16 "--physics",
17 default="isaacsim_physx",
18 choices=["isaacsim_physx"],
19 help="Physics backend.",
20)
21# append AppLauncher cli args
22AppLauncher.add_app_launcher_args(parser)
23# demos should open Kit visualizer by default
24parser.set_defaults(visualizer=["kit"])
25# parse the arguments
26args_cli = parser.parse_args()
27
28# launch omniverse app
29app_launcher = AppLauncher(args_cli)
30simulation_app = app_launcher.app
31
32"""Rest everything follows."""
33
34import torch
35
36import isaaclab.sim as sim_utils
37from isaaclab.assets import AssetBaseCfg
38from isaaclab.scene import InteractiveScene, InteractiveSceneCfg
39from isaaclab.sensors import ImuCfg
40from isaaclab.utils.configclass import configclass
41
42##
43# Pre-defined configs
44##
45from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort: skip
46
47
48@configclass
49class ImuSensorSceneCfg(InteractiveSceneCfg):
50 """Design the scene with IMU sensors on the robot."""
51
52 # ground plane
53 ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_utils.GroundPlaneCfg())
54
55 # lights
56 dome_light = AssetBaseCfg(
57 prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
58 )
59
60 # robot
61 robot = ANYMAL_C_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
62
63 imu_RF = ImuCfg(prim_path="{ENV_REGEX_NS}/Robot/LF_FOOT")
64
65 imu_LF = ImuCfg(prim_path="{ENV_REGEX_NS}/Robot/RF_FOOT")
66
67
68def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
69 """Run the simulator."""
70 # Define simulation stepping
71 sim_dt = sim.get_physics_dt()
72 sim_time = 0.0
73 count = 0
74
75 # Simulate physics
76 while simulation_app.is_running():
77 if count % 500 == 0:
78 # reset counter
79 count = 0
80 # reset the scene entities
81 root_pose = scene["robot"].data.default_root_pose.torch.clone()
82 root_pose[:, :3] += scene.env_origins
83 scene["robot"].write_root_link_pose_to_sim_index(root_pose=root_pose)
84 root_vel = scene["robot"].data.default_root_vel.torch.clone()
85 scene["robot"].write_root_com_velocity_to_sim_index(root_velocity=root_vel)
86 # set joint positions with some noise
87 joint_pos, joint_vel = (
88 scene["robot"].data.default_joint_pos.torch.clone(),
89 scene["robot"].data.default_joint_vel.torch.clone(),
90 )
91 joint_pos += torch.rand_like(joint_pos) * 0.1
92 scene["robot"].write_joint_position_to_sim_index(position=joint_pos)
93 scene["robot"].write_joint_velocity_to_sim_index(velocity=joint_vel)
94 # clear internal buffers
95 scene.reset()
96 print("[INFO]: Resetting robot state...")
97 # Apply default actions to the robot
98 targets = scene["robot"].data.default_joint_pos.torch
99 scene["robot"].set_joint_position_target_index(target=targets)
100 scene.write_data_to_sim()
101 # perform step
102 sim.step()
103 # update sim-time
104 sim_time += sim_dt
105 count += 1
106 # update buffers
107 scene.update(sim_dt)
108
109 # print information from the sensors
110 print("-------------------------------")
111 print(scene["imu_LF"])
112 print("Received angular velocity: ", scene["imu_LF"].data.ang_vel_b)
113 print("Received linear acceleration: ", scene["imu_LF"].data.lin_acc_b)
114 print("-------------------------------")
115 print(scene["imu_RF"])
116 print("Received angular velocity: ", scene["imu_RF"].data.ang_vel_b)
117 print("Received linear acceleration: ", scene["imu_RF"].data.lin_acc_b)
118
119
120def main():
121 """Main function."""
122
123 # Initialize the simulation context
124 sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device)
125 sim = sim_utils.SimulationContext(sim_cfg)
126 # Set main camera
127 sim.set_camera_view(eye=[3.5, 3.5, 3.5], target=[0.0, 0.0, 0.0])
128 # design scene
129 scene_cfg = ImuSensorSceneCfg(num_envs=args_cli.num_envs, env_spacing=2.0)
130 scene = InteractiveScene(scene_cfg)
131 # Play the simulator
132 sim.reset()
133 # Now we are ready!
134 print("[INFO]: Setup complete...")
135 # Run the simulator
136 run_simulator(sim, scene)
137
138
139if __name__ == "__main__":
140 # run the main function
141 main()
142 # close sim app
143 simulation_app.close()