Inverse Kinematics for Tripod

I’m not sure what rigging plugin you are using but yeah make sure the joints are in the correct position and the (0,0,0) orientation. But the right leg seems ok so just follow what the right leg does.

1 Like

Weird, There the same. I checked that I named the Motors Correctly and The legs are o,o,o. TripodTest.rbxl (498.0 KB)
I am using MotorCreator.

Found the issue, it’s really dumb.

If you print it out you will notice the third foot motor is missing. I believe that’s because I renamed feet to foot for grammatical purposes in the new model, and yeah that causes it be nil, so it’s only detecting one limb from joint 1 to 2, and not 2 to 3. Now it should work expected. Yeah just rename feet to foot.

Here it is for copy and paste convenience:

Fixed syntax error
--Get service
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

--Modules required
local IKControllerPointer = ReplicatedStorage.Source.LimbChain
local LimbChain = require(IKControllerPointer)

--Left leg chain motors
local tripod = workspace.Tripod

local modelMotor6Ds = {}

local modelDescendants = tripod:GetDescendants()
for _,descendant in pairs (modelDescendants) do
	if descendant:IsA("Motor6D") then
		modelMotor6Ds[descendant.Name] = descendant
	end
end

--now you can index the Motor 6d's by name through the dictionary obtained
--Get the motors of the left leg chain
local lUpperLegMotor = modelMotor6Ds["LUpperLeg"]
local lLowerLegMotor = modelMotor6Ds["LLowerLeg"]
local lfoot = modelMotor6Ds["LFoot"]

--Get the motors of the right leg chain
local rUpperLegMotor = modelMotor6Ds["RUpperLeg"]
local rLowerLegMotor = modelMotor6Ds["RLowerLeg"]
local rfoot = modelMotor6Ds["RFoot"]

--Get the motors of the back leg chain
local bUpperLegMotor = modelMotor6Ds["BUpperLeg"]
local bLowerLegMotor = modelMotor6Ds["BLowerLeg"]
local bfoot = modelMotor6Ds["BFoot"]

--Create the left leg chain
local leftLegMotorTable = {lUpperLegMotor,lLowerLegMotor,lfoot}

local leftLegChain = LimbChain.new(leftLegMotorTable)

--create the right leg chain
local rightLegMotorTable = {rUpperLegMotor,rLowerLegMotor,rfoot}
local rightLegChain = LimbChain.new(rightLegMotorTable)

--Create the back leg chain
local backLegMotorTable = {bUpperLegMotor,bLowerLegMotor,bfoot}
local backLegChain = LimbChain.new(backLegMotorTable)


RunService.Heartbeat:Connect(function()

	local leftTarget = workspace.BigLTarget.Position
	local rightTarget = workspace.BigRTarget.Position
	local backTarget = workspace.BigBTarget.Position

	leftLegChain:IterateOnce(leftTarget,0.1)
	leftLegChain:UpdateMotors()

	backLegChain:IterateOnce(backTarget,0.1)
	backLegChain:UpdateMotors()

	rightLegChain:IterateOnce(rightTarget,0.1)
	rightLegChain:UpdateMotors()

end)
1 Like

Thank you for taking time out of your day to help me. C:\Users\User1\Downloads\TripodTest.rbxl - Roblox Studio - Gyazo He Works.

1 Like

And thank you for using trying out my resource :+1: tbh I wrote it when I was learning scripting and I really hate it rn because of the aforementioned bugs in this post and the setup required. But yeah when the setup is all done it’s really satisfying. Really hope my current CCDIK project will work.

1 Like

One more thing. How would I make the targets move with the tripod As I working on a ai so how would I make the tripods foot move like in this video EZ Fabrik IK [Deprecated] - Inverse Kinematics Intended for any Motor6d Rig - #13 by dthecoolest
I am based the walk to look like this

That’s going to be a bit more complicated. Personally I use iGottics method of moving the target position in a circle while raycasting to detect the floor position. You can find it over here:

Edit: another method you can use is this IK method from Swordphin123

I believe the method is the same as this video made from codedeer

when in doubt steal from unity :wink:

