Rolling Friction Scaling issues
Posted: Fri Oct 18, 2019 12:50 pm
I am having some issues with Rolling Friction when scaling my world up.
I am trying to simulate a small sphere that starts with linear velocity and no angular velocity. According to the physics/mathematical model, we should have the ball first sliding with fast deceleration whilst linear velocity decreases heavily but angular velocity increases. When the ball starts rolling, the kinetic friction responsible for sliding no longer has any effect and the ball velocity only decreases because of rolling friction.
So what I want to do; sphere experiences kinetic friction u under sliding and rolling friction u_r when rolling (With the total friction force being u*F_n for both, F_n being the normal force).
Since the sphere and other objects are small I need to scale up the world as recommended by the wiki. However, Rolling friction just is not behaving as I expect it to. When I scale up the world by factor X, the rolling friction seems to decrease by factor 1/X even though I am setting it as constant. Even when the objects are in the 0.5-10 size range as recommended I am still experiencing this. Also; even at scale 1 the rolling friction is off by a huge factor, being much larger (~ 3 to 4 times) than the actual kinetic friction even though it's roughly 1/10th of the value.
Questions:
- How is rolling friction modelled/implemented in bullet?
- Why is the rolling friction larger than my kinetic friction even though the value is smaller at scale 1?
- How is rolling friction dependent on my world scaling? (Am I making a mistake somewhere?)
I am probably doing something wrong with scaling or misunderstanding how friction/rolling friction interact in bullet. Is there an easy to solution to this problem, or do I need to implement rolling friction manually? This is my first time working with Bullet and I only have very light experience with ODE before this, so feel free to point out any problems even if unrelated.
Any help would be greatly appreciated. Below is the relevant code reduced to a small example. I simply call this code from a small and simple main to test.
I am trying to simulate a small sphere that starts with linear velocity and no angular velocity. According to the physics/mathematical model, we should have the ball first sliding with fast deceleration whilst linear velocity decreases heavily but angular velocity increases. When the ball starts rolling, the kinetic friction responsible for sliding no longer has any effect and the ball velocity only decreases because of rolling friction.
So what I want to do; sphere experiences kinetic friction u under sliding and rolling friction u_r when rolling (With the total friction force being u*F_n for both, F_n being the normal force).
Since the sphere and other objects are small I need to scale up the world as recommended by the wiki. However, Rolling friction just is not behaving as I expect it to. When I scale up the world by factor X, the rolling friction seems to decrease by factor 1/X even though I am setting it as constant. Even when the objects are in the 0.5-10 size range as recommended I am still experiencing this. Also; even at scale 1 the rolling friction is off by a huge factor, being much larger (~ 3 to 4 times) than the actual kinetic friction even though it's roughly 1/10th of the value.
Questions:
- How is rolling friction modelled/implemented in bullet?
- Why is the rolling friction larger than my kinetic friction even though the value is smaller at scale 1?
- How is rolling friction dependent on my world scaling? (Am I making a mistake somewhere?)
I am probably doing something wrong with scaling or misunderstanding how friction/rolling friction interact in bullet. Is there an easy to solution to this problem, or do I need to implement rolling friction manually? This is my first time working with Bullet and I only have very light experience with ODE before this, so feel free to point out any problems even if unrelated.
Any help would be greatly appreciated. Below is the relevant code reduced to a small example. I simply call this code from a small and simple main to test.
Code: Select all
//
// Created by rolf on 17-10-19.
//
#ifndef BULLETTEST_SIMULATOR_H
#define BULLETTEST_SIMULATOR_H
#include "btBulletDynamicsCommon.h"
class Simulator {
public:
Simulator();
~Simulator();
void stepSimulator();
btVector3 ballPosition() const;
btVector3 ballVelocity() const;
btVector3 ballAngVelocity() const;
void printBallAcc() const;
private:
btVector3 lastVel=btVector3();
btDefaultCollisionConfiguration *collisionConfig;
btCollisionDispatcher *collisionDispatcher;
btBroadphaseInterface *overlappingPairCache;
btSequentialImpulseConstraintSolver *solver;
btDynamicsWorld* world;
btStaticPlaneShape* plane;
btCollisionObject* planeBody;
btSphereShape* ball;
btRigidBody* ballBody;
btMotionState* ballMotionState;
};
#endif //BULLETTEST_SIMULATOR_H
Code: Select all
//
// Created by rolf on 17-10-19.
//
#include <iostream>
#include "Simulator.h"
const float GRAVITY=-9.81;//m/s^2
const float BALLRADIUS=0.02133;//m
const float BALLMASS=0.04593;//kg
const float PLANEFRICTION=1.0f;
const float BALLFRICTION=0.35f;
const float BALLROLLINGFRICTION=0.0357f;
const float SCALE=100;
const float SIMULATIONSTEP=1/200.0;
const int SUBSTEPS=100;
const float INTERNALSTEP=1/20000.0;
Simulator::Simulator() {
btVector3 initialPos(0.0f,0.0f,BALLRADIUS*SCALE);
btVector3 initialVel(2.0f*SCALE,0.0f,0.0f);
//Contains default setup for memory and how collisions between different types of objects are handled/calculated
collisionConfig = new btDefaultCollisionConfiguration();
//uses the default dispatcher. We might want to use the parallel one down the road.
collisionDispatcher = new btCollisionDispatcher(collisionConfig);
//btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
overlappingPairCache = new btDbvtBroadphase();
//the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
solver = new btSequentialImpulseConstraintSolver();
// the world in which all simulation happens
world= new btDiscreteDynamicsWorld(collisionDispatcher,overlappingPairCache,solver,collisionConfig);
world->setGravity(btVector3(0.0,0.0,SCALE*GRAVITY));
//create a static plane
plane = new btStaticPlaneShape(btVector3(0.0f, 0.0f, 1.0f), 0.0f);
planeBody= new btCollisionObject();
planeBody->setCollisionShape(plane);
btTransform worldPlaneTransform;
worldPlaneTransform.setIdentity();
worldPlaneTransform.setOrigin(btVector3(0.0f,0.0f,0.0f));
planeBody->setWorldTransform(worldPlaneTransform);
planeBody->setRestitution(0.0);
planeBody->setFriction(PLANEFRICTION);
planeBody->setRollingFriction();
//add it to the world
world->addCollisionObject(planeBody);
//create a ball
ball = new btSphereShape(SCALE*BALLRADIUS);
btVector3 inertia;
ball->calculateLocalInertia(BALLMASS,inertia);
/*
btVector3 inertia(1.0,1.0,1.0);
inertia*=0.4*BALLMASS*BALLRADIUS*BALLRADIUS*SCALE*SCALE;
*/
btTransform worldBallTransform;
worldBallTransform.setIdentity();
worldBallTransform.setOrigin(initialPos);
ballMotionState = new btDefaultMotionState(worldBallTransform);
//construct the rigid body for collisions
btRigidBody::btRigidBodyConstructionInfo rbInfo(BALLMASS, ballMotionState, ball, inertia);
ballBody = new btRigidBody(rbInfo);
ballBody->setLinearVelocity(initialVel);
ballBody->setRestitution(0.0f);
ballBody->setFriction(BALLFRICTION);
ballBody->setRollingFriction(BALLROLLINGFRICTION);
ballBody->setSleepingThresholds(0.01*SCALE,0.01/2/M_PI);
//add the constructed rigid Body to the world
world->addRigidBody(ballBody);
std::cout<<"sliding decel: "<<BALLFRICTION*GRAVITY<<std::endl<<"rolling decel: "<<BALLROLLINGFRICTION*GRAVITY<<std::endl;
}
void Simulator::stepSimulator() {
lastVel=ballVelocity();
world->stepSimulation(SIMULATIONSTEP,SUBSTEPS,INTERNALSTEP);
}
btVector3 Simulator::ballPosition() const {
btTransform transform;
ballMotionState->getWorldTransform(transform);
return transform.getOrigin()/SCALE;
}
btVector3 Simulator::ballVelocity() const {
return ballBody->getLinearVelocity()/SCALE;
}
btVector3 Simulator::ballAngVelocity() const {
return ballBody->getAngularVelocity();
}
void Simulator::printBallAcc() const{
//print dv/dt
std::cout<<(ballVelocity()-lastVel).x()/SIMULATIONSTEP<<std::endl;
}
Simulator::~Simulator() {
delete ballBody;
delete ballMotionState;
delete ball;
delete planeBody;
delete plane;
delete world;
delete solver;
delete overlappingPairCache;
delete collisionDispatcher;
delete collisionConfig;
}