潘俭渝Erik头像

Webots 中 Physics 节点完全解析:质量、惯量与刚体合并机制

  • 科研
  • 自动驾驶
  • 物理引擎

【免费下载链接】webots

Webots Robot Simulator

项目地址: https://gitcode.com/gh_mirrors/web/webots
点击查看 免费下载

本文以 Webots 参考文档 Physics 节点条目为核心,系统讲解该节点的五个字段(density、mass、centerOfMass、inertiaMatrix、damping)的取值规则与生效逻辑,并结合同步源码(src/webots/nodes/WbPhysics.cpp、src/webots/nodes/WbSolid.cpp、src/webots/nodes/utils/WbSolidMerger.cpp)剖析“物理模式 vs 运动学模式”的判定、刚体隐式合并与关节创建等底层机制,帮助你正确为场景中的物体、机器人和设备配置物理属性。

Physics 节点定义与字段总览

Physics 节点用于向物理引擎(Webots 内置 ODE)指定刚体的物理参数:质量、重心位置和质量分布。它是绝大多数 Webots 世界的基本组成,只有纯运动学(kinematics)仿真才会省略它。Physics 节点必须放置在一个 Solid 节点(或任何 Solid 派生节点)的 physics 字段中——该字段是 NULL 还是指向一个 Physics 节点,直接决定了这个 Solid 是以 physics(物理)模式还是 kinematics(运动学)模式被仿真:

Physics {
  SFFloat density       1000   # {-1, [0, inf)}
  SFFloat mass          -1     # {-1, [0, inf)}
  MFVec3f centerOfMass  [ ]    # any vector
  MFVec3f inertiaMatrix [ ]    # any two vectors
  SFNode  damping       NULL   # {Damping, PROTO}
}

各字段的作用如下:

字段类型默认值作用
densitySFFloat1000所在 Solid 的密度,kg/m³;为 -1 时表示未知,必须改用 mass
massSFFloat-1所在 Solid 的总质量,kg;为 -1 时表示未知,必须改用 density
centerOfMassMFVec3f空重心位置(米,Solid 局部坐标系);为空则自动由 boundingObject 计算
inertiaMatrixMFVec3f空手动指定惯性矩阵;必须为空或恰好 2 个向量
dampingSFNodeNULL指向一个 Damping 节点,定义该 Solid 的线性/角速度阻尼

注意:在旧版 Webots 中,coulombFriction、bounce、bounceVelocity 和 forceDependentSlip 曾直接定义在 Physics 节点里。现在这些接触参数必须写在 ContactProperties 节点中。从源码看,coulombFriction、forceDependentSlip 等字段仅存在于 WbContactProperties 类中(见 WbContactProperties.hpp),WbPhysics 类(WbPhysics.hpp)只持有 density、mass、centerOfMass、inertiaMatrix、damping 五个用户字段。

字段一:density 与 mass 的互斥关系

  • density 的值应为 -1 或正数,单位为 kg/m³。取 -1 表示密度未知,此时必须指定 mass。若 density 为正,则 Solid 的总质量 = 密度 × boundingObject 中全部几何基元的总体积。需要特别注意:Webots 忽略基元之间是否相交,每个基元的体积被简单累加后再乘以密度。
  • mass 的值应为 -1 或正数,单位为 kg。取 -1 表示总质量未知,此时必须指定 density。如果机器人规格书直接给出了整机质量,直接填 mass 比反推 density 更精确。

源码印证了这条互斥规则。WbPhysics.cpp 中的 checkMassAndDensity() 会给出两条解析警告:两者同时为 -1 时提示“Either the 'mass' or the 'density' must be specified”;两者同时为正时提示“the 'density' will be ignored”(即以 mass 为准)。此外,checkDensity() 表明当 mass 非正时会把 density 重置回默认值 1000,checkMass() 则把 mass 重置为 1 或 -1——这与字段注释中 {density: 默认 1000}、{mass: 默认 -1} 的取值表一致。

字段二:centerOfMass

