由于Chrono的官方教程在一些细节方面解释的并不清楚,自己做了一些尝试,做学习总结。
今天突发奇想,想试一下,是否可以实现两个vehicle的碰撞?
1、两辆vehicle的仿真
官方提供了demo_VEH_TwoCars
这个demo,用来参考两个车的例子。
对于一个车而言,我们不需要专门制定Chrono的系统是什么,即只需要用Vehicle在创建时自动生成的system即可。
通过vehicle的底层代码,可以看到构造函数有两种,一种是不指定system,另一种是指定system的:
之前的例子,用的都是第一种初始化,这样在实际使用时,如果涉及到地形模块的交互,只需要在创建地形时,传入vehicle绑定的系统即可,例如:
HMMWV_Full hmmwv;
RigidTerrain terrain(hmmwv.GetSystem());
但是,如果有两个vehicle,再创建一个新的vehicle就会出现麻烦:他两个处于不同的物理系统。
于是,我们参考官方的例子,首先创建一个物理系统,然后在创建vehicle时指定同一个system即可:
// 创建物理仿真系统,并指定一些参数。
ChSystemNSC sys;
sys.SetCollisionSystemType(ChCollisionSystem::Type::BULLET);
sys.Set_G_acc(ChVector<>(0, 0, -9.81));
sys.SetSolverType(ChSolver::Type::BARZILAIBORWEIN);
sys.SetSolverMaxIterations(150);
sys.SetMaxPenetrationRecoverySpeed(4.0);
// 创建第1个vehicle
HMMWV_Reduced hmmwv_1(&sys);
// 创建第2个vehicle
HMMWV_Reduced hmmwv_2(&sys);
接下来,在仿真循环中,我们需要对系统进行动力学仿真。调用:sys.DoStepDynamics(step)
。
hmmwv_1.Advance(step_size);
hmmwv_2.Advance(step_size);
terrain.Advance(step_size);
vis->Advance(step_size);
// Advance state of entire system (containing both vehicles)
sys.DoStepDynamics(step_size);
之前采用vehicle的方式写代码时,不需要写出来这一句DoStepDynamics,因为在vehicle的Advance()
中,最终调用了vehicle自己system的DoStepDynamics
。如果这里我们忽略了最后这一句话,vehicle在仿真系统中是不会动的、但driver的控制量是已经给上了(这个bug卡了我半天,才想到去找demo,最后发现的问题)。
2、两车的碰撞
2.1 车辆可碰撞的地方
我们知道,chrono里面,有这个东西、可以看到可视化、以及会发生碰撞,这几件事情是没有关系的。
那首先就要搞清楚,对于一个vehicle来说,哪些地方可以“碰撞”。
从官方介绍中,可以得知,任何vehicle都包括底盘,轮式车辆又包括:悬挂、转向、传动、轮胎模型。
经过测试,轮胎、底盘是可以发生碰撞的,实际碰撞的位置如下图所示:
除了4个车轮、底盘圈出来的这部分,其他地方貌似是无法发生物理碰撞的。
2.2 碰撞设置
要想发生碰撞,需要对碰撞进行设置,包括:
- 设置system的碰撞
- 设置车辆的碰撞方法
- 设置车辆具体哪个地方可以碰撞
其中,system和车辆的碰撞设置,例如采用Bullet碰撞
// system碰撞设置
auto collision_type = ChCollisionSystem::Type::BULLET;
sys.SetCollisionSystemType(collision_type);
// 车辆碰撞设置
car1.SetCollisionSystemType(collision_type);
但是,仍需要设置,车辆哪些地方的碰撞需要启用?即需要使能。
翻阅官方文档,共有三个函数相关,分别是:
SetChassisCollide
: Enable/disable collision for the chassis subsystem. This function controls contact of the chassis with all other collision shapes in the simulation.SetChassisVehicleCollide
: Enable/disable collision between the chassis and all other vehicle subsystems. Note that some of these collisions may be always disabled, as set by the particular derived vehicle class.SetWheelCollide
: Enable/disable collision for the wheel subsystems.
注意,前两个是vehicle模块都具备的函数,第三个是wheel类型的vehicle所特有的。
第一种和第二种的区别:第一个是底盘和所有物体的碰撞;第二个是底盘和vehicle本身发生碰撞。
官方建议,当chassis或wheel一个设置为true时,另一个设置为false,避免出现bug。
2.3 结果
轮胎的碰撞:
可以看到,当两个车的轮胎碰上时,会发生碰撞,但车体之间可以相互“穿越”。
底盘碰撞:
可以看到,底盘碰撞时,轮胎可以重合,但是在底盘部分会发生碰撞,改变车的结构。
3、思考:车外壳碰撞
以上方法,只能够实现部分体积的碰撞,但车体的“外壳”无法碰撞。
自己尝试了一下,发现实现起来比较困难,原因如下:
虽然车体外壳的mesh是属于chassis控制,但chassis的体积只有上述部分,外壳部分是没有碰撞体积的;外壳碰撞时,并不会有外部的力影响车辆系统,因此,即使定义一个“无可视化”的ChBody与车体坐标系绑定,当ChBody间发生碰撞时,碰撞的力不知道怎么传递到车辆底盘,进而改变车体的各个子系统,即“碰撞”或许能看出来,但后续车辆的运动,不符合“车辆模型+控制量+碰撞”共同造成的影响。
希望有高手提供思路。