Thoughts on Chain Sag Calculation

so where can we find an example where the minimum is not between the end-points?

David Lang

Sounds like a good problem for a stackoverflow question.

I just looked at the Wikipedia article on a Catenary. Here: https://en.wikipedia.org/wiki/Catenary. I actually think it would be pretty easy to implement the full Catenary equation. Here are a few key parts:

The Catenary equation
CatenaryEquation

The parameter “a”
aCalculation

s = length of Catenary (chain)
T0 = horizontal component of tension
lambda*g = Weight of chain (Need to make sure units work out)

Going back to @madgrizzle’s original example:

a=T0/lambda*g => a=15/0.1 => a=150

Set your coordinate system s.t. x1 is at the origin => x1=0

x2 = 5/sqrt(2) => x2=3.5355

s=asinh(x2/a)-asinh(x1/a) =>
s=150sinh(3.5355/150)-150sinh(0) = 3.5358

@Joshua the problem with that article (and all the ones we’ve found) is that they assume that the low point of the curve is between the end points

In the step where it then squares one of the values, you loose this fact and the resulting number can’t work.

work with these numbers

horizontal distance between supports 9 ft
vertical distance between supports 5.5 ft
weight of chain 0.09 lb/ft
tension 4 pounds

I just realized I used the wrong equation. I am not sure if there was a typo, but the calculation of s should give some number slightly greater than 5, not 3.53…

Looking again, the correct equation is below:
UpdatedCatenaryEquation

It appears to need a numeric solution. I was able to quickly iterate on a solution which makes sense.
manipulate to solve for s (as a function of s):
s=2asinh*(h/2a)-sqrt(s^2-v^2)+s

Start by assuming s=5.
Iteration 1:
s=2150sinh(3.53553/(2*150))-sqrt(5^2-3.53553^2)+5
s=5.000074

Iteration 2:
s=2150sinh(3.53553/(2*150))-sqrt(5.000074^2-3.53553^2)+5.000074
s=5.00004337

Iteration 3:
s=2150sinh(3.53553/(2*150))-sqrt(5.00004337^2-3.53553^2)+5.00004337
s=5.00005606


My numeric method could probably be improved upon, but the numbers seem to be reasonable.

The article says " It can be shown with the methods of calculus[54] that there is at most one solution with a > 0 and so there is at most one position of equilibrium"

When I read it, i interpret it as meaning there is only one solution. What are your thoughts?

One more update. It looks like the equation, while not solvable for “a”, is solvable for s. Here it is:
s=sqrt((2asinh(h/(2*a)))^2+v^2)

So:
s=sqrt((2150sinh(3.53553/(2*150)))^2+3.53553^2)
s=5.00005234

1 Like

I thought I would go ahead and apply the equation to this problem.

a=4/.09
=> a=44.4
h=9
v=5.5
s=sqrt((2x(4/0.09)*sinh(9/(2x4/0.09)))^2+5.5^2)
=> s=10.5606

Simple geometric length:
sqrt(5.5^2+9^2)=10.547

The difference is about 5/32 of an inch; the chain length is 5/32 longer than the geometric length. The answer seems reasonable.

4 Likes

That looks very promising. Could the tension on each side be approximated from the chain angles and total sled weight?

1 Like

Yeah. That was the solution I was envisioning. I haven’t done any math, but I would treat it as a simple statics problem; sum-of-forces=0.

1 Like

if you put a distance of 9 ft, 0.9 lb/ft, and a tension of 3.2 pounds into a
chain sag calculator online (supports at equal height) it reports chain sag of
around 1/2", why is the sag so much lower when you add a height difference (and
more chain) to the mix?

1 Like

Do you have a link to the calculator?

I’ll have to dig it up, I’ve posted it several times recently

https://www.spaceagecontrol.com/calccabl.htm?F=3.2&a=9&q=.09&g=32.18503937&Submit+Button=Calculate

I get the same answer as the calculator when using the inputs of 9 ft, 0.09 lb/ft, and 3.2 lb horizontal tension. The cable length is 9.024.

I put this into my holey calibration routine and after resolving 18 different bugs (math is hard), I have it running. It seems to give results like the current method. Only thing odd is that it thinks my sled weighs 11.5 lbs which it doesn’t.

1 Like

With current chain sag:

Best so far at N: 3009243, Error Magnitude: 0.931
Motor Spacing: 3581.47428, Motor Elevation: 479.74695, Top Beam Tilt: 0.0888631427684 degrees
tleftMotorX: -1792.59763173, tleftMotorY: 1086.5696
trightMotorX: 1788.87234072, trightMotorY:1092.1243
tmotorspacing: 3581.47428
Rotation Disk Radius: 132.88, Chain Sag Correction Value: 22.443462647, Left Chain:0.0632865150145, Right Chain:0.0632865150145
leftMotorX: -1792.59763173, leftMotorY: 1086.5696
rightMotorX: 1788.87234072, rightMotorY:1092.1243
LChain Error Hole 0: -0.6028 RChain Error Hole 0: -0.8675 RMS Error Hole 0: 1.0564
LChain Error Hole 1: -0.2989 RChain Error Hole 1: 0.3 RMS Error Hole 1: 0.4235
LChain Error Hole 2: 0.8597 RChain Error Hole 2: 0.729 RMS Error Hole 2: 1.1272
LChain Error Hole 3: -0.5312 RChain Error Hole 3: 0.4179 RMS Error Hole 3: 0.6759
LChain Error Hole 4: 0.5885 RChain Error Hole 4: -0.5364 RMS Error Hole 4: 0.7962
LChain Error Hole 5: 0.9908 RChain Error Hole 5: -0.1574 RMS Error Hole 5: 1.0033
LChain Error Hole 6: -0.3237 RChain Error Hole 6: -0.7412 RMS Error Hole 6: 0.8088
LChain Error Hole 7: -1.5464 RChain Error Hole 7: -0.0826 RMS Error Hole 7: 1.5486
LChain Error Hole 8: 0.3 RChain Error Hole 8: -0.1639 RMS Error Hole 8: 0.3419

