Car's front wheel steering not working as expected

  1. What do you want to achieve? Keep it simple and clear!

I want to build a simple chassis that only contains the wheel, main part (transparent and no collide) and a vehicle seat, and can be put in any car body with small tweaking and without changing the main script.

  1. What is the issue? Include screenshots / videos if possible!

When being run, and trying to turn, the wheel behaves weirdly and sometimes the car accelerates weirdly without throttling it

This is the whole car

  1. What solutions have you tried so far? Did you look for solutions on the Creator Hub?

1.I tried connecting the steering hinge directly into the main part but it just locked the wheel.

2.I tried moving the attachment to inside the wheel but it also didn’t worked

3.I also tried making a Motor6D but since i never made one, the front wheel just collapsed.

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

This is the setup script

-- setup
if script.Parent.Part.Anchored == false then
	warn("DEV, PART MUST ANCHORED")
end

local part = script.Parent.Part
local wheelNames = {"FR", "FL", "RR", "RL"}

for i, wheelName in wheelNames do
	local wheel = script.Parent:FindFirstChild(wheelName)
	if not wheel then
		warn(wheelName .. " MISSING PART IN " .. script.Parent:GetFullName())
	else
		if wheelName == "RR" or wheelName == "RL" then
			local wheelAttachment = Instance.new("Attachment")
			wheelAttachment.Parent = wheel
			wheelAttachment.Name = "AT2" .. wheelName
			if wheelName == "RL" then
				wheelAttachment.CFrame = CFrame.new(-0.5, 0, 0)
			else
				wheelAttachment.CFrame = CFrame.new(0.5, 0, 0)
			end

			local partAttachment = Instance.new("Attachment")
			partAttachment.Parent = part
			partAttachment.Name = "AT1" .. wheelName
			partAttachment.WorldCFrame = wheelAttachment.WorldCFrame

			local hinge = Instance.new("HingeConstraint")
			hinge.Parent = part
			hinge.Attachment0 = partAttachment
			hinge.Attachment1 = wheelAttachment

		else
			local Pivot = Instance.new("Part")
			Pivot.Parent = wheel
			--part.Transparency = 1
			Pivot.Size = Vector3.new(0.5, 0.5, 0.5)
			Pivot.CFrame = wheel.CFrame
			Pivot.CanCollide = false
			if wheelName == "FL" then
				Pivot.CFrame = wheel.CFrame * CFrame.new(-0.6, 0, 0)
			else
				Pivot.CFrame = wheel.CFrame * CFrame.new(0.6, 0, 0)
			end
			Pivot.Parent = wheel
			local steerAttachment = Instance.new("Attachment")
			steerAttachment.Parent = Pivot
			steerAttachment.Name = "SteerAT2" .. wheelName
			--if wheelName == "FL" then
			--	steerAttachment.CFrame = CFrame.new(-0.5, 0, 0) * CFrame.Angles(0, math.rad(90), 0)
			--else
			--	steerAttachment.CFrame = CFrame.new(0.5, 0, 0) * CFrame.Angles(0, math.rad(90), 0)
			--end
			steerAttachment.CFrame = steerAttachment.CFrame * CFrame.Angles(0, 0, math.rad(90))
			local steerPartAttachment = Instance.new("Attachment")
			steerPartAttachment.Parent = part
			steerPartAttachment.Name = "SteerAT1" .. wheelName
			steerPartAttachment.WorldCFrame = steerAttachment.WorldCFrame

			local steerHinge = Instance.new("HingeConstraint")
			steerHinge.Parent = part
			steerHinge.Attachment0 = steerAttachment
			steerHinge.Attachment1 = steerPartAttachment
			steerHinge.Name = "SteerHinge"

			local wheelAttachment = Instance.new("Attachment")
			wheelAttachment.Parent = wheel
			wheelAttachment.Name = "AT2" .. wheelName
			if wheelName == "FL" then
				wheelAttachment.CFrame = CFrame.new(-0.5, 0, 0)
			else
				wheelAttachment.CFrame = CFrame.new(0.5, 0, 0)
			end
			
			local partAttachment = Instance.new("Attachment")
			partAttachment.Parent = Pivot
			partAttachment.Name = "AT1" .. wheelName
			partAttachment.WorldCFrame = wheelAttachment.WorldCFrame

			local hinge = Instance.new("HingeConstraint")
			hinge.Parent = part
			hinge.Attachment0 = partAttachment
			hinge.Attachment1 = wheelAttachment
			
		end
	end
