Clutch Modelling Help

Started by
17 comments, last by Vu Chi Thien 6 years, 2 months ago

Hi fellow game devs,


I'm working on a car simulator using Unity3D and currently stuck on implementing the clutch. 

Currently, my drivetrain model involves torque from engine and reaction torque from the drivetrain and is using Unity3D wheelCollider. My ultimate goal is to calculate engineRPM at each time step, from there lookup engineTorque from torque curve and send to the wheels through drivetrain. Known variables are wheelRPM (reported from wheelCollider, read only), wheelInertia (calculated from wheelMass and radius, reported from wheelCollider), and engineTorque from a torque curve. Right now for simplicity, I'm ignoring drivetrain inertia and the differential is open. 

This is my currently non-working procedure, I'm using the formula AngularAcceleration = Torque/Inertia, so each timestep engineVelocity += AngularAcceleration.

wheelAngularMomentum is calculated using Momentum = Inertia * AngularVelocity. Take the sum angular momentum of all the driven wheels, convert that angular sum to torque by divide torque to detalTime, because deltaMomentum= Torque * deltaTime, so Torque = deltaMomentum / deltaTime (I don't know if I'm right or not here). This torque will be wheelReactionTorque. 

For engineCombustionTorque, I use a curve to look up torque at certain RPM. Then engineTotalTorque will be engineCombustionTorque - frictionTorque. This sum of torque is the torque at the engine acting on the flywheel.

engineTotalTorque then drives the flywheel with its inertia engineInertia. This engineTotalTorque is resisted by the above wheelReactionTorque. So the netTorque is engineTotalTorque - wheelReactionTorque. This netTorque still drive only the flywheel which is engineInertia, but is resisted by the reaction torque from the wheels. So now the engineRPM is calculated using the formula AngularAcceleration = Torque/Inertia this way: engineRPM += netTorque / engineInertia * deltaTime. 

The biggest problem now is I don't know which force/torque will be transfered to the wheel and drives the wheels. Can you please help me out here?

Second, I don't know where and how to put the clutch in-between, I'm thinking of have a clutchInput float in wheelReactionTorque, so when it's 0 ie clutch disengaged, no resistance torque, engine freely spin the flywheel. clutchInput > 0, percentage of resistance is there, engine now drives itself and the resistance. What do you think about this?

Third, should the wheelResistanceTorque be modified with gearRatio before going back to the engine, say wheelResistanceTorque / gearRatio, or wheelResistanceTorque * gearRatio? If yes, should it be divide or multiply? I know that engineTorque going to wheel will have to be multiply with gearRatio, but what about the torque from wheel going back looking from the engine side?

I'm planning to stick with built-in wheelCollider despite its drawbacks to save time. I would like to make some sort of "sim-cade" handling similar to GRID or TDU, where the physic and handling is arcade-y, but still involves real physic factors such as managing clutch, tuning suspension, etc, as oppose to fully arcade games like need for speed or burnout.

Thank you guys very much in advance.

Advertisement

Well.  It's been a while since I've done this stuff, but let me see if I can help.

Let us refer to this diagram.

DRIVETRAIN.png.580959f38254cf6846798371cc45b804.png

 

Engine will look like:


torqueProduced = throttle * torqueLookup(RPM);	// throttle 0.0f - 1.0f
frictionTorque = frictionTorqueLookup(RPM);		// could be a constant value or linear to RPM.  You need to experiment
engineNetTorque = torqueProduced + clutchReactionTorque - frictionTorque;
engineAngularAcceleration = engineNetTorque/engineInerta;

 

Gearbox will look something like:


outputShaftSpeed = drivenWheelRPM;	// Let's ignore the differential gearratio and bake it into the gearbox overall ratio.
inputShaftSpeed = outputShaftSpeed * currentGearRatio;	// Lookup based on current gear selection.
outputTorque = clutchReactionTorque * currentGearRatio;

 

Driven wheels:


netTorque = reactionTorqueFromGround + (gearboxOutputTorque / numDriveWheels);
angularAcceleration = netTorque/wheelInertia;

 

