Archived

This topic is now archived and is closed to further replies.

Car engine simulation questions

This topic is 5006 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I just started driving school and also decided to try to simulate a car (engine at first though)... Well, I''ve done this little "simulator", which works quite well. The problem is that I don''t understand how should I disconnect rpm from the wheel velocity! I calculate the torque from the rpm which I calculate from wheel''s angular velocity. So to get the motor even running, I have to give it some fixed velocity at the start Now if the rpm gets too low, I can''t get any torque from the engine - I need a clutch! How in the hell should I implement one? How should I simulate engine braking? At the moment only thing that lowers rpm is air drag (actually air drag decreases velocity which in case decreases rpm) At the moment torque curve (in this simulation) limits the maximum rpm to 6000. How should I limit the rpm in case I get the clutch to work? (in neutral when flooring the gas?) Any ideas are welcomed
namespace Obnoxious
{
	public sealed class CarEngine
	{
		private float GetRpm()
		{
			// Get the rpm from the velocity

			float wheelAngularVelocity = velocity / wheelRadius;
			float rpm = wheelAngularVelocity * ratios[gear - 1] * differentialRatio;

			// Convert to revolutions per minute

			rpm *= (60.0f / (2 * (float)Math.PI));
			return rpm;
		}

		private float GetTorque(float rpm)
		{
			// Clamp the rpm between 0 and 10000

			rpm = Math.Max(0, Math.Min(rpm, 10000.0f));

			// Get the torque array location for the rpm

			// The closest array location is searched and the

			// correct torque is then interpolated between the

			// current array location and the next one

			float rpmIncrementInTorqueArray = 500.0f;
			float floatingArrayPosition = rpm / rpmIncrementInTorqueArray;
			int exactArrayPosition = (int)floatingArrayPosition;
			float interpolationAmount = floatingArrayPosition - (float)exactArrayPosition;

			// Get the torques around the current position

			float firstTorque = torque[exactArrayPosition];

			if(++exactArrayPosition > torque.Length - 1)
				exactArrayPosition = torque.Length - 1;

			float secondTorque = torque[exactArrayPosition];

			// Calculate the interpolated torque using the remainder

			// left from the division above

			float interpolatedTorque = (1.0f - interpolationAmount) * firstTorque + interpolationAmount * secondTorque;
			return interpolatedTorque;
		}

		private float GetDrive(float rpm)
		{
			// Return the real torque the engine would give

			float maximumTorque = GetTorque(rpm);
			float engineTorque = maximumTorque * throttle;
			float gearTorque = engineTorque * ratios[gear - 1];
			float driveTorque = gearTorque * differentialRatio;
			return (driveTorque * transmissionEfficiency);
		}

		private float GetDrag()
		{
			// Simply calculate the air drag, everyone knows the formula :)

			return (0.5f * coefficientOfFriction * frontalArea * airDensity * (velocity * velocity));
		}

		public void Update()
		{
			float acceleratingForce = GetDrive(GetRpm()) - GetDrag() - (brake * brakingForce);
			velocity += acceleratingForce / mass;

			if(velocity < 0)
				velocity = 0;
		}

		public int Gear
		{
			get { return gear; }
			set { gear = Math.Max(1, Math.Min(value, ratios.Length)); }
		}

		public float Throttle
		{
			get { return throttle; }
			set { throttle = Math.Max(0, Math.Min(value, 1.0f)); }
		}

		public float Brake
		{
			get { return brake; }
			set { brake = Math.Max(0, Math.Min(value, 1.0f)); }
		}

		public float Velocity { get { return velocity; } }
		public float Rpm { get { return GetRpm(); } }

		// Values that user changes to affect the engine

		private int gear = 1;
		private float throttle = 0;
		private float brake = 0;

		// User cannot change

		private float velocity = 4.0f;

		// Values that will be ready or will be read from the disk

