Centripetal Motion on Aircraft

Hello, I’m working on an aircraft system. But I’m struggling to control the aircraft when it’s on ground. I checked all the topics about the centripetal motion but couldn’t find any answer. I also asked chatgpt but still same result.

So when the engines are open the red arrow is the force being applied to front. But when I set rudder to -30 degrees, I want the plane to turn slowly to right.
Can someone help please? This is the code:

local Bindings = {

	["ThrottleUp"] = Enum.KeyCode.W,
	["ThrottleDown"] = Enum.KeyCode.S,
	["Flaps"] = Enum.KeyCode.F

}

local elevatorAddition = -3

local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local boost = 0

local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

local ignore = {"fuselage01","fuselage_wings","wing_support_L01","wing_support_R01","undercarriage02","undercarriage_L01","undercarriage_R01","undercarriage_tail01","TIP","Plane","Holder","prop01","prop02","rudder01"}

local connection, seat
local parts = {}
local hinges = {}

local EnginePower = 300

local throttle = 0
local thrust = 0

local flapStatus = 1
local Flaps = {0,-10,-20,-30}

local AirDensity = 0.01
local Mouse = nil

local function calculateCentripetalForce(velocity, radius)
	local speed = velocity.Magnitude
	local centripetalForceMagnitude = (speed^2) / radius
	return velocity.Unit * centripetalForceMagnitude
end
	
local function Start()
	local model = seat:FindFirstAncestorOfClass("Model")
	Mouse = game.Players.LocalPlayer:GetMouse()
	for index, descendant in model:GetDescendants() do
		if descendant:IsA("BasePart") then
			local A0 = Instance.new("Attachment", descendant)
			local A1 = Instance.new("Attachment", descendant)

			local VectorForce = Instance.new("VectorForce")
			VectorForce.Attachment0 = A0
			VectorForce.Parent = descendant

			local beam = Instance.new("Beam")
			beam.Parent = descendant
			beam.FaceCamera = true
			beam.Segments = 1
			beam.Width0 = 0.2
			beam.Width1 = 0.2
			beam.Color = ColorSequence.new(Color3.fromRGB(64, 245, 169))
			beam.Attachment0 = A0
			beam.Attachment1 = A1

			table.insert(parts, {
				Part = descendant,
				Attachment0 = A0,
				Attachment1 = A1,
				Beam = beam,
				VectorForce = VectorForce,
				AreaX = descendant.Size.Y * descendant.Size.Z,
				AreaY = descendant.Size.X * descendant.Size.Z,
				AreaZ = descendant.Size.X * descendant.Size.Y
			})
		elseif descendant.ClassName == "HingeConstraint" then
			table.insert(hinges, descendant)

		end

	end
end

local function Stop()
	for index, data in parts do
		data.Attachment0:Destroy()
		data.Attachment1:Destroy()
		data.Beam:Destroy()
	end
	table.clear(parts)
	table.clear(hinges)
end

local function calculateServoAngle(hinge, targetPosition)
	local baseAttachment = hinge.Attachment0

	local object_horizontal_offset = (baseAttachment.WorldCFrame):PointToObjectSpace(targetPosition)
	local object_yaw_angle = math.atan2(object_horizontal_offset.Y, -object_horizontal_offset.Z)
	object_yaw_angle = math.deg(object_yaw_angle)

	return object_yaw_angle
end

