Need to find resources of equations in engine RPM part

Hello!
I have already obtained resources explaining the gear ratio part of transmission aswell as all theese torque outputs.

Just for myself and others to memorize:


import numpy as np
from bge import logic

cont = logic.getCurrentController()
...skip this part as some inits are here...

#This curve doesn't represent reality at all, it is just approximate curve that has random numbers in it.
rpmArray = [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000]
torqArray = [0,  125,   175,   210,   290,   345,   312,   176,   51,      15]
#And so do this list and value
gearRatios = [3.5, 2.7, 1.8, 1.2, 0.6]
finalRatio = 4

#This is what I'm missing for!!!
rpm = ?

engineTorqueOut = np.interp(rpm, rpmArray, torqArray)

gear = own["gear"]

finalTorque = engineTorqueOut * gearRatios[gear] * final Ratio

This is approximate, but pretty fine code.

What I need now is to somehow get the RPM.

I have a gas that is constant value(basicly a bool - either true or false). And I have a brakes(both - brake and ebrake).
They have a custom value representing their strength and they are used with applyBraking() command.

Now I need to get RPM based on throttle(gas) and braking, but I have no idea how and I can’t find any explanations, resources or tutorials releated to equational part of this.

SO - can anybody help me directly(best way) or at least point me to some hidden resources/tutorials that I couldn’t google(a pretty good way still)?

Thank you!:slight_smile:

rpm = gear rotations number per minute?


from math import pi

def rpm(radius, speed):
    #speed in m/s
    #radius in m
    perimeter = 2*pi*radius
    rotPerSecond = speed/perimeter
    rotPerMinute = rotPerSecond * 60
    return rotPerMinute



I guess… If I make no mistake…

No, it is not what I mean - I mean engine RPM. It is how fast engine’s cylinders rotate and produce torque(turns a kinda stick around it’s axis producing rotation power needed to spin wheels).

So:

The RPM is basicly sticked with speed all the time as RPM shows how much speed is produced.
The torque is also RPM dependent and the higher is torque, the faster RPM grows within the speed.
When transmission is added, it can either increase max speed(by lowering the torque) or increase torque(by lowering max speed).

This is what I know.

Did you already have a good look at technical explanations how an engine works? Since you are really looking to get the actual mechanisms in I think understanding the mechanics will really help. Or do you just want to get the dashboard dials to make some sense? Below at least some thoughts how I would think about it. I know it is not a direct answer to how to get an RPM value.

The braking part at least does not have a direct effect on the engine RPM. The brakes apply on the wheels directly. I don’t know any details about engine design. However I would expect the engine RPM to depend on the following.

  1. Basically as I see it the engine RPM states how fast it rotates, so how much potential energy it has
  2. Adding gas will speed up the engine, and it’s energy. If you approximate the engine as a fly-wheel that might give a good relation between the gas paddle and RPM.
  3. The energy of the engine is transferred to the wheels through all the gears. So if the car is already up to speed it won’t drain the engine so much. Slowing down by braking of coarse also drains the engine.
  4. Internal friction of the engine will also slowly drain it’s energy and cause the engine to slow down

I need something like equation table or something like that. Otherwise it is a bit too difficult. From what you said I didn’t understand much. However - usually when I imagine linking the gas pedal directly to RPM, I approach a problem - how to make sure that car rpm also reduce correctly, not just increase?

RPM =

from math import pi

RAD_TO_RPM = 60/(2*pi) 

...
    rpm = object.worldAngularVelocity.length * RAD_TO_RPM
...

Now I think about it a bit more it is not as complicated as I thought. If you are switched in a particular gear your wheel rotation is directly linked to the engine. So following the next steps should work (step 2-4 were already in your script):

  1. Get wheel rotation and convert it to engine rotation using the gear ratio’s --> gives the current engine RPM
    -RPM = wheel rotation / (gear * final ratio)
  2. Use the engine RPM value to calculate engine power when pushing the gas
  3. Use the gear ratio’s to convert engine power to get the torque at the wheels
  4. Apply this torque at the wheels and the car will speed up, with likewise increase in engine RPM

As for braking, just apply the braking torque directly on the wheels and the engine RPM should be updated automatically as it is based on the actual rotation of the wheels.

Note: having 2 separate ratio’s (gear & final) seems a bit confusing to me …

From this it sounds like you want the amount of power transfer to the wheels… Or the power of the wheels…? Any way it sounds like horse power is your key here… Something can spin really really fast and not have torque… And I believe that horse power can convert to torque…

The was literally the first thing Google came up with:
http://www.crawlpedia.com/rpm_gear_calculator.htm
Look under “Engine RPM Calculation Basics”

