Page 1 of 1

Reduce time simulation

Posted: Thu May 26, 2016 12:14 pm
by MRENOU
Hi everybody,

I'm new with bullet physics.
I did a simulation of a robot with articulations (hinge and motor) and I displayed it with OpenGL, it works well ! Every second, I give new position control to motors in order to move the robot.

However, I'm now trying to do the same thing and to have the same results, but not in real time... In real time it take like 30 seconds to do my simulation but if I could reduce it to 1 second (without display of course) or less with the same results it would be wonderful...

I think it's here that I need to change something :

Code: Select all

if (myWorld){
			myWorld->stepSimulation(1);
		}
But I don't know how.

I read this but I'm not sure to really understand : http://bulletphysics.org/mediawiki-1.5. ... _The_World

I hope that it's possible !
Thanks a lot :D (and sorry for this horrible english..)

Re: Reduce time simulation

Posted: Thu May 26, 2016 3:40 pm
by Basroil
That code simply means that you want to take a 1 second step using the default parameters (1/60s substep, etc), which doesn't sound like what you want to do. If you aren't using GUI, the method is very easy, just loop the world step command with the substep size as fast as you can, something like:

Code: Select all

while(m_time<30.0){
myWorld->stepSimulation(1.0/60.0);
}
If you must use "realtime" GUI, it will be a bit more complicated as slow computers might not be able to handle the number of substeps necessary for a certain speed. If you know your computer handles 30x speed, you can use

Code: Select all

myWorld->stepSimulation(oglDT * 30.0, largeNumber, frequency);
where the oglDT is time between render frames, largeNumber is a number that will handle a reasonable amount of substeps, and frequency is the substep frequency. If largeNumber is too large and your computer too slow, you could get a runaway latency, where substeps still needed to be calculated keep increasing. If the number of backlogged steps exceeds that largeNumber, you'll start skipping simulation frames and end up with lower quality results.

A good way to avoid that issue is to simply do 30 steps per frame (30.0x1.0/60.0 step size), but you'll end up lower than 30x realtime rendering if your computer can't finish in time (time drifts closer to 1x)

Re: Reduce time simulation

Posted: Thu May 26, 2016 4:06 pm
by benelot
Hello MRENOU,

Welcome to the Bullet Physics forum!

Sounds like you have a nice project going on there.

So what you need is to step the world as fast as possible without making the simulation going undeterministic.

You refer to the right sources, and you definitely want to also look into the canonical game loop page (it is actually the update loop of your simulation):
http://www.bulletphysics.org/mediawiki- ... _Game_Loop

What you want to separate in your code is the physics simulation (here called the Model) and your visualization (The View). If you separated this well enough, so that the View reads the visualization directly from the model, and if you leave out the view update, the simulation runs headless, then you are on the right track.

I can give you an example on how to do this:

What the code needs to correctly run the update loop:

Code: Select all

     // loop timing components ###################
	//# loop timestamps
	Some::Timer mSomeTimer; /**!< The some timer to time the loop correctly */
	unsigned long int mApplicationStart; /**!< The time the application was started (absolute, in Milliseconds) */
	unsigned long int mPreviousModelIteration; /**!< The previous model iteration timestamp (absolute, in Milliseconds) */
	unsigned long int mThisModelIteration; /**!< This model iteration timestamp (absolute, in Milliseconds) */

	//# loop durations
	long int mModelAccumulator; /**!< The time to forward the model in this loop iteration (relative, in Milliseconds) */
	unsigned long int mFrameTime; /**!< The time to render a frame (relative, in Milliseconds) */
	unsigned long int mApplicationRuntime; /**!< The total application runtime (relative, in Milliseconds) */

	long int mInputDt; /**!< The time difference of input that has to be fed in */
	unsigned long int mInputClock;

	long int mLastGraphicsTick; /*!< The time it took the graphics rendering last time (relative, in Milliseconds) */
	unsigned long int mGraphicsStart;

	long int mLastInputTick; /**!< The time it took the input to process last time (relative, in Milliseconds) */
	unsigned long int mInputStart;

	long int mLastModelTick; /**!<  The time it took the model to update last time
	 This includes the bullet physics update */
	long int mModelStart; /**!< The timestamp the model started updating last (absolute, in Milliseconds)*/

	long int mPhysicsTick; /**!< The time remaining in the loop to update the physics (relative, in Milliseconds)*/
	long int mPhysicsStepStart; /**!< The physics start timestamp (absolute, in Milliseconds) */
	long int mPhysicsStepEnd; /**!< The last physics step end (absolute, in Milliseconds) */
       bool mPhysicsPaused;