local function Loop(deltaTime)
	--[[ BACK-END ]]--
	--12500
	if UserInputService:IsKeyDown(Bindings.ThrottleUp) then throttle += 50 * deltaTime end
	if UserInputService:IsKeyDown(Bindings.ThrottleDown) then throttle -= 50 * deltaTime end
	local fixedThrottle = math.round(throttle)
	if fixedThrottle > 100 then
		fixedThrottle = 100
	elseif fixedThrottle < 0 then
		fixedThrottle = 0
	end
	throttle = fixedThrottle
	if thrust < throttle * EnginePower then
		thrust += EnginePower
	elseif thrust > throttle * EnginePower then
		thrust -= EnginePower
	end
	if thrust ~= 0 then 
		boost += EnginePower / 10
	else
		boost -= EnginePower / 3
		if boost <= 0 then
			boost = 0
		end
	end
	--thrust += EnginePower
	--[[ FRONT-END ]]-- 
	for index, data in parts do 
		local velocity = -data.Part:GetVelocityAtPosition(data.Part.Position)
		if data.Part.Name == "Motor" then
			data.VectorForce.Force = Vector3.new(0,0,-(thrust + boost))
		else
			data.VectorForce.Force = Vector3.zero
		end

		if data.Part.Name == "TIP" then
			data.Part.Orientation = data.Part.Orientation + Vector3.new(0, 10 * deltaTime, 0)  -- Rotate the TIP part for visual effect
		end

		if table.find(ignore, data.Part.Name) then 

		else
			if velocity.Magnitude > 0 then
				
				local dotRight = data.Part.CFrame.RightVector:Dot(velocity.Unit)
				data.VectorForce.Force += Vector3.xAxis * AirDensity * dotRight * data.AreaX * velocity.Magnitude^2

				local dotUp = data.Part.CFrame.UpVector:Dot(velocity.Unit)
				data.VectorForce.Force += Vector3.yAxis * AirDensity * dotUp * data.AreaY * velocity.Magnitude^2

				local dotLook = data.Part.CFrame.LookVector:Dot(velocity.Unit)
				data.VectorForce.Force -= Vector3.zAxis * AirDensity * dotLook * data.AreaZ * velocity.Magnitude^2

			end
			data.Attachment1.Position = data.VectorForce.Force / 400
		end

	end
	for index, hinge in hinges do
		hinge.TargetAngle = 0

		for index, value in hinge:GetAttributes() do

			--[[if hinge:GetAttributes()["Type"] == "Elevator" then
			hinge.TargetAngle += -math.clamp(calculateServoAngle(hinge, Mouse.Hit.Position), -20,20)
		end]]

			if hinge:GetAttributes()["Type"] == "Flap" then
				hinge.TargetAngle += Flaps[flapStatus]
			end
			local SCREEN_WIDTH = game.Workspace.Camera.ViewportSize.X
			local SCREEN_LENGTH =  game.Workspace.Camera.ViewportSize.Y
			local MouseX = UserInputService:GetMouseLocation().X
			local MouseY = UserInputService:GetMouseLocation().Y

			local normalizedX = (MouseX/SCREEN_WIDTH * 2) - 1 
			local normalizedY = (MouseY/SCREEN_LENGTH * 2) - 1 
			if index ~= "Type" then
				if hinge:GetAttributes()["Type"] == "Aileron" then
					hinge.TargetAngle += (normalizedX * value)
				elseif hinge:GetAttributes()["Type"] == "Elevator" then
					hinge.TargetAngle += normalizedY * value
					hinge.TargetAngle += elevatorAddition
				elseif hinge:GetAttributes()["Type"] == "Rudder" then
					hinge.TargetAngle += seat["SteerFloat"] * value

				end
			end
		end

		--hinge.TargetAngle += -math.clamp(calculateServoAngle(hinge, Mouse.Hit.Position), -20,20)
		--[[
		for index, value in hinge:GetAttributes() do
			hinge.TargetAngle += seat[index] * value
		end--]]
	end
end

UserInputService.InputBegan:Connect(function(input, gameProc)
	if gameProc == false then
		if connection ~= nil then
			if input.KeyCode == Bindings.Flaps then
				if flapStatus == #Flaps then
					flapStatus = 1
				else
					flapStatus += 1
				end
			end
		end
	end
end)

local function Seated(active, currentSeat)

	if active == false then 
		if connection == nil then return end
		connection:Disconnect()
		connection = nil
		Stop()
	elseif currentSeat.Name == "Plane" then
		seat = currentSeat
		Start()
		connection = RunService.PostSimulation:Connect(Loop)
	end
end

humanoid.Seated:Connect(Seated)


Thank you!

Are you sure your rudder force isn’t just backwards? There is not a physical reason for this force.

No, I didn’t meant that. The rudder perfectly works when the plane is going fast. The direction of the force is right or left depending on the orientation of the rudder. What I’m trying to do is to being able to rotate the airplane faster when taxiing (slowly moving on ground).