end

for _, descendant in pairs(script.Parent:GetDescendants()) do
	if descendant:IsA("BasePart") then
		descendant.Anchored = false
	end
end

script.Parent.control.Enabled = true

this is on the control script

local Vseat = script.Parent.VehicleSeat

-- VARIABLES -- 
local MaxSpeed = 50 -- if this was set to 1 it will mean 1 full rotation of an wheel (RPM). changing the size of the wheel will affect the actual speed.
local Acceleration = 10
local ReverseSpeed = 10
local DirtSpeed = 25
local GrassSpeed = 10
local MinimumTurn = -45
local MaximumTurn = 45
-- END
Vseat.MaxSpeed = MaxSpeed
for _, descendant in script.Parent.Part:GetChildren() do
	if descendant.Name == "HingeConstraint" then
		descendant.ActuatorType = Enum.ActuatorType.Motor
		descendant.MotorMaxTorque = 100000
		descendant.MotorMaxAcceleration = Acceleration
	end
end
for _, descendant in script.Parent.Part:GetChildren() do
	if descendant.Name == "SteerHinge" then
		descendant.ActuatorType = Enum.ActuatorType.Servo
		descendant.ServoMaxTorque =  100000
		descendant.AngularSpeed = 10
		descendant.LimitsEnabled = true
		descendant.LowerAngle = MinimumTurn
		descendant.UpperAngle = MaximumTurn
	end
end


-- Function to check if the vehicle is on ground material
local function getGroundSpeed()
	local mainPart = script.Parent.Part
	if not mainPart then
		return MaxSpeed
	end

	local origin = mainPart.Position
	local direction = Vector3.new(0, -5, 0)
	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {script.Parent}
	params.FilterType = Enum.RaycastFilterType.Exclude

	local result = workspace:Raycast(origin, direction, params)
	if result and result.Instance then
		if result.Instance:IsA("BasePart") then -- Check material 
			local mat = result.Instance.Material
			if mat == Enum.Material.Ground or mat == Enum.Material.Mud or mat == Enum.Material.Sand then
				return DirtSpeed
			elseif mat == Enum.Material.Grass then
				return GrassSpeed
			end
		end
	end
	return MaxSpeed
end

while true do
	local currentSpeed = getGroundSpeed()
	if Vseat.Throttle == 1 then
		for _, descendant in script.Parent.Part:GetChildren() do
			if descendant.Name == "HingeConstraint" then
				descendant.AngularVelocity = currentSpeed
			end
		end
	elseif Vseat.Throttle == -1 then
		for _, descendant in script.Parent.Part:GetChildren() do
			if descendant.Name == "HingeConstraint" then
				descendant.AngularVelocity = -ReverseSpeed
			end
		end
	elseif Vseat.Throttle == 0 then
		for _, descendant in script.Parent.Part:GetChildren() do
			if descendant.Name == "HingeConstraint" then
				descendant.AngularVelocity = 0
			end
		end
	end
	if Vseat.Steer == -1 then
		for _, descendant in script.Parent.Part:GetChildren() do
			if descendant.Name == "SteerHinge" then
				descendant.TargetAngle = MaximumTurn
			end
		end
	elseif Vseat.Steer == 1 then
		for _, descendant in script.Parent.Part:GetChildren() do
			if descendant.Name == "SteerHinge" then
				descendant.TargetAngle = MinimumTurn
			end
		end
	elseif Vseat.Steer == 0 then
		for _, descendant in script.Parent.Part:GetChildren() do
			if descendant.Name == "SteerHinge" then
				descendant.TargetAngle = 0
			end
		end
	end
	task.wait(0.1)
end

This is the whole car:

Any help appriciated!

This may help…


rack1a

Wheels steering aligned (centered)


Wheels steering not aligned (wobble/pulling)

You may know this…

When I’m putting a body or a frame together, I start with a middle part and base everything else off that. I place it at 0,0,0 so everything added can be mirrored on the other side, accurate to the thousandth place. If the part on the right is 1.945, then the same part on the left would be -1.945. If you’re careful, you can make a perfectly true frame and body. That really helps with the wheels and everything attached to them also.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.