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.
How it should be:
It should always be touching the wire no matter what the Z axis difference is.
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.
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!