Now the bit to put it all together... The clutch.


clutchASpeed = engineRPM;
clutchBSpeed = gearboxInputShaftSpeed;

// Now, when the clutch is engaged, it wants its two speeds to be equal.
// So it should apply reaction torques to try to achieve this. 
// A naive approach might look something like:
clutchTorque = frictionConstant * clutchFactor;  // clutchFactor = 0.0f -> 1.0f
if(clutchASpeed > clutchBSpeed)					 
	reactionTorqueA = -clutchTorque;
	reactionTorqueB = clutchTorque;
else
 	reactionTorqueA = clutchTorque;
	reactionTorqueB = -clutchTorque;
// This may have problems where is oscillates around equal speeds.  
// Depends on your integrator timestep, masses, etc.
// You could experiment with making the reaction torque linear to slip speed, 
// putting limits as the speeds get close to equal, etc.

So, what should happen, is when the engine is faster than the input shaft of the gearbox, the clutch generates a torque that tries to slow the engine and tries to speed up the gearbox.  Vice-versa when the engine is slower than the gearbox input.  The gearbox multiplies this torque and sends it to the wheels.  (Divide it up by the number of drive wheels). 

As I said, it's been a long time since I've done this.  So I could have missed something somewhere, but a similar approach has worked for me in the past.

 

Oh boy, what a warm welcome for a complete beginner like me. Looking at your implementation I just want to punch myself, because of how obvious and easy it is, and I'm here digging myself in all of the complicating maths.

 However I'm still confused in some places:

15 hours ago, CombatWombat said:

engineNetTorque = torqueProduced + clutchReactionTorque - frictionTorque;

I'm guessing this clutchReactionTorque is reactionTorqueA? Because when engine is faster than wheels, engine must be slowed down like this:

15 hours ago, CombatWombat said:

if(clutchASpeed > clutchBSpeed) reactionTorqueA = -clutchTorque;

Next is the gearBox:

15 hours ago, CombatWombat said:

outputTorque = clutchReactionTorque * currentGearRatio;

I thought the output of the gearbox should be what ever the engine is outputing  through clutch * gearRatio? If the output torque is clutchReactionTorque, in this case I'm guessing reactionTorqueB. then the torque at the wheels will be very very small, because in this reactionTorqueB is just clutchTorque, which is clutchFactor * frictionCoefficient.

15 hours ago, CombatWombat said:

reactionTorqueB = clutchTorque;

Or maybe I guessing you meant


clutchNetTorque = engineOutputTorque - reactionTorqueB;

then this clutchNetTorque will be driving the gearbox, and then the gearbox torque now drives the wheels?

 

So in my mind the model looks like this:


engineNetTorque = engineTorque - frictionTorque + reactionTorqueA;

clutchNetTorque = engineNetTorque + reactionTorqueB;

gearBoxOutTorque = clutchNetTorque * gearRatio;

wheelTorque = gearBoxOutTorque * diffBiasRatio; //use torque because Unity's wheelCollider RPM is read-only

By doing this, both sideA (engine) and sideB (shaftIn) will be dependent on the reactionTorque at the clutch, and both sides will rotate freely, connected only by the clutch. shaftIn torque will affect both engine the engine and the wheels

Then the cases for reactionTorque;


if (sideA > sideB) //engine (sideA) is faster, brake engine, speed up shaft (sideB)
{
  reactionTorqueA = -clutchTorque;
  reactionTorqueB = clutchTorque;
}
else if (sideA < sideB) //shaft is faster, brake shaft, speed up engine
{
  reactionTorqueA = clutchTorque;
  reactionTorqueB = -clutchTorque;
}
else //equal speed, reactionTorque is 0
{
  reactionTorqueA = reactionTorqueB = 0;
}
  

Also I'm thinking about making reactiontorque = (sideA - sideB) * clutchfactor, that way the if statement can be omitted and only the applying the correct sign at sideA and sideB is needed.

Any opinions on the above?

 

