惯性测量单元 (IMU)#

惯性测量单元 (IMUs) 是一种用于测量物体加速度的传感器。这些传感器传统上设计用于报告线性加速度和角速度,并且基于与数字秤类似的原理工作: 它们报告由 作用在传感器上的净力 所产生的加速度。
一个简单的IMU实现会在传感器静止并处于某个局部引力场时,报告一个负的重力加速度。这在大多数实际应用中通常不需要,因此大多数真实的IMU传感器通常会包括一个 重力偏置 ,并假设设备位于地球表面。我们在Isaac Sim中提供的IMU也包含一个类似的偏置项,默认值为 +g。这意味着,如果你将IMU添加到你的仿真中,并且没有更改此偏置项,你将检测到一个与重力加速度方向相反的加速度,即: \(+ 9.81 m/s^{2}\) 。
考虑一个简单的环境,其中一个 Anymal 四足机器人配备了一个 IMU,分别安装在其两只前脚上。
@configclass
class ImuSensorSceneCfg(InteractiveSceneCfg):
"""Design the scene with 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", debug_vis=True)
imu_LF = ImuCfg(prim_path="{ENV_REGEX_NS}/Robot/RF_FOOT", gravity_bias=(0, 0, 0), debug_vis=True)
def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
"""Run the simulator."""
# Define simulation stepping
sim_dt = sim.get_physics_dt()
在这里,我们显式地从其中一个传感器中移除了偏差,我们可以通过可视化传感器,查看运行示例脚本时这如何影响报告的值。

请注意,右前脚显式地具有 (0,0,0) 的偏差。在可视化中,您应该看到表示右侧 IMU 加速度的箭头随时间快速变化,而表示左侧 IMU 的箭头始终指向垂直轴。
从传感器中检索值是以常规方式进行的
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)
传感器报告的数值波动是传感器如何计算加速度的直接结果,这个计算是通过相邻的地面真实速度值之间的有限差分近似来完成的,这些值是由仿真报告的。我们可以在报告的结果中看到这一点(请注意 线性加速度 ),因为右脚的加速度很小,但明确为零。
Imu sensor @ '/World/envs/env_.*/Robot/LF_FOOT':
view type : <class 'omni.physics.tensors.impl.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.impl.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')
-------------------------------
imu_sensor.py的代码
1# Copyright (c) 2022-2025, The Isaac Lab Project Developers.
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="Tutorial on adding sensors on a robot.")
14parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to spawn.")
15# append AppLauncher cli args
16AppLauncher.add_app_launcher_args(parser)
17# parse the arguments
18args_cli = parser.parse_args()
19
20# launch omniverse app
21app_launcher = AppLauncher(args_cli)
22simulation_app = app_launcher.app
23
24"""Rest everything follows."""
25
26import torch
27
28import isaaclab.sim as sim_utils
29from isaaclab.assets import AssetBaseCfg
30from isaaclab.scene import InteractiveScene, InteractiveSceneCfg
31from isaaclab.sensors import ImuCfg
32from isaaclab.utils import configclass
33
34##
35# Pre-defined configs
36##
37from isaaclab_assets.robots.anymal import ANYMAL_C_CFG # isort: skip
38
39
40@configclass
41class ImuSensorSceneCfg(InteractiveSceneCfg):
42 """Design the scene with sensors on the robot."""
43
44 # ground plane
45 ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_utils.GroundPlaneCfg())
46
47 # lights
48 dome_light = AssetBaseCfg(
49 prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75))
50 )
51
52 # robot
53 robot = ANYMAL_C_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
54
55 imu_RF = ImuCfg(prim_path="{ENV_REGEX_NS}/Robot/LF_FOOT", debug_vis=True)
56
57 imu_LF = ImuCfg(prim_path="{ENV_REGEX_NS}/Robot/RF_FOOT", gravity_bias=(0, 0, 0), debug_vis=True)
58
59
60def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene):
61 """Run the simulator."""
62 # Define simulation stepping
63 sim_dt = sim.get_physics_dt()
64 sim_time = 0.0
65 count = 0
66
67 # Simulate physics
68 while simulation_app.is_running():
69
70 if count % 500 == 0:
71 # reset counter
72 count = 0
73 # reset the scene entities
74 # root state
75 # we offset the root state by the origin since the states are written in simulation world frame
76 # if this is not done, then the robots will be spawned at the (0, 0, 0) of the simulation world
77 root_state = scene["robot"].data.default_root_state.clone()
78 root_state[:, :3] += scene.env_origins
79 scene["robot"].write_root_link_pose_to_sim(root_state[:, :7])
80 scene["robot"].write_root_com_velocity_to_sim(root_state[:, 7:])
81 # set joint positions with some noise
82 joint_pos, joint_vel = (
83 scene["robot"].data.default_joint_pos.clone(),
84 scene["robot"].data.default_joint_vel.clone(),
85 )
86 joint_pos += torch.rand_like(joint_pos) * 0.1
87 scene["robot"].write_joint_state_to_sim(joint_pos, joint_vel)
88 # clear internal buffers
89 scene.reset()
90 print("[INFO]: Resetting robot state...")
91 # Apply default actions to the robot
92 # -- generate actions/commands
93 targets = scene["robot"].data.default_joint_pos
94 # -- apply action to the robot
95 scene["robot"].set_joint_position_target(targets)
96 # -- write data to sim
97 scene.write_data_to_sim()
98 # perform step
99 sim.step()
100 # update sim-time
101 sim_time += sim_dt
102 count += 1
103 # update buffers
104 scene.update(sim_dt)
105
106 # print information from the sensors
107 print("-------------------------------")
108 print(scene["imu_LF"])
109 print("Received linear velocity: ", scene["imu_LF"].data.lin_vel_b)
110 print("Received angular velocity: ", scene["imu_LF"].data.ang_vel_b)
111 print("Received linear acceleration: ", scene["imu_LF"].data.lin_acc_b)
112 print("Received angular acceleration: ", scene["imu_LF"].data.ang_acc_b)
113 print("-------------------------------")
114 print(scene["imu_RF"])
115 print("Received linear velocity: ", scene["imu_RF"].data.lin_vel_b)
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 print("Received angular acceleration: ", scene["imu_RF"].data.ang_acc_b)
119
120
121def main():
122 """Main function."""
123
124 # Initialize the simulation context
125 sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device)
126 sim = sim_utils.SimulationContext(sim_cfg)
127 # Set main camera
128 sim.set_camera_view(eye=[3.5, 3.5, 3.5], target=[0.0, 0.0, 0.0])
129 # design scene
130 scene_cfg = ImuSensorSceneCfg(num_envs=args_cli.num_envs, env_spacing=2.0)
131 scene = InteractiveScene(scene_cfg)
132 # Play the simulator
133 sim.reset()
134 # Now we are ready!
135 print("[INFO]: Setup complete...")
136 # Run the simulator
137 run_simulator(sim, scene)
138
139
140if __name__ == "__main__":
141 # run the main function
142 main()
143 # close sim app
144 simulation_app.close()