Please, search harder before asking others to search for you.

@pqftgs, What is axle gear ratio? Is this what I use in this array?


gearRatios = [3.5, 2.7, 1.8, 1.2, 0.6]

However, I again run onto fact that here I need to invert my engine principals and that means that all my transmission stuff must be rewrited into a way that I don’t know. Because here I can not apply throttle AFAIK.

@quickmind, I’m not sure about horsepower and I need the RPM for the HUDs too.

@Wraah, Firstly, I must get wheel count which are applying force or to be more honest - how much each applies force(due to drift setup my drives are:


"4x4": [1.0, 1.0, 1.0, 1.0]
"Rear": [0.5, 0.5, 1.5, 1.5]
"Front": [1.5, 1.5, 0.5, 0.5]

as mutlipliers for torque applied), so I can, OK - I can reduce numbers in theese arrays, you’re right.

However, I had similar setup before, it works fine when driving, but if car stops, it can’t start driving. Maybe I can just make it more realistic by making it have minimum of 500 RPM in gears that are over 0(neutral)? I may need more discussions here…

https://www.reddit.com/r/gamedev/comments/1320er/math_for_simulating_a_car_transmission_xpost_rmath/
It was mentioned here.

A car engine typically stalls when the RPM gets to low (driving slow in high gear). So when braking hard you set the gears to free, else the engine stops. So I think you can fix it by making an exception to have some start boost in first gear.

As for multiple ratio’s. The total is just multiplying all the individual steps (gear box, drive shaft etc.) so in the end you only need 1 value. But keeping it separate indeed keeps the numbers more meaningful on their own.

What does it exactly mean?

wheel rotation / (gear * final ratio)

This doesn’t give values in thousands(something in range 1000 - 7000) but instead something between 50 and 500.

wheel rotation in Blender is radians per second. Did you already calculate it to revolutions per minute (RPM). (x60 / (2xPI) -> roughly a factor 10).

Why an engine stops at low RPM I don’t know exactly, other than that it does not like it. I guess it needs a certain RPM to run smoothly. At low speed in too high gear will first lead to some choppy behavior and if you don’t push the clutch in time the engine will stop completely.


(car["speed"] / 3.6) / (2 * pi * wheelRadius) * 60

This is the equation, I divide by 3.6 as it is km/h.


import bge
from bge import logic
import PhysicsConstraints
from gamesystem import gaudges
from math import pi
import numpy as np


### Define ###
scene = logic.getCurrentScene()
car = scene.objects["Car"]
keyboard = logic.keyboard
JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
ACTIVE = bge.logic.KX_INPUT_ACTIVE


#keyboard keys
gas = keyboard.events[bge.events.WKEY]
left = keyboard.events[bge.events.AKEY]
reverse = keyboard.events[bge.events.SKEY]
right = keyboard.events[bge.events.DKEY]
ebrake = keyboard.events[bge.events.SPACEKEY]


#stats
gasPower = car["gasPower"] * 10
brakePower = car["brakePower"]
ebrakePower = car["ebrakePower"]
reversePower = car["gasPower"] / 3 * 20
maxSteer = car["maxSteer"]
steerSpeed = car["steerSpeed"]
maxSpeed = car["maxSpeed"]


# Define tire objects
tireFL = scene.objects["TireFL"]
tireFR = scene.objects["TireFR"]
tireRL = scene.objects["TireRL"]
tireRR = scene.objects["TireRR"]


### Initialise ###