		private float differentialRatio = 3.42f;
		private float transmissionEfficiency = 0.7f;
		private float wheelRadius = 0.34f;
		private float mass = 2000.0f;
		private float coefficientOfFriction = 0.3f;
		private float frontalArea = 2.2f;
		private float airDensity = 1.29f;
		private float brakingForce = 1000.0f;

		private float[] torque = {
									 // Torque	// Rpm		// Array location

									 0,			// 0		0

									 0,			// 500		1

									 390.0f,	// 1000		2

									 420.0f,	// 1500		3

									 430.0f,	// 2000		4

									 440.0f,	// 2500		5

									 450.0f,	// 3000		6

									 460.0f,	// 3500		7

									 480.0f,	// 4000		8

									 480.0f,	// 4500		9

									 470.0f,	// 5000		10

									 450.0f,	// 5500		11

									 0,			// 6000		12

									 0,			// 6500		13

									 0,			// 7000		14

									 0,			// 7500		15

									 0,			// 8000		16

									 0,			// 8500		17

									 0,			// 9000		18

									 0,			// 9500		19

									 0};		// 10000	20


		private float[] ratios = {
									 // Ratio	// Gear number	// Array location

									 2.66f,		// 1			// 0

									 1.78f,		// 2			// 1

									 1.3f,		// 3			// 2

									 1.0f,		// 4			// 3

									 0.74f,		// 5			// 4

									 0.5f};		// 6			// 5

	}
}
Business is business and Moses is Moses [Homesite]
Yes, you do need a clutch. Basically you can make it a boolean value for engaged or disengaged. When it is disengaged (from the driveline) the engine RPM will be independent of wheel RPM. You can limit the RPM in neutral the same way everyone else does: simulate an electronic rev limiter that just kills fuel at a certain RPM.

Share this post


Link to post
Share on other sites
Ok, but how do I calculate the rpm when disengaged from wheels? I''m now calculating the rpm from the wheel angular velocity. To make things a bit harder, the clutch cannot be boolean... It should rather be a value in range [0,1].

The problem is that I cannot figure out a way to calculate the rpm from somewhere else than the wheels. Also the engine breaking should be modeled, but I haven''t got a clue which is the realistic way.

Business is business and Moses is Moses
[Homesite]
*laugh* Realistically simulating clutch depression on a computer is absurd. Even the most realistic racing games (NASCAR Thunder 2004 f.i.) that have clutches in them do not support real clutch depression. But if you want to do it, have at it, I don''t really have any suggestions for that.

To simulate engine speed when the clutch is disengaged you do the following:

e = engine speed at idle
e[m] = engine speed at rev limiter
e[c] = e[i] + %pedalDepression * e[m]

Engine braking is calculated as follows:

When the car is in gear but the gas pedal is not depressed then you have a situation where the momentum of the car is turning the axles, which in turn turns the differential, which in turn turns the driveshaft, turning the gears, turning the input shaft, turning the crankshaft. The resistance to motion is the crankshaft''s resistance to motion. You need to find the moment of inertia of the crankshaft and use that to retard momentum.

Share this post


Link to post
Share on other sites
Thanks, I'll start thinking this now. I just wonder how the clutch is implemented in lfs (Live For Speed)? It seems quite realistic.

What do you actually mean with crankshaft's inertia? My english lacks here, so could you explain how could it be implemented?

edit: A new problem I can't get fixed It goes like this: I update the engine 20 times a second, and that's a constant. I have every other value physically correct, expect this update frequency. The motor is reacting way too fast... If I floor the gas with 1st gear, car accelerates to 85 km/h way too fast. This far I have just multiplied the final acceleratingForce with some constant (0.2f for example). How should I make this work realistically? (Like if I put in a real cars values, and floor the gas, the car would accelerate just like in real life)

Business is business and Moses is Moses
[Homesite]

[edited by - Miksan on March 26, 2004 4:29:06 PM]
Hi,