/**
 * Step size of the bullet physics simulator (solverAccuracy). Accuracy versus speed.
 */
//#define FIXED_STEPS_PER_SEC 60.0f // Too low
//#define FIXED_STEPS_PER_SEC 120.0f // Might be too low
//#define FIXED_STEPS_PER_SEC 200.0f // Might be ok
#define FIXED_STEPS_PER_SEC 240.0f // Might be better
//#define FIXED_STEPS_PER_SEC 1000.0f // Best results
const double PhysicsConfiguration::SIMULATOR_PHYSICS_FIXED_STEPS_PER_SEC =
FIXED_STEPS_PER_SEC;
const double PhysicsConfiguration::FIXED_STEP_SIZE_SEC = 1.0f / FIXED_STEPS_PER_SEC;
const double PhysicsConfiguration::FIXED_STEP_SIZE_MILLI = 1000.0f / FIXED_STEPS_PER_SEC;

const double PhysicsConfiguration::BULLET_OGRE_BOX_SCALING_FACTOR = 0.01; /**!< A box of unit size in ogre has the size of 100 in bullet */

const double PhysicsConfiguration::BULLET_DEACTIVATION_TIME = 5; /**!< The deactivation time of a bullet object */
const double PhysicsConfiguration::BULLET_LINEAR_SLEEPING_TIME = 1.6; /**!< The time to sleep with linear movement */
const double PhysicsConfiguration::BULLET_ANGULAR_SLEEPING_TIME = 5; /**!< The time to sleep with angular movement */

const double PhysicsConfiguration::SIMULATION_SPEEDS[] = { /**!< The simulation speeds of the Bullet Physics simulation*/
-2,/**!<SIMULATION_SPEED_01*/-1,/**!<SIMULATION_SPEED_02*/
0,/**!<SIMULATION_SPEED_03*/1,/**!<SIMULATION_SPEED_04*/
2,/**!<SIMULATION_SPEED_05*/3,/**!<SIMULATION_SPEED_06*/
4, /**!<SIMULATION_SPEED_07*/5,/**!<SIMULATION_SPEED_08*/
0, /**!<SIMULATION_SPEED_09 run as fast as possible with graphics*/
0 /**!<SIMULATION_SPEED_10 run as fast as possible headless*/
};
What you do in every update:

Code: Select all

	// structure according to the canonical game loop
	// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Canonical_Game_Loop

	//##############
	// breaking conditions - if the loop should stop, then check it here

	//#############
	// model update
	do {
		// update timers
		mThisModelIteration = mSomeTimer.getMilliseconds();
		mFrameTime = mThisModelIteration - mPreviousModelIteration; /**!< Calculate the frame time (in Milliseconds) */
		mPreviousModelIteration = mThisModelIteration;

		mApplicationRuntime = mThisModelIteration - mApplicationStart; /**!< Update main frame timer (in Milliseconds) */

		mModelStart = mSomeTimer.getMilliseconds(); /**!< Begin with the model update (in Milliseconds)*/
		mLastGraphicsTick = mModelStart - mGraphicsStart; /**!< Update graphics timer (in Milliseconds) */

		mUniverse.setSimulationSpeed(mCurrentSimulationSpeed); /**!< Set the current simulation speed of the simulation */

		if (mCurrentSimulationSpeed == PhysicsConfiguration::SIMULATION_SPEED_09 /** If we are in speed 9 or 10*/
			|| mCurrentSimulationSpeed
				== PhysicsConfiguration::SIMULATION_SPEED_10) {
			mPhysicsTick = ApplicationConfiguration::APPLICATION_TICK /**!< calculate the remaining time for physics (in Milliseconds) */
			- mLastGraphicsTick - mLastInputTick;

			mPhysicsStepStart = mOgreTimer.getMilliseconds(); /**!< The physics updates start (in Milliseconds)*/

			while (mPhysicsTick > mPhysicsStepEnd - mPhysicsStepStart) { /**!< Update the physics until we run out of time (in Milliseconds) */
				mWorld.update(PhysicsConfiguration::FIXED_STEP_SIZE_SEC); /**!< update the world (in Seconds) */
				mPhysicsStepEnd = mSomeTimer.getMilliseconds(); /**!< Update the last physics step end to stop updating in time (in Milliseconds) */
			}
		} else { /**!< This mode tries to progress as much time as it is expected from the game loop*/
			if (mFrameTime > ApplicationConfiguration::APPLICATION_TICK) { /** cap frametime to make the application lose time, not the physics (in Milliseconds) */
				mFrameTime = ApplicationConfiguration::APPLICATION_TICK;
			}

			mModelAccumulator += mFrameTime; /**!< Update physics update time that we are going to use (in Milliseconds) */
			double speed = pow(2, /**!< calculate the speed of the simulation */
			PhysicsConfiguration::SIMULATION_SPEEDS[mCurrentSimulationSpeed]);

			int steps = floor(
				mModelAccumulator
					/ PhysicsConfiguration::FIXED_STEP_SIZE_MILLI); /**!< Calculate the number of full normal time steps we can take */

			if (steps > 0) { /**!< Update if we can take at least one step */
				mUniverse.update(
					speed * steps * PhysicsConfiguration::FIXED_STEP_SIZE_SEC); /**!< update the universe (in Seconds) */
				mModelAccumulator -= steps
					* PhysicsConfiguration::FIXED_STEP_SIZE_MILLI; /**!< Subtract the number of full normal time steps (in Milliseconds) */
			}
		}

		mInputStart = mOgreTimer.getMilliseconds(); /**!< Start the input update */
		mLastModelTick = mInputStart - mModelStart; /**!< Calculate the time the model update took */

		//#############
		// Input update - Game Clock part of the loop
		/** This runs once every APPLICATION_TICK milliseconds on average */
		mInputDt = mThisModelIteration - mInputClock;
		if (mInputDt >= ApplicationConfiguration::APPLICATION_TICK) {
			mInputClock = mThisModelIteration;
			mInputHandler.injectInput(); /**!< Inject input into handlers */
			mInputHandler.update(mInputClock); /**!< update elements that work on the current input state */
		}

		mGraphicsStart = mSomeTimer.getMilliseconds(); /**!< Start the graphics update */
		mLastInputTick = mGraphicsStart - mInputStart; /**!< Calculate the time the input injection took */

	} while (mStateHandler.getCurrentState()
		== StateHandler::HEADLESS_SIMULATION); /**!< In headless simulation we never update the graphics */

	//#############
	// Graphics update
	updatePanels(evt.timeSinceLastFrame); /**!< Update the information in the panels on screen if any */

	mViewController.update(evt.timeSinceLastFrame); /**!< Update view */

	mWorld.drawDebugWorld(); /**!< draw the debug output if enabled */
In the code above, I called a non-existing method in mWorld, which is update(), it does the following:

Code: Select all

//step the simulation
	if (mDynamicsWorld && (!mPhysicsPaused)) {

		if (timeStep) {
			// since we want to see all substeps, we make them by ourselves
			int subSteps = 1;

			mDynamicsWorld->stepSimulation(btScalar(timeStep),
				btScalar(subSteps),
				btScalar(PhysicsConfiguration::FIXED_STEP_SIZE_SEC));
		}
	}
It takes a while to understand the structure, so it is best for you to first read the canonical game loop page and the links provided there. Then look at my example code.

The code is based on snippets from my simulator, which implements the functionality (starting in frame rendering queued):
https://github.com/benelot/minemonics/b ... anager.cpp

If I find time, I will write an example for the bullet physics example browser on the topic to clear things up.

Edit: I see that Basroil posted earlier :D

Here is a thread were we discussed this before:
http://www.bulletphysics.org/Bullet/php ... ilit=speed

Edit: In case you do not get my posted code segments (there are some undefined parts in it I realized, I am just working on an example for the example browser und how to reduce simulation time.)

Re: Reduce time simulation

Posted: Fri May 27, 2016 7:50 am
by MRENOU
Hi !

Thanks a lot guys ! That's exactly what I want. In fact I'm doing quite the same project than alberto2000, I didn't find his topic in my searches.

I will read that this afternoon, I think it will be ok :)

Thanks again ! :D