Also kind of out-of-place but I also would like to ask about differential after the clutch model is done, is it OK?

Update: I sort of having a rough implementation of this, and my problem now is that the engine keeps on accelerating like there is no resistance torque from the clutch, and the output torque at wheel is tiny. 

Here is my code so far, I'm using (engineSpeed - wheelSpeed) for reaction torque, so that I can omit the if statements:


//speed is in rad/s
//torque in Nm
//inertia in kg/m^2
//clutchStrength is abitrary, currently 10
//clutchInput goes from 0 (depressed, engaged) to 1 (pressed, disengaged)
float clutchTorque = (engineSpeed - driveTrainSpeed) * (1.0f - clutchInput) * clutchStrength * gearClutch; //gear clutch is when in neutral gear which is ratio 0

float engineOutputTorque = currentTotalEngineTorque - clutchTorque; //the torque coming out of the engine, factored in friction and resistance from clutch
float clutchOutputTorque = (engineOutputTorque + clutchTorque) * (1.0f - clutchInput); //the torque coming out of the clutch to drive the gearBox, the problem is somewhere here I guess. 1.0f-clutchinput is added later because torque is able the reach wheels even if clutch is disengaged, maybe problem related to this also.
float outputTorque = clutchOutputTorque * currentGearRatio * finalDriveRear; //the torque coming out of the gearbox to drive the wheels

 currentEngineRPM += radsToRPM((engineOutputTorque * Time.fixedDeltaTime) / engineInertia) ; //accelerate the engine with the netTorque

//finally drives the wheels
RR.motorTorque = outputTorque / 2.0f;
RL.motorTorque = outputTorque / 2.0f;

So the problem maybe is that clutchTorque that resists engine is too low so the engine keeps on accelerating like there's no resistance at all. When shifting gear the engineSpeed doesn't jump back either.

Also the input torque for clutch maybe is wrong. I'm specifying the net engine output torque as input, which maybe is wrong because only fraction of the engine output torque should be in the clutch when clutch is slipping. Or maybe the output altogether is wrong (which is engineOutputTorque + clutchTorque).

Can someone take a look and give me some advice?

Thank you very very much.

Hi, Just a quick addition. It seems you already experienced something related.

The engine/gearbox speed will never be the same, so some torque is always applied and with small difference it'll overshoot the acceleration, and develops some vibration, and that could go wrong.

So when I made mine, I had an open-locked clutch state.
Open by default until the engine and gearbox "equal" speed, in practice, when the sign of the speed difference changes.

So when locked, you don't need to add clutch torques any more, just apply the engine torque directly to the wheels like the whole thing was fixed together.

And most importantly there should be a setting for the maximum clutch torque, that's the amount the clutch can deal with (this should be multiplied by the current clutch pedal position). If the engine or wheel reaction torque is greater than this the clutch starts slipping and gets open again, so you can apply those clutch torques again.

I hope I could give some hint:)

 

 

1 hour ago, bmarci said:

Hi, Just a quick addition. It seems you already experienced something related.

The engine/gearbox speed will never be the same, so some torque is always applied and with small difference it'll overshoot the acceleration, and develops some vibration, and that could go wrong.

So when I made mine, I had an open-locked clutch state.
Open by default until the engine and gearbox "equal" speed, in practice, when the sign of the speed difference changes.

So when locked, you don't need to add clutch torques any more, just apply the engine torque directly to the wheels like the whole thing was fixed together.

And most importantly there should be a setting for the maximum clutch torque, that's the amount the clutch can deal with (this should be multiplied by the current clutch pedal position). If the engine or wheel reaction torque is greater than this the clutch starts slipping and gets open again, so you can apply those clutch torques again.

I hope I could give some hint:)

 

 

Hi.

Thank you so much for your reply. Yes you gave me some precious light when I'm in total darkness like right now.

Actually my model I'm thinking of doing right now is very similar to what you've said, having a clutch with states. Before this I've looked this model from Matlab:

https://www.mathworks.com/help/simulink/examples/building-a-clutch-lock-up-model.html