With alternate chain sag:

Best so far at N: 3880627, Error Magnitude: 0.953
Motor Spacing: 3581.41866, Motor Elevation: 480.05655, Top Beam Tilt: 0.0895876365325 degrees
tleftMotorX: -1792.60372411, tleftMotorY: 1086.8566
trightMotorX: 1788.81055789, trightMotorY:1092.4565
tmotorspacing: 3581.41866
Rotation Disk Radius: 133.151, Chain Sag Correction Value: 11.415580169, Left Chain:0.0570802539334, Right Chain:0.0570802539334
leftMotorX: -1792.60372411, leftMotorY: 1086.8566
rightMotorX: 1788.81055789, rightMotorY:1092.4565
LChain Error Hole 0: -0.6072 RChain Error Hole 0: -0.9057 RMS Error Hole 0: 1.0904
LChain Error Hole 1: -0.3035 RChain Error Hole 1: 0.3167 RMS Error Hole 1: 0.4387
LChain Error Hole 2: 0.936 RChain Error Hole 2: 0.6411 RMS Error Hole 2: 1.1345
LChain Error Hole 3: -0.5746 RChain Error Hole 3: 0.5032 RMS Error Hole 3: 0.7638
LChain Error Hole 4: 0.6612 RChain Error Hole 4: -0.5591 RMS Error Hole 4: 0.8659
LChain Error Hole 5: 0.9573 RChain Error Hole 5: -0.2053 RMS Error Hole 5: 0.9791
LChain Error Hole 6: -0.3 RChain Error Hole 6: -0.7945 RMS Error Hole 6: 0.8493
LChain Error Hole 7: -1.5687 RChain Error Hole 7: -0.0751 RMS Error Hole 7: 1.5705
LChain Error Hole 8: 0.3002 RChain Error Hole 8: -0.2356 RMS Error Hole 8: 0.3816

2 Likes

I recommend you use the Levenberg Marquardt algorithm to do the optimization. It is a curve-fit, which is a little different. Once implemented, it will be much faster. There won’t be these thousands of iterations. It will converge in a few, to a few dozen iterations.

It is available in Python in a library, either scipy or numpy. I don’t remember which.

1 Like

So it converged on practically the same parameters, except chain sag is substantially different, but that’s not surprising. The end error value was 0.93 just like the current method.

This is the routine I’m using:

  leftForce = chainSagCorrection/((targetX-leftMotorX)/(leftMotorY-targetY)+(rightMotorX-targetX)/(rightMotorY-targetY))*math.sqrt(math.pow(((rightMotorX-targetX)/(rightMotorY-targetY)),2)*math.pow(((targetX-leftMotorX)/(leftMotorY-targetY)),2)+math.pow(((rightMotorX-targetX)/(rightMotorY-targetY)),2))
  rightForce =chainSagCorrection/((targetX-leftMotorX)/(leftMotorY-targetY)+(rightMotorX-targetX)/(rightMotorY-targetY))*math.sqrt(math.pow(((rightMotorX-targetX)/(rightMotorY-targetY)),2)*math.pow(((targetX-leftMotorX)/(leftMotorY-targetY)),2)+math.pow(((targetX-leftMotorX)/(leftMotorY-targetY)),2))
	hl = math.cos(leftChainAngleTarget)*leftChainStraightTarget*0.00328084
	hr = math.cos(rightChainAngleTarget)*rightChainStraightTarget*0.00328084
	vl = math.sin(leftChainAngleTarget)*leftChainStraightTarget*0.00328084
	vr = math.sin(rightChainAngleTarget)*rightChainStraightTarget*0.00328084
	al = math.cos(leftChainAngleTarget)*leftForce/0.09
	ar = math.cos(rightChainAngleTarget)*rightForce/0.09
	leftChainSag = math.sqrt( math.pow((2*al*math.sinh(hl/(2*al))),2)+vl*vl)/0.00328084
	rightChainSag = math.sqrt( math.pow((2*ar*math.sinh(hr/(2*ar))),2)+vr*vr)/0.00328084
	LChainLengthTarget = (leftChainAroundSprocketTarget + leftChainSag*leftChainTolerance)-rotationRadius
	RChainLengthTarget = (rightChainAroundSprocketTarget + rightChainSag*rightChainTolerance)-rotationRadius

The force calculation appears dimensionless (the part that divides into chainSagCorrection) so I don’t think I have to worry about units being in mm.

The only thing concerning is that chainSagCorrection, which is basically the sled weight here, is too low if it truly represents the sled weight.

Here’s a sample of the calculations:

chainSag: 30.0
targetX,Y: 0, 0
chainStraightL,R: 2095.25386998, 2095.25386998
ForcesL,R: 28.8908257068, 28.8908257068
anglesL,R: 31.554701169, 31.554701169
hl, hr: 5.85778143585, 5.85778143585
vl, vr: 3.59734930469, 3.59734930469
al, ar: 273.545078447, 273.545078447
Lchains (straight, sag, delta): 2095.25386998, 2095.28294102, 0.0290710335626
Rchains (straight, sag, delta): 2095.25386998, 2095.28294102, 0.0290710335626
finals: 1968.09884324, 1968.09884324

(finals are modified by chain wrap and rotational radius)