centerOfMass 定义 Solid 的重心位置:

  • 字段为空(0 个向量):重心自动根据 boundingObject 计算;
  • 字段含 1 个向量:以该向量(单位米,Solid 局部坐标系)为准,覆盖自动计算;
  • 若该向量不为 [0 0 0],Webots 3D 窗口中会用一个深红/绿/蓝十字标出重心位置(对应 WbSolid.cpp 中 mCenterOfMassTransform 节点的可见性逻辑)。

centerOfMass 最多接受 1 个向量,多余向量会被丢弃并产生警告,见 WbPhysics.cpp 中 preFinalize() 的校验代码。

字段三:inertiaMatrix 与两种配置模式

inertiaMatrix 可用于手动指定 Solid 的惯性矩阵。字段要么为空(默认,此时 Webots 依据 boundingObject 中几何基元的位置与朝向自动计算),要么恰好包含 2 个向量:

  • 第 1 个向量 [I11, I22, I33] 表示主惯性矩(principals moments of inertia);
  • 第 2 个向量 [I12, I13, I23] 表示惯性乘积(products of inertia)。

二者共同构成 3×3 惯性矩阵:

[ I11 I12 I13 ]
[ I12 I22 I23 ]
[ I13 I23 I33 ]

Ixx 以 kg·m² 为单位,且主惯性矩必须为正;该矩阵是相对于 centerOfMass 定义的。内部实现中,这 6 个值不经换算直接传给 ODE 的 dMassSetParameters 函数——这一点在 WbSolid.cpp 的 setOdeInertiaMatrix() 中可以清楚看到:

dMassSetParameters(mOdeMass, p->mass(), 0.0, 0.0, 0.0, v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z());
...
dMassTranslate(mOdeMass, com.x(), com.y(), com.z());  // 平移到 Solid 坐标系原点

如果指定了 inertiaMatrix,则 mass 字段必须同时指定;源码在 checkInertiaMatrix() 中做了三重校验:主惯性矩必须全为正(否则调试版 ODE 会触发断言失败)、矩阵必须正定(dIsPositiveDefinite)、且必须同时提供 centerOfMass 和正的 mass。

综合来看,从源码结构可以归纳出 WbPhysics 的三种工作模式(定义于 WbPhysics.hpp 的 ModeType 枚举):

模式触发条件(updateMode())
CUSTOM_INERTIA_MATRIXmass > 0 且 centerOfMass 恰有 1 个向量且惯性矩阵合法
BOUNDING_OBJECT_BASEDmass 或 density 为正,且 inertiaMatrix 为空
INVALID其余情况,此时 ODE 沿用最近一次有效配置

一个容易忽略的细节是:在 BOUNDING_OBJECT_BASED 模式下,计算出的惯性矩阵是以 boundingObject 自身质心为基准的,Solid 的行为等效于“把质量分布平移到 centerOfMass 处,而物理边界不动”(见 WbPhysics.hpp 顶部注释)。

字段四:damping

damping 字段指向一个 Damping 节点,用于定义作用在该 Solid 上的速度阻尼参数。Damping 的 linear/angular 字段取值范围为 [0, 1],分别对线速度和角速度每秒衰减相应比例。合并刚体的阻尼值会按各 Solid 分量体积加权平均(合并逻辑见 WbSolidMerger.cpp 中 setupOdeBody() 调用的 setOdeDamping())。仓库中 tests/physics/worlds/damping.wbt 展示了在多个 Solid 上分别配置不同 linear 阻尼(0、0.4、0.8)的对比测试场景。

如何决定一个物体是否需要 Physics 节点

若 Solid 含有 Physics 节点,该物体以 physics 模式仿真:引擎会计算作用在刚体上的力以及刚体属性(质量、转动惯量);反之,physics 字段为 NULL 时物体以 kinematics 模式仿真:只模拟运动本身而不考虑引发运动的力。典型差异是:运动学模式下物体可以瞬时达到目标速度,而物理模式下惯性阻力会使物体逐渐加速。

是否给某个物体配置 Physics,取决于你想建模现实中的哪一面。

