前言
最近做仿真时候需要处理力反馈数据,之前用isaacsim 2023.1.1版本时候使用的是F/T sensor,直接或许UR机械臂末端的传感器数据,但是特别烂,值完全不对,gripper夹取一个3kg垂直提升时候读取数据是200还是300N,而且physics_dt值不同时候数值也跟着变,无语了,最近isaaclab这个直接contact force更新的更完善了,出个经验贴给大家分享一下,做locomotion或者力控都很有用。
官方文档介绍:Contact Sensor — Isaac Lab Documentation
之前的安装教程:IsaacLab最新2025教程-环境配置(IsaacSim 4.5.0/Ubuntu22.04) 原创_isaacsim4.5-CSDN博客
如果下载了最新的isaaclab可以直接在文件夹中运行:
## cd IsaacLab进入isaaclab下面的文件夹
## 注意我使用的conda虚拟环境,可以直接用python运行,可以看我之前的安装教程
python scripts/demos/sensors/contact_sensor.py
1. Contact Sensor
Isaaclab中的接触力是检测两个physical object的接触力,现在只看了rigid body,deformable object后续再研究,但是大体思路是互通的。而且接触力可以选取特定的两个object的接触,比如机械狗上台阶的时候,可能卡在台阶上,轮子踩着一个台阶同时,轮子顶着高一阶的台阶(如果不理解下次上楼时候,脚踩着地面往前蹭,直到顶着下一个台阶蹭不动了就行了),但是我们只关心和踩着的台阶的接触力,不在乎和更高的台阶的接触力,这时候就可以设置一个filter只获取指定的两个object的接触力就可以了,下面是文档里的代码,依旧是复制过来加一些自己的tips。
2. 代码示例:在 Isaac Lab 中定义接触传感器
以下代码展示了如何在 Isaac Lab 中定义一个包含接触传感器的场景。我们以一个四足机器人(Anymal Quadruped)和一个立方体为例,展示如何为机器人的足部定义接触传感器。
场景配置
首先,我们定义一个场景配置类 ContactSensorSceneCfg
,其中包含地面、灯光、机器人和立方体的配置。
"""
这里的内容都很简单,就当成是复习之前搭建scene的流程了
"""
@configclass
class ContactSensorSceneCfg(InteractiveSceneCfg):
# 地面
ground = AssetBaseCfg(prim_path="/World/defaultGroundPlane", spawn=sim_util)
# 灯光
dome_light = AssetBaseCfg(
prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0)
)
# 机器人
robot = ANYMAL_C_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
# 立方体
cube = RigidObjectCfg(
prim_path="{ENV_REGEX_NS}/Cube",
spawn=sim_utils.CuboidCfg(
size=(0.5, 0.5, 0.1),
rigid_props=sim_utils.RigidBodyPropertiesCfg(),
mass_props=sim_utils.MassPropertiesCfg(mass=100.0),
collision_props=sim_utils.CollisionPropertiesCfg(),
physics_material=sim_utils.RigidBodyMaterialCfg(static_friction=1.0),
visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0)),
),
init_state=RigidObjectCfg.InitialStateCfg(pos=(0.5, 0.5, 0.05)),
)
定义接触传感器
接下来,我们为机器人的足部定义接触传感器。前足(左前足和右前足)分别定义为独立的传感器,而后足(左后足和右后足)则定义为单个传感器。
"""
这里面是加载传感器,目测直接加在需要的rigid body的prim path上就行了
"""
## 注意这里的filter_prim_paths_expr就是之前说的选取特定的接触物体,这样就不会考虑与其他物体的接触力了
contact_forces_LF = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/LF_FOOT",
update_period=0.0,
history_length=6,
debug_vis=True,
filter_prim_paths_expr=["{ENV_REGEX_NS}/Cube"],
)
contact_forces_RF = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/RF_FOOT",
update_period=0.0,
history_length=6,
debug_vis=True,
filter_prim_paths_expr=["{ENV_REGEX_NS}/Cube"],
)
## 这个意思是把两条后腿当成整体进行受力分析了,之前都是把单独一条腿进行受力分析,跟初中物理的受力分析一个道理哈
contact_forces_H = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/.*H_FOOT",
update_period=0.0,
history_length=6,
debug_vis=True,
)
运行仿真并打印传感器数据
在定义好传感器后,我们可以运行仿真并打印传感器的数据。
def run_simulator(sim: sim.utils.SimulationContext, scene: InteractiveScene):
while simulation_app.is_running():
# 打印传感器信息
print("---")
print(scene["contact_forces_LF"])
print("Received force matrix of: ", scene["contact_forces_LF"].data.force_matrix)
print("Received contact force of: ", scene["contact_forces_LF"].data.net_force)
print("---")
print(scene["contact_forces_RF"])
print("Received force matrix of: ", scene["contact_forces_RF"].data.force_matrix)
print("Received contact force of: ", scene["contact_forces_RF"].data.net_force)
print("---")
print(scene["contact_forces_H"])
print("Received force matrix of: ", scene["contact_forces_H"].data.force_matrix)
print("Received contact force of: ", scene["contact_forces_H"].data.net_force)
看看结果:
传感器数据解析
在仿真过程中,我们可以观察到以下传感器数据:
-
前左足传感器:
-
净接触力:
tensor([[[[-1.3923e-05, 1.5727e-04, 1.1032e+02]]]]
-
力矩阵:
tensor([[[[-1.3923e-05, 1.5727e-04, 1.1032e+02]]]]
-
-
前右足传感器:
-
净接触力:
tensor([[[1.3529e-05, 0.0000e+00, 1.0069e+02]]]
-
力矩阵:
tensor([[[[0., 0., 0.]]]])
-
-
后足传感器:
-
净接触力:
tensor([[[9.7227e-06, 0.0000e+00, 7.2364e+01], [2.4322e-05, 0.0000e+00, 1.8102e+02]]]
-
力矩阵:
None
-
从数据中可以看出,前左足传感器报告了来自立方体的接触力,而前右足传感器没有报告任何力,因为它没有站在立方体上。后足传感器由于是多个刚体的传感器,因此力矩阵为 None
,但净接触力包含了两个刚体的力信息。大概理解是,net_forces_w是这个物体在多个物体接触的情况下受到的合力,force_matrix_w是与filter指定的物体的特定接触力,w意思就是在世界坐标系下。
这是单独的关于力传感器的tutorial,如果要结合具体的强化学习训练示例,可以看官方环境中的locomotion里面的任务,基本上都要用到接触力。