# Thoughts on Chain Sag Calculation

#41

@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

#42

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:

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.

Discussion Regarding Triangular Calibration
#43

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?

#44

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

#45

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.

#46

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

#47

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.

#48

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?

#49

Do you have a link to the calculator?

#50

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

#51

#52

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.

#53

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.

#54

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

#55

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.

#56

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)

Optical Calibration Demo and Three Hours Working on a Bug
#57

I compared the current calculations with the alternate calculations and it looks like, for the same chain sag parameter, the alternate method calculates substantially less sag:

–Original–
Lchains (straight, sag, delta): 2095.25386998, 2095.4733707, 0.219500713652
Rchains (straight, sag, delta): 2095.25386998, 2095.4733707, 0.219500713652
–New–
MotorSeparation: 3581.481
MotorHeight: 1087.86
chainSag: 30.0
targetX,Y: 0.0, 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
%DifferenceL,R: -86.7558364258%, -86.7558364258%
finals: 1968.09884324, 1968.09884324

#58

Well, I’ll try it out and see how it works when I can get back out to the shed. I’ve put it into the firmware and it will be used if you enter a negative value for chain sag.

#59

How confident are you in the chain tension calculation? Would it be worthwhile for someone to check it?

#60

Well, I posted the routine above with the hope someone could find something wrong with it… but keep in mind that when I say I put it in the firmware, that’s just in my customized version that I use for testing. It’s not going into general public use (though anyone has access to it off my github repo) until everyone agrees on it.

Also, I have no official relationship with @bar, et al. I’m just a community guy trying to make things better.