But I find the steps hard to follow so I used IGottics method. IDK both should work.

2 Likes

So I Looked over the code and I noticed that I am going to have to change many things. Now the Tripod doesn’t have any hip motors so what should I do?

	["rightLeg"] = {
		["CurrentCycle"] = 0,
		["LimbChain"] = rightLegChain,
		["HipAttachment"]= rightHipAttachment,
		["FootAttachment"] = rightStepAttachment,
	},

	["leftLeg"] = {
		["CurrentCycle"] = math.pi,
		["LimbChain"] =leftLegChain,
		["HipAttachment"]= leftHipAttachment,
		["FootAttachment"] = leftStepAttachment,
	}
}

Oh, the hip motor in the procedural animator script refers to the Motor6D that is connected from the HumanoidRootPart to the rig with the part0 being the humanoid root part and the part1 being connected to the first thing to the rig which in my case was the hip.

For the R15 dummy it will be the Root Motor6D.

And the hip attachment just controls the position where the foot detection system will start raycasting from in order to detect the floor.

I chose to use attachments because well they are easily debuggable visually and controllable. But yeah hope this clears up the terminology I used when making the procedural animator script. For more notes, you can look into the original script source which I copied took inspiration from which is the R15 foot planting resource. You will notice most of the things like variables for the RootMotor6D are the same.

1 Like

Ah Ok, So I just added a Hip Motor to the humanoid root part to the torso base, were the other motors for the legs are. Would I put this Procedural code in Serverscriptservice and separate from the muiti chain?

Well, the procedural animation code is a module script so it can be wherever however the multichain script has to have access to this object class as in order to create the object it requires the LimbChain object as noticed in the dictionary used to construct the legs.

["rightLeg"] = {
		["CurrentCycle"] = 0,
		["LimbChain"] = rightLegChain,
		["HipAttachment"]= rightHipAttachment,
		["FootAttachment"] = rightStepAttachment,
	},
1 Like

Its not working, I did some test, changed were the script was from the script service to the tripod model itself. I checked the output but there was no error, the inverse kinematics still work fine though. TripodTest.rbxl (502.7 KB) Wait Dont I need to weld the targets to the Main Torso or legs?

I’m guessing you need to animate it in a heartbeat loop

local RunService = game:GetService("RunService")
 
local tripod = proceduralAnimator.new()-- create it
RunService.Heartbeat:Connect(function(step)
ProceduralAnimatorClass:Animate(step)
end)
1 Like

Ok Now I am completely lost. When you mean Animate it do you mean like animate it though animation editor as I know that you can do that. If you have the save for the procedural mech? I can maybe reverse engineer it for my tripod.

Sorry, by animating I meant the procedural animation with my method of using a script to move the target points in a circle for the inverse kinematics script to follow and also I’m not planning to open-source my current procedural mech.

I believe the procedural animator above in the cool creations showcase I gave should be enough to work from, or maybe you should directly look at the R15 procedural animation resource for notes then reverse engineer from there like I have before. It was specifically in this post where I took notes of the target points the inverse kinematics is trying to reach the goal towards where I recorded a video of what the procedural animation script is actually doing, moving the red target in a circle which the inverse kinematics will then follow.

1 Like

Alright thanks. I am going to read through the ik script in the foot planting to get a better understanding. I still very new to scripting so that’s why I been asking many questions and probably dumb ones.

1 Like

I reamber that you told me that the FabIk

seems like my initial method didn’t work for really long legs.

Why is that the case?. Also With your CCDIK you been working on, what would be new added that’s is different to the your current Fabik. Also the foot of the tripods are not moving. I checked if the were some how welded some how. but nop just to the foot part itself.
Edit: I just check and the foot orientation is 0,0,0

Oh Initially I believed this section of the code was wrong for finding a vector that goes from the one motor to the other. I think it’s more reliable to work with the joint in world terms instead by multiplying the motor6d Part0 CFrame with the C0.

