关节力旋量传感器#
JointWrenchSensor 测量关节系统各刚体父关节处的反力和反力矩。力的单位为牛顿,力矩为牛顿米,条目顺序与 body_names 一致。
力旋量约定#
incoming_joint_frame 约定在子侧关节锚点处、以子侧关节坐标系表示力旋量。这与安装在关节处的六轴力/力矩传感器的位置相符。各后端实现会将求解器原生输出转换为这一统一约定。
PhysX 的 get_link_incoming_joint_force() 返回的力旋量已经以子侧关节坐标系表示,并以其锚点为参考点,因此 PhysX 传感器直接提供这些分量。再次应用 USD 的 localPos1 和 localRot1 会重复平移和旋转该力旋量。
通过关节系统数据读取#
若观测需要遵循关节系统的 body_ordering,请使用 body_joint_wrench。数据容器会应用关节系统已有的刚体映射,因此 robot.find_bodies() 返回的索引在力/力矩数据和其他关节系统数据中选中相同的刚体,无需另建传感器。
使用 Newton 时,请在构造关节系统前设置 robot_cfg.enable_joint_wrench = True,以请求扩展求解器状态。该功能增加求解器工作量,且与 MJWarp 禁用传感器的确定性模式不兼容,因此默认不启用。PhysX 和 OVPhysX 无需此标志,可按需提供数据。
robot = scene["robot"]
body_ids, _ = robot.find_bodies([".*foot"])
wrench = robot.data.body_joint_wrench.torch[:, body_ids]
force = wrench[..., :3]
torque = wrench[..., 3:]
张量形状为 (num_envs, num_bodies, 6),采用与传感器相同的连接关节坐标系约定。Newton 将自由根和世界固定根的条目填为零,且不包含闭环约束;PhysX 和 OVPhysX 则暴露根部反力。数据是最近一个物理步的求解结果,因此重置或写入状态后,应至少执行一个物理步再读取。
下述独立传感器 API 保留后端原生条目顺序,并具有独立的更新与重置时序。
配置传感器#
将 prim_path 设为关节体根节点。报告的刚体范围取决于物理后端:
PhysX 和 OVPhysX 报告所有关节体连杆,包括根连杆。
Newton 报告关节体树中每个非自由关节的子连杆,包括刚体间的固定连接,例如焊接的腕部传感器或工具法兰。不包括自由关节、与世界相连的固定关节,以及闭环约束。即使焊接关节没有自由度,其报告的力旋量仍包含由子树传递的负载。
请使用 body_names 或 find_bodies() ,不要假定不同后端提供相同数量或顺序的条目:
joint_wrench = JointWrenchSensorCfg(prim_path="{ENV_REGEX_NS}/Robot")
基于管理器的环境可以通过 SceneEntityCfg 选择刚体子集,并使用 body_incoming_wrench() 作为观测项:
feet_body_forces = ObsTerm(
func=mdp.body_incoming_wrench,
scale=0.1,
params={"sensor_cfg": SceneEntityCfg("joint_wrench", body_names=FEET_BODY_NAMES)},
)
actions = ObsTerm(func=mdp.last_action)
读取数据#
对于 E 个环境和 B 个报告的刚体, force.torch 和 torque.torch 的形状均为 (E, B, 3) 。两个缓冲区在仿真初始化前均为 None 。
joint_wrench = scene["joint_wrench"]
foot_ids, _ = joint_wrench.find_bodies([".*foot"])
force = joint_wrench.data.force.torch[:, foot_ids]
torque = joint_wrench.data.torque.torch[:, foot_ids]
wrench = torch.cat((force, torque), dim=-1)
组合后的 wrench 形状为 (E, num_selected_bodies, 6) ,力分量在前,力矩分量在后。 B 及条目的排列顺序可能因后端而异。