Inverse Kinematics Module

What is inverse kinematics? It is that cool arm robot from iron man.

In computer animation and robotics, inverse kinematics is the mathematical process of calculating the variable joint parameters needed to place the end of a kinematic chain, such as a robot manipulator or animation character’s skeleton, in a given position and orientation relative to the start of the chain. (straight off wikipedia)

process of obtaining joint angles from known coordinates of end effector.
(OPEN SOURCE)

This module uses FABRIK (Forward and Backward Reaching Inverse Kinematics) You can enable 2D or 3D.

In the future I will add constraints to it. Meaning certain points can turn only at a certain angle.
I might add more stuff to the module in the future.

Kinematics.lua (5.2 KB)
ExamplePlace.rbxl (56.4 KB)

Preview 2D

Preview 3D

Code Documentation (its short so ill put it here)
Create IK 3D

local Kinematics = require(game:GetService("ServerScriptService").Kinematics).new{ 
	Type = "2D", -- Create a 2D type. it only accepts "2D" or "3D"
	Arm = {7, 5, 3}  -- Create our arm of lengths. Add as much arms you want
	-- First arm is 7 Studs, second arm is 5 studs, third are is 3 studs
}

while task.wait() do
	local originPosition = workspace.Origin.Position -- get start position in workspace
	local targetPosition = workspace.End.Position -- get target position in workspace
	
	local success = Kinematics:FABRIK{ -- use FABRIK (Forward and Backward Reaching Inverse Kinematics)
		Origin = originPosition, -- give it start position
		Target = targetPosition, -- give it target position
		
		Tolerance = 0.1, -- Optional doesnt need to be here unless you want manual settings
		MaxIterations = 100 -- Optional doesnt need to be here unless you want manual settings
	}

	local cframes = Kinematics:GetPartCFrames(originPosition, targetPosition) -- get the cframes so we can display and show
	for armIndex = 1, #cframes do -- loop through them numerical loop cuz fast and cool
		local cframe = cframes[armIndex] -- get the cframe

		local arm = workspace[`Arm{armIndex}`] -- get the part in workspace that we are gonna apply cframe to
		arm.CFrame = cframe -- set the part cframe and done.
	end -- do other stuff
end

All the stuff you can do

local Kinematics = require(game:GetService("ServerScriptService").Kinematics)

-- Create new Kinematic Solver
local solver = Kinematics.new{
	Type = "3D", -- what type? "2D" or "3D"
	Arm = { 3, 3 } -- lengths of arms, can have as much arms as you want and as much lengths
}

local success = solver:FABRIK{ -- use FABRIK, forwa and bawa reac ivner kinema
	Origin = Vector3.new(2, 5, 6), -- start position
	Target = Vector3.new(2, 2, 2), -- end position

	Tolerance = 0.2, -- not needed since its automatically set but tolerance meaning how close it needs to be for to be success
	MaxIterations = 25, -- max amount it'll do forwrad and back if not reached tolerance
} -- success means if it reached the target position within the tolerance and maxInterations

local armsData = solver:GetArmsData() -- gets all the data of each arm, gets points and length
-- returns { { position: Vector3, length: number, constraint: not used } }

local positions = solver:GetPositions() -- gets position of all points
-- it returns and array of positions so { Vector3, Vector3, Vector3 }

local cframes = solver:GetPartCFrames() -- gets cframes of all points similar to points but it gets the cframe directly and positions them in the middle
-- it returns and array of cframes so { CFrame, CFrame, CFrame }

Check out my machine learning (VERY COOL AI) library

21 Likes

But, doesn’t Roblox already support this by using IKControl Instance?

1 Like

Yes you’re right. IKControl are used for Humanoids/Characters. This module is mainly on parts without
Humanoids or Animation Controllers.
So you could probably use this for making a Robot Arm
image

Or you could make the Legs of an AT-ST Walker

2 Likes

Cool, maybe in your example place, have comments in that code also…

