有许多因素会影响仿真的稳定性和性能。
仿真参数调整
可以使用PhysX CPU或Flex作为仿真后端。即将添加对PhysX GPU关节求解器的支持。有两个常见的参数可以调整来改善性能和/或仿真稳定性-时间步长和子步长数以及一些引擎特定的参数。目前只有Flex支持可变形物体仿真。
常见参数
-
dt - 仿真的时间步长,默认为1/60秒
-
substeps - 仿真的子步长数,默认为2。实际的仿真时间步长为dt/substeps。
参数dt是用于推进仿真的时间步长,单位为秒。准确而稳定的物理仿真需要相当短的时间步长,通常在1/50秒以下。时间步长过长可能导致不稳定性,特别是对于快速移动的物体、强力或复杂的关节组装。除了推进仿真,您通常还会在循环的每次迭代中查询世界的状态并应用控制。然后,dt参数确定您与仿真交互的频率。通常情况下,与稳定的物理仿真所需的频率相比,交互的频率较低。参数num_substeps用于将每个时间步长分成相等的子区间,以实现稳定的物理仿真。在上面的代码段中,dt是1/60,因此您可以在每秒的仿真时间内与仿真交互60次。但是num_substeps是2,这意味着物理仿真以1/120秒的增量前进。这些是默认的仿真参数。
Flex
-
solver_type - Flex有6种可用的约束求解器,编号如下:
-
0 - XPBD (GPU) - 使用迭代下降法的基于位置的求解器,该方法比牛顿求解器(下面的求解器)精度较低,但通常用于中等刚度的系统,速度快且稳健。
Flex还支持使用多种不同线性求解器作为后端的非线性牛顿求解器,下面列出了这些求解器:
-
1 - Newton Jacobi (GPU) - GPU上的Jacobi求解器(CUDA)
-
2 - Newton LDLT (CPU) - CPU上的Cholesky后端(基于Eigen)
-
3 - Newton PCG1 (CPU) - CPU上的预条件共轭梯度(基于Eigen)
-
4 - Newton PCG2 (GPU) - GPU上的预条件共轭梯度(CUDA)
-
5 - Newton PCR (GPU) - GPU上的预条件共轭残差法(CUDA)
默认和推荐的求解器是5 - Newton PCR求解器,CPU后端在大型系统中可能非常慢,大多用于验证目的。
-
num_outer_iterations - 每个仿真子步骤求解器迭代的次数。
-
num_inner_iterations - 每个外部迭代所采用的线性求解器迭代次数,仅由Newton求解器使用。
-
relaxation - 控制求解器的收敛速率。默认值为0.75。大于1的值可能导致不稳定性。Newton求解器目前使用零速度起始迭代,因此如果收敛不足够、松弛太高,会引入一种与阻尼等效的数值等价物 = 1 - (1 - relaxation)^numOuterIterations。
-
warm_start - 下一个仿真步骤中要使用的缓存的拉格朗日乘数的比例。加速收敛,保守的默认值为0.4。较大的值可能导致更弹性的行为,有时在系统中存在快速运动和/或大范围、快速变化的力的情况下会导致不稳定性。在您试图模拟一个相当缓慢移动的系统,例如具有抓握复杂形状的机器人操作任务时,您可以尝试更高的warm start值,最高可达1.0。
-
shape_collision_distance - 粒子与刚体形状之间保持的距离(与半径参数分开)。
-
shape_collision_margin - 生成接触的距离(以米为单位)。Flex使用一种推测性接触模型,当特征对(例如:顶点/边)在时间步长开始时相互间的距离小于此距离时,将生成一个接触约束。如果物体移动得很快,那么边界值应该足够大,以确保在一个时间步长内不会错过接触。可以用以下方式规范化这一点:如果特征的最大速度为v,时间步长为dt,则边界值应为margin = v * dt / substeps。如果您从较高的高度掉落物体并看到它们“弹起”,那么很可能是碰撞边界值太低了(物体相互穿透,然后被弹出来)。
改善仿真的稳定性(收敛性)和减少穿透的最通用方法是增加子步骤的数量。但这可能会导致仿真的代价很大。其他尝试的方法包括:
在缺乏收敛性的情况下,增加外部和内部迭代的次数可能有所帮助。另一种不稳定性的来源可能是初始配置不好和存在自碰撞。可以通过可视化系统中的接触力并在可能时禁用机器人的自碰撞来诊断这一点,或者修复初始配置。除了增加子步骤的数量之外,如果可能的话,使shapeCollisionDistance更大可以帮助防止快速移动物体的穿透。如果慢速运动的系统中存在穿透,例如机器人手臂,在模拟中首先应检查并减小生成的接触力,例如通过使机器人电机更弱。
Flex中的形状表示是通过三角网格 - 所有基本形状,包括球体、胶囊体和盒子,都通过存储在GPU BVH结构中的三角网格表示(球体和胶囊体可以被认为是一个单一退化三角形+厚度)。这种统一表示意味着Flex可以处理非凸和任意的动态物理形状的三角形网格,但与凸多面体不同,三角形集一般不能定义“内/外”区域。这意味着一旦发生相互穿透,就无法以明确定义的方式解决。为了避免穿透,建议在碰撞形状上使用足够厚度的层。
PhysX
-
num_threads - PhysX使用的CPU核心数量。默认值为4。将其设置为0将在调用PxScene::simulate()的线程上运行模拟。大于0的值将生成numCores-1个工作线程。
-
solver_type - 使用的求解器类型。默认和推荐使用的是1 - TGS:时间高斯塞德尔求解器。它是一个非线性迭代求解器。
-
contact_offset - 距离小于其contactOffset值之和的形状将生成接触点。默认为0.02米。
-
rest_offset - 两个形状将停止在距离等于其restOffset值之和的位置。默认值为0.01米。
-
num_position_iterations - PhysX求解器的位置迭代次数。默认为4。
-
num_velocity_iterations - PhysX求解器的速度迭代次数。默认为1。
-
bounce_threshold_velocity - 相对速度低于此值的接触点将不会反弹。默认为0.2米/秒。
-
max_depenetration_velocity - 求解器允许引入的用于纠正接触点渗透的最大速度。默认为100.0米/秒。
为了改善求解器的收敛性,通常只应增加位置迭代次数。速度迭代次数可能会对求解器的收敛性产生负面影响。它们的作用是减少渗透带来的能量增益,但会使整体模拟变得不太牢固。对于TGS求解器来说,速度迭代的默认选择是0。不稳定性需要根据具体情况进行处理。然而,一般规则是:
如果是由于深入渗透引起的,可以使用更多的子步骤或限制求解器在纠正错误时可以注入的能量来帮助解决问题。参见 PxRigidBody::setMaxDepenetrationVelocity
。默认值为5米/秒,但在存在大力时,较大的值(例如100米/秒)有助于消除渗透。
如果不稳定性基本上是系统无法收敛造成的,增加位置迭代次数或子步数应该有所帮助。如果使用的是PGS求解器,子步数对模拟质量的影响要比增加迭代次数大得多,但子步需要更多的计算资源(迭代相对较便宜)。如果使用的是TGS求解器,子步数和迭代次数对收敛性的影响更为相似。迭代的计算成本低于子步,但不如PGS求解器便宜。在可能的情况下,强烈推荐使用TGS而不是PGS。可能导致稳定性的其他参数有:形状的接触偏移(间隙)、休息偏移(膨胀)。
场景参数
-
bounce_threshold_velocity - 触发反弹的相对速度阈值。默认值为0.2米/秒,在某些情况下可能相当高。降低该值可以获得更自然的弹跳行为,例如在弹跳球的情况下。
-
friction_offset_threshold - 计算摩擦力开始的接触距离。默认值为0.04米。如果模拟的是非常小的对象,应该减小该值。
-
friction_correlation_distance - 如果接触点之间的距离小于相关距离,可以将接触点合并为单个摩擦锚点。默认值为0.025米。
PhysX可视化调试器(PVD)
当使用PhysX模拟时,PhysX可视化调试器(PVD)允许您可视化、调试和交互物理场景表示:https://developer.nvidia.com/pvd-tutorials
只有在使用PhysX后端时,PVD才会起作用。
如果您正在编译源代码,请搜索premake5.lua中是否有以下行:
def{ "USE_PHYSX" "_toggle", "On" }
将其更改为:
def{ "USE_PHYSX" "_toggle", "On" }
然后重新编译以启用PVD调试。
local physxLibs = "profile"
将physxLibs变量设置为“profile”或“checked”以使PVD正常工作。如果更改此变量,请确保重新构建。
默认情况下,Gym将尝试连接到在本地主机上运行的PVD。如果您希望连接到另一台机器上的PVD,请将环境变量GYM_PVD_HOST设置为IP或主机名。
您可以在终端中设置环境变量,也可以在Python脚本中这样做:
import os
os.environ["GYM_PVD_HOST"] = "xxx.yyy.zzz.www"
如果您希望将PVD捕获保存到文件而不是连接到实时的PVD,将环境变量GYM_PVD_FILE设置为文件名。您可以省略扩展名。
例如:
os.environ["GYM_PVD_FILE"] = "foo"
将创建一个名为foo.pxd2的文件。