ODE (Open Dynamics Engine) 初級講座の第12回目です。
今回は摩擦について説明します。摩擦については高校で習ったと思います。fNを法線方向、fTを接線方向の力ベクトル、μを摩擦係数とすると以下の公式が成り立ちます。
|fT|
接触面の方向によらず上の式が成り立つ場合は、上の不等式は、円錐の軸がfNで、接触点が頂点の摩擦円錐となります。 fNとfTの合力である摩擦力ベクトルが摩擦円錐内にあれば滑りは発生しませんが、外に出ると滑り出すことになります。
ODEの摩擦モデルはクーロン摩擦モデルの近似です。高速化のために摩擦円錐を次の2通りのモデルで近似しています。特に設定しない場合は、最も単純な最大摩擦力近似となります。摩擦がシミュレーションに重要な影響を及ぼす場合は摩擦四角錘近似を選択してください。なお、ODEでは静止摩擦係数、動摩擦係数の区別はありません。
1. 最大摩擦力近似 (constant force limit)
摩擦係数μを接触点における接線方向の最大摩擦力と近似する。つまり、法線方向の力を考慮しない単純なモデルです。
2. 摩擦四角錘近似(friction pyramid approximation)
摩擦円錐を摩擦四角錘で近似します。このモデルを選択するためには接触フラグにdContactApprox1を設定します。
具体的な設定方法を以下のプログラムに示します。17行目で摩擦四角錘近似を設定するためにdContactApprox1を設定しています。これが有効になるのは衝突するジオメトリがbox[0].geomの場合で、それ以外のジオメトリは最大摩擦力近似となります。
サンプルプログラムでは斜面の角度を少しずつ増加させ、2つのボックスが滑り出す角度が違うことがわかります。摩擦係数を1に設定しているため、ボックスが滑り始める角度の理論値は45度になります。摩擦四角錘近似モデルの場合(左側の赤いボックス)は約45度で滑り出しますが、最大摩擦近似モデルではそれより小さい角度で滑り出すことが確認できると思います。
サンプルプログラムを次からダウンロードして確認してみてください。
今回はここまでとします。
static void nearCallback(void *data, dGeomID o1, dGeomID o2) { const int N = 10; dContact contact[N]; if (((o1 == ground) && (o2 == slope )) || ((o1 == slope) && (o2 == ground))) return; int isGround = ((ground == o1 || slope == o1) || (ground == o2 || slope == o2)); int n = dCollide(o1, o2, N, &contact[0].geom, sizeof(dContact)); if (isGround) { for (int i = 0; i < n; i++) { if ((o1 == box[0].geom) || (o2 == box[0].geom)) { // friciton: friction pyramid model 摩擦四角錘近似 contact[i].surface.mode = dContactApprox1|dContactSoftERP|dContactSoftCFM; } else { // friction: constant force limit model 最大摩擦力近似 contact[i].surface.mode = dContactSoftERP|dContactSoftCFM; } contact[i].surface.mu = 1.0; // dInfinity; contact[i].surface.soft_erp = 1.0; //1.0; contact[i].surface.soft_cfm = 1e-10; dJointID c = dJointCreateContact(world, contactgroup, &contact[i]); dJointAttach(c,dGeomGetBody(contact[i].geom.g1), dGeomGetBody(contact[i].geom.g2)); } } }