被动静止物体

  • 如果一个被动物体在仿真中绝不应移动(墙、地板),就把 physics 字段留空。此时不会在该物体上模拟任何接触力,它永远不会动。
  • 地板尤其必须不带 Physics 节点,否则在重力作用下地板本身会掉下来。
  • 反之,如果被动物体会被推、踢、掉落(足球被踢出滚动、箱子被推倒或堆叠),就必须给它加 Physics 节点,摩擦力和重力才会作用其上。

机器人

关节式机器人、人形机器人、车辆等都构建为 Solid(或其子类)的层级结构。腿或轮子产生的接触力、摩擦力的仿真,以及抓取式机械手/夹爪的接触力,通常是机器人运动仿真的核心。因此机器人的机械部件(腿、轮、臂、手等)一般需要 Physics 节点。

说明:可以把一个 Robot 或顶层 Solid 的 physics 字段设为 NULL,将其基座固定于静态环境。这对基座锚定在固定位置上的机械臂仿真很有用。更一般地,你可以定义一个以某个顶层 Solid 为根的更大“静态基座”:从该顶层 Solid 出发、整棵子树中所有 Solid 都不含 Physics 节点。

说明:采用差速轮配置的 Robot 是特例:即使没有 Physics 节点也能移动,因为 Webots 对此类机器人使用了特殊的运动学算法;但一旦存在 Physics 节点,就切换回常规物理仿真算法。从源码看,WbSolid::createJoint() 的默认行为是创建 ODE 固定关节(WbSolid.cpp 中 dJointCreateFixed(world, 0)),即 Solid 与父级刚体之间默认以固定关节连接。而一个 Robot 要被识别为差速轮机器人,必须满足:机器人有 2 个 HingeJoint,两轴平行对齐,且两个关节 endPoint 字段中 Solid 的 bounding object 必须是半径相同的 Cylinder。

隐式 Solid 合并与关节

先明确“Solid 子节点”的广义定义:给定一个 Solid,其子节点既包括直接放进 children 列表的节点,也包括放在 children 中某个 Joint 的 endPoint 字段里的 Solid;该定义可延伸到从 Solid 的 children 列表开始、包含 Joint 或 Solid 的嵌套 Group。

若一个广义子 Solid 与其父 Solid 之间没有关节相连,且两者都有 Physics 节点,则它们在物理引擎层面被合并:ODE 只获得一个 body 来同时表示父与子。该过程递归进行,直到某个通过关节指向上层 Solid 的最高祖先,或最高无 Physics 节点的祖先之前为止。这样一来,即使一个刚性质组件由大量小 Solid 拼装而成,也不会拖累物理仿真速度。

注意:发生刚体合并时,刚性质组件中只有最高祖先持有 ODE body(即非空 dBodyID),并承载整组组件的物理属性。这一点会影响 physics plugin 的设计方式。源码印证:WbSolidMerger.cpp 中每个合并器用 dBodyCreate 创建一个 ODE body,appendSolid() 把各子 Solid 的 dMass 收集进 mMergedSolids 映射表,最终由 mergeMasses() 汇总到这一个 body 上。

设计机器人节点树结构时,关于 Physics 节点有一条必须牢记的规则:

规则 (1):如果一个 Solid 节点的父节点和子节点都有 Physics 节点,那么它自己也必须带有 Physics 节点。

其推论是:在机器人树中,只有叶子节点以及 static basis(静态基座,见上文)内的节点才允许 physics 字段为 NULL。顶层 Robot 节点通常必须带 Physics,否则其任何子节点都无法使用物理仿真。

同时要注意:每个 Physics 节点都会显著增加世界的复杂度、拖慢仿真速度,因此 Physics 节点数量应尽可能少。即使是很复杂的轮式或关节式机器人,部分 physics 字段也可以保持为空。以一台双腿关节机器人为例(高度简化的模型),两条腿需要 Physics 节点,因为它们与地面接触产生的力是机器人移动的来源;若腿上没有 Physics,接触力无从产生,机器人就不会动。按规则 (1),腿有了 Physics,父级 Robot 也必须有 Physics,否则仿真无法工作(腿会“脱落”):