It's a very clean implementation, but doesn't fit Unity3D's physic engine too well, so I have to modify it and ended up with the model posted above. I'm thinking of making the clutch as a separate C# class, integrate as a separate object and output appropriate torque to engine and wheel side. The stuff I posted here is what I'm testing with the case of slipping clutch.

In case of locked clutch, I'm thinking of just setting the engineSpeed to the wheelSpeed * gearRatio, and engineTorque * gearRatio goes straight to the wheel. To me it's easier since Unity3D's physic engine calculate the wheelSpeed of the wheel object (wheelCollider) for me based on how much torque I put in and the tire slip force setting. Also this is the "recommended way" of doing engineSpeed according to Unity, which I think is not the best.

The hard thing is the slipping clutch. The downside of Unity's physic engine is that it does not expose the rolling resistance force and load of the wheel, so having wheel resistance torque acting back on the engine is not possible. The only way is to use wheelSpeed.

However, it's possible to calculate the angular Momentum of the wheel because the physic engine exposes wheel radius, weight and speed. So is it possible to somehow convert the momentum of the wheel to torque and resist the engine?

Also would you mind explaining this:

2 hours ago, bmarci said:

Open by default until the engine and gearbox "equal" speed, in practice, when the sign of the speed difference changes.

What do you mean by sign changed? Is it like

if sign(speedBefore) != sign(speedAfter) then clutchLocked

So based on what you've said, I have this model in mind


bool clutchLocked = false; //clutch open by default
float engineTorque = lookUpCurve(engineSpeed) - friction - clutchResist; 
//find out if clutch is slipping
//if engine torque overcomes clutch avaiable torque
//or speed different higher than threshold (since can't use wheel resistance torque for now)
if (engineTorque > clutchTorque || Abs(engineSpeed - wheelSpeed) > threshold)
{
  clutchLocked = false;
}
else 
  clutchLocked = true;


if (clutchLocked) 
{
  engineSpeed = shaftSpeed; //when clutch locked engine speed == wheel speed over gear system
  //all available engine torque goes to the wheels
  clutchResist = 0;
}
else  
{
  //clutch slipping
  //engine torque drive the engine itself with resistance from clutch
  //not going dirrectly to wheels
  engineSpeed += engineTorque / engineInertia * deltaTime;
  clutchResist = (engineSpeed - shaftSpeed) * clutchInput * clutchStrength;
}

