[SOLVED] Train pantograph bug - Motor6D

Hi, I’m working on a pantograph for a train and for the pantograph I would like it to raise or lower depending on the height of the overhead wire that is above the pantograph, so far I’ve kind of got it to work but the issue is it doesn’t raise properly.

Here is a couple screen shots of what is happening:
If the wire and the pantograph is the same on the Z axis it’ll raise properly but if not it’ll either be too low or too high.

image
image
image

How it should be:
It should always be touching the wire no matter what the Z axis difference is.
image

This pantograph is controlled by 3 motors. 1 motor controls the lower arm, 1 motor controls the upper arm and 1 motor controls the pantographs hand.

In the image below, each green dot represents a motor.
Top dot - Hand
Middle dot - Upper Arm
Bottom dot - Lower Arm

Here is the code that controls the lower arm and upper arm. The coding for the hand works perfectly so I have removed that from below.

local RaycastResult = workspace:Raycast(OriginRay.Position, OriginRay.CFrame.UpVector * 20, raycastParams)

if RaycastResult then
	local Wire = RaycastResult.Instance
	local Distance = RaycastResult.Distance

	local LowerArmAngle = math.rad(-Distance * LowerArm.Size.Z)
	local UpperArmAngle = math.rad(Distance * UpperArm.Size.Z)

	LowerArm.Motor.C1 = CFrame.fromOrientation(LowerArmAngle / 2, 0, 0)
	UpperArm.Motor.C1 = CFrame.fromOrientation(UpperArmAngle, 0, 0)
end

I’ve tried a million different ways to get it to try raise properly but nothing will work so I’ve now came here for help.

Thanks to anyone that can help!

2 Likes

Interesting kinematics, which I suck at. I do notice that your UpperArmAngle seems to be not divided, which might be an issue.

1 Like

Why does the upper arm angle need to be divided?

2 Likes

I’m not familiar with these types of kinematics, but since your lower arm angle is divided, it might make sense to do the same with the upper arm. Currently, 45 degrees on the lower arm means 90 degrees on the upper, right?

1 Like

If the lower arm is not divided it’ll look like this but if it is divided then the lower arm would be hopefully what I want.

Um I I think. I don’t know lol its been a long time since I’ve last worked on this since Its been very hard for me to figure out.

image

1 Like

In that case, you might want to add/subtract math.pi/4 to get a 45-degree angle to the upper arm, since it will likely provide what you want.

1 Like

Will this work even if the wire changes rotations or heights?

try adjusting pantograph height by subtracting desired distance from raycast result.

local desired_distance = 0
local RaycastResult = workspace:Raycast(OriginRay.Position, OriginRay.CFrame.UpVector * 20, raycastParams)

if RaycastResult then
	local Distance = RaycastResult.Distance - desirder_distance
	local LowerArmAngle = math.rad(-Distance * LowerArm.Size.Z)
	local UpperArmAngle = math.rad(Distance * UpperArm.Size.Z)

	LowerArm.Motor.C1 = CFrame.fromOrientation(LowerArmAngle / 2, 0, 0)
	UpperArm.Motor.C1 = CFrame.fromOrientation(UpperArmAngle, 0, 0)
end

try using different values for “desired_distance” to find the best pantograph height. if issues persist, check for motor limitations and alignment problems.

1 Like

Possibly. However, the arm cannot rotate on the Y axis.

Wouldn’t the desired distance change if the wire that’s above the train changes height or rotation while the train moves?

Wouldn’t there be some calculation I could do that would make the pantograph raise up correctly?

Of course. I’m not an expert in kinematics though, so I might not be able to help. I do have a feeling that it has something to do with the distance or the rotational multiplier.

Yeah I also think its that but not sure what I have to do lol.

Thanks anyways.

Indeed, if the wire’s height or rotation changes while the train is in motion, the desired distance for the pantograph needs to be dynamically adjusted. This ensures continuous contact between the pantograph and the wire, adapting to any changes during the train’s movement.

What would the desired distance have to be or what’s the calculation for this?

try this code:

local desired_distance = 0
local previous_wire_position = nil

local RaycastResult = workspace:Raycast(OriginRay.Position, OriginRay.CFrame.UpVector * 20, raycastParams)

if RaycastResult then
    local wire_position = RaycastResult.Instance.Position
    
    if previous_wire_position ~= wire_position then
        -- calculate the new desired distance according to wire's position (you decrease the train's position from the wire're postion)
        desired_distance = 
        
        local LowerArmAngle = math.rad(-desired_distance * LowerArm.Size.Z)
        local UpperArmAngle = math.rad(desired_distance * UpperArm.Size.Z)

        LowerArm.Motor.C1 = CFrame.fromOrientation(LowerArmAngle / 2, 0, 0)
        UpperArm.Motor.C1 = CFrame.fromOrientation(UpperArmAngle, 0, 0)
    end
    
    previous_wire_position = wire_position
end

1 Like

This part is very confusing to me…

replace it with this:

local desired_distance = (wire_position - train_position).Magnitude

I tried the code you gave me and it didn’t work

Hello, it has been a while and I’ve still not been able to solve this issue and I really want to get this issue solved but I’m not very good at maths so its nearly impossible for me to figure this out by myself hence why I’ve made this Devforum post so if any could help please reply with your solution. This bug is starting to bug me now.

Thanks to anyone that can help!