Engine: I suggest having a separate class for this part of car (too). It would store its behaviour (torque curve), inertia, friction coeff, minimal rpm etc.
Variables would be the actual rpm, and the torque at this rpm. The final torque will include the friction as well.
I don''t think you need a limiter. Because at 6000 your net torque is 0, so the engine''s rpm won''t increase any more, rather decrease because of the friction. So if you integrate correctly and your calculation are based on laws of physics, it should behave this way.

If I were you I would handle the car parts separatly, I would not integrate it so much. For driveline modelling (including clutch !!!) check out google with ''driveline modelling'' keyword. The first will be a PDF, which is quite good! I will also apply it.
Clutch can be simulated correctly, you just should have a pedal to control it.

For accurate simulation you should use better integration than Euler (it''s rather unstable). I use RK4, which is very accurate and stable, but slower of course. But RK2 is also good for a game. You can also mix them to get optimal performance and accuracy.

So my suggestions:
- separate classes for parts of the car, like engine, clutch, gearbox, differential, wheel, tyre, body, suspension, control (for applying input)
- use OOP technics, like abstract classes, inheritence, virtual method. For example CTyre is an abstract class, and you derive specific models like CTyrePacejka. This way you can easily change tyre models, even during running the simulation (!)
- good integrators, I have separate classes for these like RK4, RK4Linear, RK4Rotational
- use accurte timing with PerformanceCounter
- low, perhaps constant timestep


Good luck!

OffTopic:
The most impressive simulator was LFS for me so far. I have just tried CMR4, but I could not notice much difference to CMR2 in it. And when revesing with quite low speed (no slide), the back wheels move VERY strange !!! Check it out. It''s a shame. MY sim behaves better in this situation, seriously.

Share this post


Link to post
Share on other sites
When you simulate the motion of a rigid body, you will have a timestep of for example 2 ms. This shows how often you "take a sample" of the forces, torques acting your rigid body. Knowing the force and mass you can calculate the acceleration at that moment. From the torque and the inertia you can calculate the angular acceleration at that moment. Then you integrate acceleration through the timestep to get the new velocity: vel+=timestep*acc.
And then integrate the velocity to get the new position: pos+=timestep*vel.
This was the Euler integration method. This is easy to understand, it''s quite unaccurate and sometimes unstable. That''s why it is wise to use different integration methods for example to get the new velocity from the acceleration, the timestep, and the previous velocity.
Euler method is a first order method, so you have to take sample once through a timestep.
RK2 is a second order one, so you have to take sample twice: once at the current time, and once at the middle of the timestep (current time + timestep/2). It gives a more precise result.
RK4 is a fourth order so 4 sample per timestep (one at the current time, two at the middle, and one at the end of the timestep), the result is accurate, provided the timestep is small enough. With a timestep about 0.01 sec this methos also may become unaccurate and unstable.
The best and simplest example to compare the methods is to simulate an ideal spring with the same timestep. With Euler the amplitude will be larger and larger as the time goes by.
With Runge-Kutta methods this increase is quite smaller. But in real life there is always some kind of damping everywhere, so for these methods it does not care.
Hope this helps

Share this post


Link to post
Share on other sites
Miksan: now your Update() method realizes an Euler integration of acceleration. But your timestep seems to be 1 sec or what.
I suggest using SI units.
Use QueryPerformanceCounter() and QueryPerformanceFrequency() to get the accurete time.


[edited by - szinkopa on March 27, 2004 6:30:58 PM]

Share this post


Link to post
Share on other sites
Yes you should. But I would decrease this timestep with this Euler integration to 1-2 ms to keep it stabler. With RK2 perhaps 3-4 ms would be ok yet. And with RK4 perhaps up to 8 ms. But this timestep is related to how huge the applied force or torque is. If it''s huger you should use smaller timesteps.
When your engine did not stop accelerating, it was due to the instability, I think.
And because of not writing this 0.05, your car accelerated too fast, 20 times faster than it should.

Share this post