Of the locking check can be like this (according to how I understand what you've said):


float speedDiff = engineSpeed = shaftSpeed;
//when sign changes or torque at both side less than clutch torque, clutch is locked
if ( sign(speedDiff) != sign(engineSpeed - shaftSpeed) || (engineTorque < clutchTorque && wheelTorque < clutchTorque) ) 
{
  clutchLocked = true;
}
else 
  clutchLocked = false;

What do you think? Would you mind giving me advises?

 

Your implementation looks close, but let's put some numbers and see where it's going awry.


// Let's pick some reasonable starting conditions for trying to accelerate.
// EngineRPM: 1000	[104.72 rad/s]
// DrivelineRPM: 0	[0 rad/s]
// EngineTorque(1000) = 400 Nm
// 1st Gear Ratio: 3.00
// Final Drive Ratio: 3.73


float clutchTorque = (engineSpeed - driveTrainSpeed) * (1.0f - clutchInput) * clutchStrength * gearClutch;
// (104.72 - 0) * (1.0f - 0.0f) * 10.0f * 1.0f = 1047.2 Nm
// This is a lot of torque and should definitely accelerate something!
// I would lean towards calling this "clutchReactionTorque" or something similar.  
// It is the torque acting between the two discs.


float engineOutputTorque = currentTotalEngineTorque - clutchTorque; 
// We're saying engine is making 400Nm, so 400Nm - 1047.2Nm = -647.2Nm.
// I would call it "engineNetTorque".  We're not actually "outputting" it anywhere.


float clutchOutputTorque = (engineOutputTorque + clutchTorque) * (1.0f - clutchInput);
// I don't understand this, really.  I think it might be where the problem is, but let's try anyways...
// (400Nm + 1047.2Nm) * (1.0f - 0.0f) = 1447.2 Nm.
// I think correct line would be clutchOutputTorque = clutchTorque;  
// This is because if you draw FBD of the clutch output plate, it only 
// knows about clutch input plate and gearbox.  It has no idea what engine is actually doing.  
// It only knows that clutch input plate is rubbing against it with some friction force.

float outputTorque = clutchOutputTorque * currentGearRatio * finalDriveRear;
// 1447.2Nm * 3.0 * 3.73 = 16194.17 Nm.  This is a big number of torques.  So something should drive somewhere.

 currentEngineRPM += radsToRPM((engineOutputTorque * Time.fixedDeltaTime) / engineInertia);
// so, we saw that engineOutputTorque is actually -647.2Nm, so the engine should slow down.

//finally drives the wheels
RR.motorTorque = outputTorque / 2.0f;
RL.motorTorque = outputTorque / 2.0f;
// Each wheel receives 8097.09 Nm.  So assuming the sign is correct (positive number rotates so the car goes forward), 
// then wheel speed should increase.  Drivelinespeed should increase.  Enginespeed will decrease as we saw above.  
// This brings clutch plate speeds closer together. So things appear to be close to working.  
// Try outputting debug numbers and see if things are behaving as above.

 

What was said above about switching to a "locked clutch" model when speeds equalize is a good idea, but it shouldnt be necessary to get things driving presuming your integrator is stable enough that things don't completely explode.

Edit: I would like to clarify that for the model as shown, the clutch and gearbox are both kinda of "virtual".  We have not assigned mass or inertia to them.  In a way they are just typedefs or "specially named attachment points" of the engine and wheel, since those are the only things with mass in the system.

Specifically, the "A" side of the clutch will always have the same speed as the engine.  It is effectively part of the engine, but we give it a special name for convenience. 

Same with the "B" side of the clutch, the gearbox, and the wheels being one "unit".

See the following, because MSPaint is THE tool of the future:

FreeBodyDiagram

 

FBD.png.6ea0a1a0359a6f4d0cd3eca5dec52db1.png

Thanks for the awesome reply. 


clutchTorque = (engineSpeed - driveTrainSpeed) * (1.0f - clutchInput) * clutchStrength * gearClutch;
17 hours ago, CombatWombat said:

Specifically, the "A" side of the clutch will always have the same speed as the engine.  It is effectively part of the engine, but we give it a special name for convenience. 

Same with the "B" side of the clutch, the gearbox, and the wheels being one "unit".

Oh OK I understand now. So basically I can imagine this as the engine driving the gearbox directly, but the two can be taken apart to spin independently.

17 hours ago, CombatWombat said:

// I think correct line would be clutchOutputTorque = clutchTorque; // This is because if you draw FBD of the clutch output plate, it only // knows about clutch input plate and gearbox. It has no idea what engine is actually doing. // It only knows that clutch input plate is rubbing against it with some friction force.

This is where I lost it. So based on the model of clutchTorque


clutchTorque = (engineSpeed - driveTrainSpeed) * (1.0f - clutchInput) * clutchStrength * gearClutch;

if this clutchTorque is used to drive the wheels, then there will be torque only if there is different in engineSpeed and wheelSpeed, ie torque is highest if clutch is slipping like crazy, which is not correct. And since this torque is fed back to the engine, then the engine speed would going up and down in a unrealistic manner. 

Another thing is that the engine torque does not go to the wheels but only the reaction torque does, which is

On 1/28/2018 at 4:37 AM, CombatWombat said:

clutchTorque = frictionConstant * clutchFactor;

which is a very small amount of torque.

Looking at the diagram (which is the best by the way), the way I understand it is that the engineNetTorque drives the flywheel, which is sideA. A fraction (0 - 100%) of that torque must affect/output to sideB, and how much of engineNetTorque is going to sideB depends on the amount of space in between sideA and sideB.

Or actually a fraction of combustionTorque (not netTorque) is going to sideB and the amount depends on the space in betweeen. The same with reaction torque on engine, the amount of that reactionTorque depends on the space as well.

 

This is the biggest confusion in all the clutch model I've looked at. Would you mind explaining a little bit more on this? Also one thing to note is that in the current physic engine I'm using (Unity3D), there is no way to extract roadReactionTorque at the wheel to feed back on the engine, so wheelReactionTorque = roadTorque + torque friction is a no go (well if that's the only way and its necessary in this model). That's why I'm replacing the whole wheelReactionTorque with the above (engineSpeed - wheelSpeed).

Second is that it is not possible to manually modify rpm, so wheelRPM += wheelAcceleration is a no go either. The way it works is that I give the wheel a torque value and the engine would integrate and return the rpm and slip based on the slip tire force curve (Pajeka like curve).

 However it is possible to get angular momentum of the wheels since wheel mass, radius and rpm are exposed. So is there any way to extract torque from angular momentum (or impulse) to apply to the roadTorque + torqueFriction model?

Here is the debug log in a run at 1st gear and specs of the car:


//In 1st gear launching
EngineSpeed: 19.20 DrivetrainSpeed: 0.00 clutchTorque: 253.54 engineTorque: 63.55 engineOutput: -189.99 clutchOutput: 31.08 output: 485.07
//Accelerating
EngineSpeed: 19.07 DrivetrainSpeed: 0.02 clutchTorque: 251.42 engineTorque: 100.46 engineOutput: -150.96 clutchOutput: 49.13 output: 766.80
EngineSpeed: 18.96 DrivetrainSpeed: 0.05 clutchTorque: 249.57 engineTorque: 128.12 engineOutput: -121.46 clutchOutput: 62.65 output: 977.87
//So the RPM did jump down until the engine output torque ie net torque is  positive
EngineSpeed: 16.43 DrivetrainSpeed: 10.16 clutchTorque: 169.31 engineTorque: 200.51 engineOutput: 31.20 clutchOutput: 200.51 output: 3129.79
EngineSpeed: 16.46 DrivetrainSpeed: 11.47 clutchTorque: 134.66 engineTorque: 200.55 engineOutput: 65.90 clutchOutput: 200.55 output: 3130.44
//HOwever eventually the engineRPM reach Max, but wheel RPM doesn't match, thus output torque is tiny.
//Also the rev limiter kicked in making engineTorque 0, making the engine the same speed but wheel speed also never match
//and the final output torque can't accelerate the wheels anymore.
EngineSpeed: 19.46 DrivetrainSpeed: 19.27 clutchTorque: 5.38 engineTorque: 5.38 engineOutput: 0.01 clutchOutput: 5.38 output: 84.01
EngineSpeed: 18.20 DrivetrainSpeed: 15.34 clutchTorque: 77.11 engineTorque: -118.47 engineOutput: -195.58 clutchOutput: -118.47 output: -1849.13

Subaru BRZ:

1st gear: 3.63

Final drive: 4.3

I actually had wheelspin when launching, but after that, the engineRPM accelerated way ahead of the wheelRPM though clutch fully engaged, and engineRPM kept staying at max, and wheelRPM slowly caught up after, which is not real. So it's a chase between the wheelRPM and the engineRPM. It's like the clutch was too weak. But increasing clutchStrength would cause haywire due to large number. I will post a video later to demonstrate.

Here is the demo video. Sorry for the buggy audio since I'm debugging a lot and there's little to no optimization at this moment.

As you can see (and hear) the engine revs up to max while the wheel rpm keeps up. The Delta W in the inspector window on the right is (engineRPM - wheelRPM), and you can see that they never match, and wheelRPM tried to keep up very slowly. No matter how high the clutch strength value is, they never match. The clutch strength value now is 27.

Unity 5.6.1f1 Personal (64bit) - DevelopmentTestTrack.unity - Car0 - PC, Mac & Linux Standalone _DX11_ 31-Jan-18 1_06_39 AMTrim.mp4

 

This topic is closed to new replies.

Advertisement