Robot {
  ...
  children [
    DEF LEG1_HINGE HingeJoint  {
      ...
      endPoint DEF LEG1 Solid {
        physics Physics {
        }
      }
    }
    DEF LEG2_HINGE HingeJoint {
      ...
      endPoint DEF LEG2 Solid {
        physics Physics {
        }
      }
    }
  ]
  physics Physics {
  }
}

现在假设给机器人加一个 Camera。若相机质量很小、且希望忽略相机与其他物体的碰撞,则相机的 physics 字段留空即可:

Robot {
  ...
  children [
    DEF CAM Camera {
      ...
    }
    DEF LEG1_HINGE HingeJoint  {
      ...
      endPoint DEF LEG1 Solid {
        ...
        physics Physics {
        }
      }
    }
    DEF LEG2_HINGE HingeJoint {
      ...
      endPoint DEF LEG2 Solid {
        physics Physics {
        }
      }
    }
  ]
  physics Physics {
  }
}

再假设相机需要伺服化,例如水平旋转。此时只需把相机放进控制其水平位置的 HingeJoint 的 endPoint 字段。若假设电机质量小、转动惯量无关紧要,相机的 Physics 节点同样可以省略:

Robot {
  ...
  children [
    DEF CAMERA_HINGE HingeJoint {
      ...
      device DEF CAM_MOTOR RotationalMotor {
          ...
      }
      endPoint DEF CAM Camera {
        ...
      }
    }
    DEF LEG1_HINGE HingeJoint  {
      ...
      endPoint DEF LEG1 Solid {
        ...
        physics Physics {
        }
      }
    }
    DEF LEG2_HINGE HingeJoint {
      ...
      endPoint DEF LEG2 Solid {
        physics Physics {
        }
      }
    }
  ]
  physics Physics {
  }
}

设备(Devices)

大多数设备节点在没有 Physics 节点的情况下也能工作,但可选地加一个 Physics 节点来仿真设备自身的重量和转动惯量。一般建议:除非设备在仿真机器人中代表可观的质量或体积,否则保持设备的 physics 字段为空。这条建议适用于:Accelerometer、Altimeter、Camera、Compass、DistanceSensor、Emitter、GPS、LED、LightSensor、Pen、Receiver。

注意:InertialUnit、Connector 和 VacuumGripper 的行为不同——它们要求父节点存在 Physics 节点才能工作(例如 WbVacuumGripper.cpp 在吸附失败时会报告“neither the VacuumGripper node nor the solid object have Physics nodes”)。也可以在设备本身上指定 Physics 节点,但代价是给仿真额外增加一个 body。

TouchSensor 是另一个特例:作为“力传感器”使用时需要 Physics 节点;仅作为“碰撞器”(bumper)使用时则不一定需要。从源码看,WbTouchSensor::createJoint()(WbTouchSensor.cpp)会在 forceBehavior() 为真时创建 dJointFeedback 以收集接触力。

实战建议小结

  1. 地板、墙体等永久静止物体一律不加 Physics,否则地板会在重力下坠落;需要被推动/踢动的物体(足球、木箱)必须加。
  2. 遵守规则 (1):父、子都有 Physics 的中间 Solid 必须自己带 Physics;顶层 Robot 一般必须带 Physics。
  3. 质量已知优先写 mass,否则写 density;二者同时为正时 density 被忽略且会产生警告。
  4. 需要精确惯性行为时提供 inertiaMatrix + centerOfMass + 正的 mass 三件套,并注意主惯性矩为正、矩阵正定。
  5. 传感器、摄像头、发射器等轻设备保持 physics 为空;只有 InertialUnit、Connector、VacuumGripper 及作力传感器用的 TouchSensor 例外。
  6. 控制 Physics 节点总数:利用隐式刚体合并机制,把同一刚性质组件拆成多个小 Solid 不会额外增加 ODE body 数量,但每个独立 Physics 都会增加求解开销。
  7. 摩擦、反弹等接触参数请写到 ContactProperties,速度阻尼写到 Physics.damping 指向的 Damping 节点。
  • 科研
  • 自动驾驶
  • 物理引擎

【免费下载链接】webots

Webots Robot Simulator

项目地址: https://gitcode.com/gh_mirrors/web/webots
点击查看 免费下载

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/gitblog_00091/article/details/157404437

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--