Link to post
Share on other sites
Yes you should. But I would decrease this timestep with this Euler integration to 1-2 ms to keep it stabler. With RK2 perhaps 3-4 ms would be ok yet. And with RK4 perhaps up to 8 ms. But this timestep is related to how huge the applied force or torque is. If it''s huger you should use smaller timesteps.
When your engine did not stop accelerating, it was due to the instability, I think.
And because of not writing this 0.05, your car accelerated too fast, 20 times faster than it should.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Remember that torque is not a direct function of rpm, it depends more on throttle position than rpm. Im sure youre taking this into account though...

My thought for engine breaking was to have "negative" torque for whatever set of values of rpm and throttle position.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Remember that torque is not a direct function of rpm, it depends more on throttle position than rpm. Im sure youre taking this into account though...

My thought for engine breaking was to have "negative" torque for whatever set of values of rpm and throttle position.


Yep, this line here:
float engineTorque = maximumTorque * throttle;

I was just thinking how would this euler''s integration "instability" or "blowing up" affect the motor system? I really don''t get it where is it unstable? Or when might it blow up? (Revving too long too high, of course )



Business is business and Moses is Moses
[Homesite]
I'm trying to do the exact same thing. Would you mind letting me have a look at the code? I really suck at car physics and it would be good to see an example that works. I've tried using Marco Monsters tutorial but I can't seem to make a decent implementation.. you seem to be on the right track.

There really isn't any good info to be found. I wish someone would put up a tutorial with example classes for a 2d car physics engine. Everything is either 3D or really complex.

[edited by - Lightstrike on March 30, 2004 11:33:32 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Lightstrike
I'm trying to do the exact same thing. Would you mind letting me have a look at the code?


Did you mean me? Look at the first post. There's the first version I made, it lacks clutch though.

Or did you mean the one with all parts separated as classes? I'm not going to show anything yet That's because I've got something like three different solutions for it, and I don't know yet which of them works the best.

I have now implemented the engine, clutch, gearbox, differential and wheel parts. At the moment they all work in like 1-dimension, so differential only acts like it's coupled with one wheel

I haven't been doing anything with the driveline for past few days, because I got interested in doing some sort of sound system for the motor. It's a bit of pain in the ass, because I haven't ever done anything with sounds before. But I think it's going to be very cool if I get it working...

edit: Btw, Lightstrike, that Street Cars is way too cool Reminds me of GTA.

I'm also trying to implement a real engine behaviour - so that the engine will stall out if you get rpms too low. And to get it running, you have to use starter engine I thought this was unique, but I just tried Toca Race Driver 2... It has very cool engine behaviour.

Business is business and Moses is Moses
[Homesite]

[edited by - Miksan on March 30, 2004 2:39:09 PM]
quote:
Original post by Miksan
Or did you mean the one with all parts separated as classes? I'm not going to show anything yet That's because I've got something like three different solutions for it, and I don't know yet which of them works the best.



Yeah, hehe okay. I finally understood some parts of the tutorial so I've managed to get started but I haven't reached the slip stuff yet.

quote:
Original post by Miksan
I have now implemented the engine, clutch, gearbox, differential and wheel parts. At the moment they all work in like 1-dimension, so differential only acts like it's coupled with one wheel



hehe well thats cool too

quote:
Original post by Miksan
I haven't been doing anything with the driveline for past few days, because I got interested in doing some sort of sound system for the motor. It's a bit of pain in the ass, because I haven't ever done anything with sounds before. But I think it's going to be very cool if I get it working...



yeah it is.. we actually got the sound engine 100% ready now and it feels great

quote:
Original post by Miksan
edit: Btw, Lightstrike, that Street Cars is way too cool Reminds me of GTA.



Thanks.. I'm reworking the physics for it now. How did you know I was making it?

quote:
Original post by Miksan
I'm also trying to implement a real engine behaviour - so that the engine will stall out if you get rpms too low. And to get it running, you have to use starter engine I thought this was unique, but I just tried Toca Race Driver 2... It has very cool engine behaviour.



yeah its a cool feature.. is there a demo out for race driver 2?

[edited by - Lightstrike on March 30, 2004 4:04:34 PM]

Share this post


Link to post
Share on other sites