also what is the difference between using the 2D or 3D parameter ?

What stuff have you created with this?

And how can I get it to have constraints, so that if I am moving it in an arc, it does not bend out sideways, and instead bends in an arc like a rope would?

2D locks one of its axis and has it where it only faces you.
3D makes it so all of its axis are unlocked and each joint can face a different direction.

If you moved the arm side to side with 2D all the parts would move to keep it locked on one of its axis.
If you moved the arm side to side with 3D the last part would move because it can change directions of the other parts

I have created this walking robot.

I plan to add constraints in the future, I just haven’t created it yet.

2 Likes

So IKControl doesn’t work for stuff other than Humanoids?
Also:
Docs says:

IKControls must be a child of a Humanoid or AnimationController with an Animator

So we can simply add AnimationController with an Animator inside that.

Why not use AnimationControllers?

IKControl does work for nonhumanoids yes. This module provides more support and manipulation for non-rigged parts.

The IK module will provide you direct access to all information stored.

Oh, This is great and a pros of this module, I would certainly use that and experiment with it.

1 Like

This is great and I’m gald i could use this!
But sadly I cant use models for the arms, I’m gonna try and make it to be abe to handle models but I’m not sure if it will succeed!
(Yes I will give a copy of the edited version)

edit: Ok so i got it to work, Ill send the code:

--serverscriptstorage
local module = script.Parent
local serverstor = game.ServerStorage
local models = serverstor.STORAGE.TentacleModels
local signals = serverstor.SIGNALS
signals.MakeArms.Event:Connect(function(Name, Folder, ListLengths)
	local get1 = Folder
	local get2 = models:FindFirstChild(Name)
	if get1 and get2 then
		for N, Length in ipairs(ListLengths) do
			--loop trough lenghts to create all parts

			local clone = get2:Clone()
			if clone.ClassName == "Model" then
				local m = clone:FindFirstChild("inner")
				if m then
					m.Size = Vector3.new(m.Size.X, m.Size.Y, Length) 
				else
					warn("INVALID MODEL IN STORAGE!")
				end
			elseif clone.ClassName == "Part" then
				clone.Size = Vector3.new(clone.Size.X, clone.Size.Y, Length)
			end
			clone.Name = "Arm"..N
			clone.Parent = get1
			local b = clone:FindFirstChildOfClass("Script")
			if b then
				b.Enabled = true
			end
		end
		print("succes!")
	else
		warn("invalid tentacle information given, expect errors!")
	end
end)
local serverscrip = game:GetService("ServerScriptService")
local serverstora = game:GetService("ServerStorage")
local signals = serverstora:WaitForChild("SIGNALS")
local tents = workspace:WaitForChild("Visuals"):WaitForChild("Tentacles")
local base = script.Parent.Base
--functions
local function createTentacle(Lengths)
	local Arms = Instance.new("Folder")
	Arms.Name = "Test"..(#tents:GetChildren()+1)
	Arms.Parent = tents
	signals.MakeArms:Fire("Model1", Arms, Lengths)
	return Arms
end

local function RefreshTentacle(folder)
	local Kinematics = require(serverscrip.Kinematics).new{Type = "3D", Arm = lengths}
	local success = Kinematics:FABRIK{
		Origin = script.Parent.Base.Position,
		Target = script.Parent.Player.Position
	}
	local cframes = Kinematics:GetPartCFrames(originPosition, targetPosition)
	for armIndex = 1, #cframes do
		local cframe = cframes[armIndex]
		local arm = folder[`Arm{armIndex}`]
		if arm.ClassName == "Model" then
			arm:PivotTo(cframe)
		else
			arm.CFrame = cframe
		end
	end
end

--start
wait(1)
local f = createTentacle(lengths)
wait(0.2)
while task.wait() do
	RefreshTentacle(f)
end

Just make sure to have the correct folders and signals in the right places and it should work flawlessly!