wrong code
function LimbChain.JointOneToTwoVector(motorOne, motorTwo)
    -- Check if its a motor6d
    if motorOne:IsA("Motor6D") and motorTwo:IsA("Motor6D") then
        local vecOne = motorOne.C1.Position
        local vecTwo = motorTwo.C0.Position
        local combinedVector = vecTwo - vecOne
        return combinedVector
    else
        return "Error: motor 6ds are not inserted in the function"
    end
end

Honestly I think you should just use my current implementation the the CCDIK ik as it uses a complete different method to rotate the limb which is not dependent on the orientation being (0,0,0) which the Fabric algorithm does. This is because I found out how to properly obtain the rotation CFrame between two vectors from EgoMoose’s tutorial.

1 Like

I was doing some test and found this quite funny. https://i.gyazo.com/cdbfc86db9a27af3700bcf033af96868.mp4

How Would I do the Foot placing system, on my tripod? As the MultiChain and the mech constraint Test are both written diffently.
Ok So I just added it to the script and changed thing around. Still would not work, but the IK still works and no errors in the output.

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

--Modules required
local IKControllerPointer = ReplicatedStorage.Source.LimbChain
local LimbChain = require(IKControllerPointer)

--Left leg chain motors
local tripod = workspace.Tripod

local modelMotor6Ds = {}

local modelDescendants = tripod:GetDescendants()
for _,descendant in pairs (modelDescendants) do
	if descendant:IsA("Motor6D") then
		modelMotor6Ds[descendant.Name] = descendant
	end
end

--now you can index the Motor 6d's by name through the dictionary obtained
--Get the motors of the left leg chain
local lUpperLegMotor = modelMotor6Ds["LUpperLeg"]
local lLowerLegMotor = modelMotor6Ds["LLowerLeg"]
local lfoot = modelMotor6Ds["LFoot"]

--Get the motors of the right leg chain
local rUpperLegMotor = modelMotor6Ds["RUpperLeg"]
local rLowerLegMotor = modelMotor6Ds["RLowerLeg"]
local rfoot = modelMotor6Ds["RFoot"]

--Get the motors of the back leg chain
local bUpperLegMotor = modelMotor6Ds["BUpperLeg"]
local bLowerLegMotor = modelMotor6Ds["BLowerLeg"]
local bfoot = modelMotor6Ds["BFoot"]

--Create the left leg chain
local leftLegMotorTable = {lUpperLegMotor,lLowerLegMotor,lfoot}

local leftLegChain = LimbChain.new(leftLegMotorTable)

--create the right leg chain
local rightLegMotorTable = {rUpperLegMotor,rLowerLegMotor,rfoot}
local rightLegChain = LimbChain.new(rightLegMotorTable)

--Create the back leg chain
local backLegMotorTable = {bUpperLegMotor,bLowerLegMotor,bfoot}
local backLegChain = LimbChain.new(backLegMotorTable)

--Foot placement system
local footParams = RaycastParams.new()
local ignoreParts = workspace:WaitForChild("RayFilterFolder")
footParams.FilterDescendantsInstances = {tripod,ignoreParts}

leftLegChain.FootPlacementRaycastParams = footParams
leftLegChain.LengthToFloor = 80

local down = Vector3.new(0,-80,0)

RunService.Heartbeat:Connect(function()
	
	local goalPosition = workspace.BigLTarget.Position
	local goalRightPosition = workspace.BigRTarget.Position
	local goalLeftPosition = workspace.BigRTarget.Position
	local rayResult = workspace:Raycast(goalPosition,down,footParams)
	if rayResult then
		leftLegChain:IterateOnce(rayResult.Position,0.1)
	end
	leftLegChain:UpdateMotors()

	local leftTarget = workspace.BigLTarget.Position
	local rightTarget = workspace.BigRTarget.Position
	local backTarget = workspace.BigBTarget.Position

	leftLegChain:IterateOnce(leftTarget,0.1)
	leftLegChain:UpdateMotors()

	backLegChain:IterateOnce(backTarget,0.1)
	backLegChain:UpdateMotors()

	rightLegChain:IterateOnce(rightTarget,0.1)
	rightLegChain:UpdateMotors()

end)

TripodTest.rbxl (1.1 MB)