# Inverse Kinematics Issue

I am currently trying to make a robotic arm with inverse kinematics using the script below to calculate it. But there is an issue when you bring the arm into certain positions which I think is caused by the position from P1 to P2 being less than the distance to the midpoint.

I’ve scanned the devforum a bit but couldnt find a solution.

Video Example of the issue: https://gyazo.com/59a03af92014e86e8e41db85038ee88a

``````local P1, P2 = game.Workspace.P1, workspace.P2

local joint = P1.Position + P2.Position
joint = joint/2

local Distance = (P1.Position - P2.Position).Magnitude/2

local Segment1 = game.Workspace.S1
local Segment2 = game.Workspace.S2

function raysegment(Segment,P1,P2)
Segment.CFrame = CFrame.new(P1,P2) * CFrame.new(0,0,-Distance/2)
end

function FindEndpoint(Segment, point)
local p1 = Segment.Position + Vector3.new(0,0,Segment.Size.Z/2)
local p2 = Segment.Position - Vector3.new(0,0,Segment.Size.Z/2)
local x,y,z = Segment.CFrame:toEulerAnglesXYZ()
local Angle = CFrame.Angles(x,y,z)
local cf1 = Segment.CFrame * Angle * (Segment.CFrame:Inverse() * CFrame.new(p1)).p
local cf2 = Segment.CFrame * Angle * (Segment.CFrame:Inverse() * CFrame.new(p2)).p

local mag1 = (cf1 - point).Magnitude
local mag2 = (cf2 - point).Magnitude

if mag1 < mag2 then
return cf1
else
return cf2
end
end

raysegment(Segment1, P1.Position, joint)
raysegment(Segment2, joint, P2.Position)

function Solve()
raysegment(Segment2, P2.Position, joint)
joint = FindEndpoint(Segment2, P1.Position)
raysegment(Segment1, joint, P1.Position)
if Distance == joint then

end

raysegment(Segment1, P1.Position, joint)
joint = FindEndpoint(Segment1, P2.Position)
raysegment(Segment2,joint,P2.Position)
end

P1.Changed:Connect(function()
Solve()
end)

P2.Changed:Connect(function()
Solve()
end)
``````

Can you explain a little about what `FindEndpoint` is supposed to do?

It finds the end point of a segment which are the actual sections of the arm which there are 2 of them that are equal lengths

Oh, that’s very confusing for what it does. Just for my own understanding I simplified it a bit. This does the same thing with less CFrame math:

``````-- Returns the CFrame for the front/back end of `Segment` which is
-- closer to `point`
function FindEndpoint(Segment, point)
local halfLength = Segment.Size.Z / 2

local relative = Segment.CFrame:PointToObjectSpace(point)

if relative.Z > 0 then
return Segment.CFrame * Vector3.new(0, 0, halfLength)
else
return Segment.CFrame * Vector3.new(0, 0, -halfLength)
end
end
``````

But that doesn’t matter anyway, because `FindEndpoint` is the problem.

You don’t want to decide which endpoint is closest to the joint. You already know which one it is.

In other words, your whole `Solve` function can just be:

``````function Solve()
raysegment(Segment2, P2.Position, joint)
joint = Segment2.CFrame * Vector3.new(0, 0, -Segment2.Size.Z / 2)
raysegment(Segment1, joint, P1.Position)

raysegment(Segment1, P1.Position, joint)
joint = Segment1.CFrame * Vector3.new(0, 0, -Segment1.Size.Z / 2)
raysegment(Segment2,joint,P2.Position)
end
``````

And you can throw out the `FindEndpoint` method entirely.

1 Like

Thanks so much, I’ll try it out and see how it goes.

Also, you didn’t ask, but you’ll have trouble if your IK rig is straight, and you move the target straight back.

You can fix this by checking if the arm is straight first, and jiggling the joint a bit if so (at the top of the `Solve` function):

``````	-- quick check if things are colinear so we can jiggle it a bit
if math.abs(Segment1.CFrame.LookVector:Dot(Segment2.CFrame.LookVector)) > 0.999 then
joint = joint + Vector3.new(0, 0.001, 0)
end
``````

I’ll try it now

many characters are needed

Works perfectly

many characters are needed