if not "ini" in car:
    pid = car.getPhysicsId()
    suspension = PhysicsConstraints.createConstraint(pid, 0, 11)
    cid = suspension.getConstraintId()
    suspension = PhysicsConstraints.getVehicleConstraint(cid)


    wheelRadius = 0.345
    suspensionRestLength = 0.5
    hasSteering = 1
    
    car["gearRatios"] = [3.5, 2.7, 1.8, 1.2, 0.6]
    car["finalRatio"] = 4
    
    car["rpmArray"] = [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000]
    car["torqArray"] = [0,  125,   175,   210,   290,   345,   312,   176,   51,      15]


    ### Tweakables ###
    damping = car["damping"]
    stiffness = car["stiffness"]
    compression = car["compression"]
    roll = car["roll"]
    grip = car["grip"]
    drift = car["drift"]
    
    car["wheelPerimeter"] = 2 * pi * wheelRadius


    ### Actions ###


    # Generate tires
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [-0.745, 1.27, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    suspension.addWheel(tireFL, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [0.745, 1.27, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    suspension.addWheel(tireFR, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [-0.75, -1.18, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    hasSteering = 0
    suspension.addWheel(tireRL, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)
    wheelAttachDirLocal = [0, 0, -1]
    wheelAttachPosLocal = [0.75, -1.18, 0.59]
    wheelAxleLocal = [-1, 0, 0]
    suspension.addWheel(tireRR, wheelAttachPosLocal, wheelAttachDirLocal, wheelAxleLocal, suspensionRestLength, wheelRadius, hasSteering)


    # Update suspension
    for tire in range(4):
        suspension.setSuspensionDamping(damping, tire)


        suspension.setSuspensionStiffness(stiffness, tire)


        suspension.setSuspensionCompression(compression, tire)
        
        suspension.setRollInfluence(roll, tire)
        
    suspension.setTyreFriction(grip, 0)
    suspension.setTyreFriction(grip, 1)
    suspension.setTyreFriction(grip / (drift * ((maxSpeed - gaudges.speed) / maxSpeed)), 2)
    suspension.setTyreFriction(grip / (drift * ((maxSpeed - gaudges.speed) / maxSpeed)), 3)
    
    car["ini"] = True
    car["CID"] = cid


### Car in action ###


wheelRPS = (car["speed"] / 3.6) / car["wheelPerimeter"]
car["wheelRPM"] = wheelRPS * 60


car["RPM"] = car["wheelRPM"] / (car["gearRatios"][car["Gear"] - 1] * car["finalRatio"]) * 4


torque = np.interp(car["RPM"], car["rpmArray"], car["torqArray"])
torque = torque * car["gearRatios"][car["Gear"] - 1] * car["finalRatio"]


suspension = PhysicsConstraints.getVehicleConstraint(car["CID"])


# Drift
suspension.setTyreFriction(car["grip"] / (car["drift"] * ((maxSpeed - gaudges.speed) / maxSpeed)), 2)
suspension.setTyreFriction(car["grip"] / (car["drift"] * ((maxSpeed - gaudges.speed) / maxSpeed)), 3)


# Gas
if gas == ACTIVE:
    car["gas"] = torque
else:
    car["gas"] = 0
    
# Emergency brake
if ebrake == ACTIVE:
    car["ebrake"] = ebrakePower
else:
    car["ebrake"] = 0
    
# Reverse
if reverse == ACTIVE:
    if car["speed"] > 0:
        car["brake"] = brakePower
        car["gas"] = 0
    else:
        car["brake"] = 0
        car["gas"] = -torque
else:
    car["brake"] = 0
    
# Steering
if right == ACTIVE:
    if car["steer"] > -maxSteer:
        car["steer"] -= steerSpeed
elif left == ACTIVE:
    if car["steer"] < maxSteer:
        car["steer"] += steerSpeed
else:
    car["steer"] = 0.0


drive = car["drive"]
## drives
    # 1: rear
    # 2: front
    # 3: full
frontDrive = 0
rearDrive = 0


if drive == 1:
    rearDrive = 1.5
    frontDrive = 0.5
elif drive == 2:
    rearDrive = 0.5
    frontDrive = 1.5
else:
    rearDrive = 1.0
    frontDrive = 1.0


for tire in range(4):
    # Front tires
    if tire < 2:
        suspension.applyEngineForce(-car["gas"] * frontDrive, tire)
        suspension.applyBraking(car["brake"], tire)
    # Rear tires
    else:
        suspension.applyEngineForce(-car["gas"] * rearDrive, tire)
        suspension.applyBraking(car["ebrake"], tire)


suspension.setSteeringValue(car["steer"], 0)
suspension.setSteeringValue(car["steer"], 1)


gaudges.speed = car.getLinearVelocity(1).y * 3.6
car["speed"] = int(gaudges.speed)


if car["speed"] > maxSpeed:
    car.localLinearVelocity.y = maxSpeed / 3.6
    
if car["speed"] < -(maxSpeed / 2):
    car.localLinearVelocity.y = -((maxSpeed / 2) / 3.6)

My current script, kinda not what I need.

Does anyone know how to calculate the rpm in percentages?

For example: I want to calculate the rpm of an object by, say 50%, like if the object is rotating 50% slower from its actual rpm

That make much sense by itself. You can’t calculate an RPM as a percentage. You can determine the ratio of the current RPM to another RPM value. You don’t even need to bother multiplying by RAD_TO_RPM when you’re dividing one value by another



ang_vel_a = obj.worldAngularVelocity.length
ang_vel_b = 3.14

fractional_ratio = ang_vel_a / ang_vel_b
percentage_ratio = fractional_ratio * 100


Thanks for replying but I’m totally new to scripting can you explain how can I use this please? :spin: