Activity › Forums › Adobe After Effects Expressions › Two interconnected points of rotation
-
Two interconnected points of rotation
Posted by George Umanov on February 3, 2019 at 5:44 pmHi all,
Need a bit of help on this animation of “two interconnected points of rotation”.
Here is a photo for visual aid:

It’s basically two mechanical “levers” that are connected together by a rod. The right one is the input (green arm), which controls the “fuel arm” to the left.
I managed to get the rod to rotate properly with the rotation of the input (and the rod automatically faces itself toward the anchor point of the fuel arm), but I can’t figure out a way to calculate the proper angle for the fuel arm rotation (relative to input rotation angle).
For example: If green arm is rotated by 30 degrees, the resultant angle of fuel arm rotation is roughly 42.5 degrees. I’d like to make an expression for this so it’s done automatically without me constantly having to manually rotate the fuel arm after rotating the green input arm.
Note: The mechanism is physically limited in the range of -40 degrees to +60 degrees, so the green input arm will never be outside of that range.
For those wondering, it’s the fuel control mechanism of a PT6 turbine engine.
The top part of the image is the “zero” point. All rotation are done from this initial point. So ultimately it’s the rotation angle of line “E” that I’m after, in relation to line “F” rotation.Thanks for any suggestions!
George Umanov replied 6 years, 8 months ago 2 Members · 6 Replies -
6 Replies
-
Oleg Pirogov
February 4, 2019 at 7:54 amIt can be done with an iteration algorithm:
https://www.youtube.com/watch?v=5R-GqLtYOJ4In my implementation the rod is attached to Arms 1 and 2 at Nulls 1 and 2;
Arm 2 is Input.
Arm 1 is Fuel.This expression for Arm 1 Rotation approximates the Rotation Angle of Arm 1 till the distance between attachment points [almost] equals the length of the Rod:
//computes the difference between (target) Rod's length and a length you get when dependent Arm's rotation is alpha
var deltaRodLength = function(alpha){
//Arm 1 radius
R1 = thisComp.layer("Animation Controls").effect("D1")("Slider")/ 2;
arm1 = thisComp.layer("Arm 1");
arm2 = thisComp.layer("Arm 2");
//point at which Rode is attached to Arm 2
null2Pos = arm2.toWorld(thisComp.layer("Null 2").position);//Rode length
targetRodLength = thisComp.layer("Animation Controls").effect("Rod Length")("Slider");
currentRodLength = length([R1*Math.cos(alpha), -R1*Math.sin(alpha)]+arm1.position, null2Pos);return currentRodLength - targetRodLength;
}a = 0
b = Math.PI;
err = 0.001//iteration algo
i=0
while (Math.abs(deltaRodLength((a+b)/ 2)) >=err){
if (deltaRodLength((a+b)/ 2) > 0){b = (a+b)/ 2;}
if (deltaRodLength((a+b)/ 2) < 0){a = (a+b)/ 2;}
if (deltaRodLength((a+b)/ 2) == 0){
a = (a+b)/ 2;
b = (a+b)/ 2;
}//this prevents AE from freezing when no solution exists
i++;
if (i>200) {break;};
}-radiansToDegrees((a+b)/ 2);
Surprisingly neat expression.
Of cause, it can also been done with an explicit trigonometric formula for the Fuel Arm angle, but it’s quite hideous.Some contents or functionalities here are not available due to your cookie preferences!This happens because the functionality/content marked as “Google Youtube” uses cookies that you choosed to keep disabled. In order to view this content or use this functionality, please enable cookies: click here to open your cookie preferences.
-
George Umanov
February 5, 2019 at 5:05 amAlthough I haven’t been able to modify your expression to work correctly in my composition (yet), I’m really impressed with how quickly you came up with that! Thank you!
I modified it to try to make it work with my layer names and dimensions, but I can’t figure it out.
Here’s what I have so far:
Arm 1 = “FCU arm”
Arm 2 = “Cam input arm”Rod attaches to FCU arm (arm1) at Null 1 (“Interconnect Point A – pivot”)
Road attaches to Cam input arm (arm2) at Null 2 (“Interconnect Point B – pivot”)Parenting:
Null 1 parent is FCU arm
Null 2 parent is Cam input armRod position expression:
B = thisComp.layer(“Interconnect Point B – pivot”);
B.toWorld(B.anchorPoint);Null 3 (“Rod Point C”) is parented to the rod (where it attaches to FCU arm (arm1).
Used to calculate rod length.Link to AE file below, if you want to have a closer look
https://curious.ninja/wp-content/uploads/misc/FCU_Interconnect_folder.zipAppreciate any further help,
Thank you//computes the difference between (target) Rod's length and a length you get when dependent Arm's rotation is alpha
var deltaRodLength = function(alpha){
arm1 = thisComp.layer("FCU arm");
arm2 = thisComp.layer("Cam input arm");
rod = thisComp.layer("FCU Interconnect rod");
//point at which Rod is attached to Arm 1
null1Pos = arm1.toWorld(thisComp.layer("Interconnect Point A - pivot").position);
//point at which Rod is attached to Arm 2
null2Pos = arm2.toWorld(thisComp.layer("Interconnect Point B - pivot").position);
//point at which Rod is attached to Arm 1, parented to rod
null3Pos = rod.toWorld(thisComp.layer("Rod Point C").position);
//Arm 1 radius
R1 = length(thisComp.layer("FCU arm").position, null1Pos);//Rod length
targetRodLength = length(null3Pos, null2Pos);
currentRodLength = length([R1*Math.cos(alpha), -R1*Math.sin(alpha)]+arm1.position, null2Pos);return currentRodLength - targetRodLength;
}a = 0
b = Math.PI;
err = 0.001//iteration algo
i=0
while (Math.abs(deltaRodLength((a+b)/ 2)) >=err){
if (deltaRodLength((a+b)/ 2) > 0){b = (a+b)/ 2;}
if (deltaRodLength((a+b)/ 2) < 0){a = (a+b)/ 2;}
if (deltaRodLength((a+b)/ 2) == 0){
a = (a+b)/ 2;
b = (a+b)/ 2;
}//this prevents AE from freezing when no solution exists
i++;
if (i>200) {break;};
}-radiansToDegrees((a+b)/ 2)+119.8;
-
Oleg Pirogov
February 5, 2019 at 7:31 amThe implementation is generally fine as is.
If you put the Rod layer (“FCU Interconnect Rod”) beneath the FCU arm layer, it will work like intended, as I presume:https://www.youtube.com/watch?v=ZLkF7eAffhw
Switching layers’ order is not a proper solution though, the problem is that you have a cross reference:
Rod -(expression)-> A
A -(child)-> FCU arm
FCU arm -(expression)-> C
C -(child) -> RodRod -(expression)-> A -(child)-> FCU arm -(expression)-> C -(child) -> Rod
In this case Gd only knows in what order AE will render and what output you’ll get.
If Rod is above FCU arm you get this:

If Rod is below FCU arm you (may) get:

The Rod image is in the right place but null and source rectangle are not.
This can be cured by cache cleaning but may also lead to various bugs in the future.Bottom line, you would probably wanna find another way to define the Rod length (maybe just a constant), thus breaking the reference loop at C-point. Namely, getting rid of this reference:
//point at which Rod is attached to Arm 1, parented to rod
null3Pos = rod.toWorld(thisComp.layer("Rod Point C").position);Some contents or functionalities here are not available due to your cookie preferences!This happens because the functionality/content marked as “Google Youtube” uses cookies that you choosed to keep disabled. In order to view this content or use this functionality, please enable cookies: click here to open your cookie preferences.
-
George Umanov
February 9, 2019 at 10:43 pmOleg,
Thank you much for the help! I got that interconnect working with your expressions and suggestions.
I decided to use the constant rod length.I am using your same method to rotate another 3rd lever, attached to the FCU arm. Still needs some tweaking, but I’m very close!
AE Files:
https://curious.ninja/wp-content/uploads/misc/Overcenter-interconnect.zipIf you rotate the green “cam input lever” you can see how it works so far.
Seems to rotate the 3rd lever only after 30 degrees on the green arm. -
Oleg Pirogov
February 11, 2019 at 7:54 amI see you’ve switched to AE CC 2019. Bear in mind that it has an updated expression engine and is much more strict on syntax and
I’ve only tested this code in previous versions. Though, I believe, I was careful with syntax, still some issues may rise when running this code in CC 2019. -
George Umanov
September 14, 2019 at 5:52 pmHi Oleg,
Apologies for bringing back such an old thread, but I wanted to give this another attempt – I never did get that second lever working properly. The second lever only rotates after approximately +29 degrees of input from the main input arm.
In following images, the green path is the “rod”.
0 degrees:

29 degrees

45 degrees

What do you think is the cause of the gap between 0 and 29 degrees?
Appreciate any help, thank you!Below are the project files in CC 2019:
https://curious.ninja/wp-content/uploads/misc/CC2019Overcenter-interconnect-lever.zipI can add the CC 2018 version if needed..
//computes the difference between (target) Rod's length and a length you get when dependent Arm's rotation is alpha
var deltaRodLength = function(alpha){
arm1 = thisComp.layer("FCU lever");
arm2 = thisComp.layer("FCU arm");
rod = thisComp.layer("Overcenter rod simulator");
//point at which Rod is attached to Arm 1
null1Pos = arm1.toWorld(thisComp.layer("Overcenter Point A - fuel lever anchor").position);
//point at which Rod is attached to Arm 2
null2Pos = arm2.toWorld(thisComp.layer("Overcenter Point B - fuel arm anchor").position);
//Arm 1 radius
R1 = length(thisComp.layer("FCU lever").position, null1Pos);
//Rod length
targetRodLength = 240.81;
currentRodLength = length([R1*Math.cos(alpha), -R1*Math.sin(alpha)]+arm1.position, null2Pos);return currentRodLength - targetRodLength;
}a = 0
b = Math.PI;
err = 0.001//iteration algo
i=0
while (Math.abs(deltaRodLength((a+b)/2)) >=err){
if (deltaRodLength((a+b)/2) > 0){b = (a+b)/2;}
if (deltaRodLength((a+b)/2) < 0){a = (a+b)/2;}
if (deltaRodLength((a+b)/2) == 0){
a = (a+b)/2;
b = (a+b)/2;
}//this prevents AE from freezing when no solution exists
i++;
if (i>100) {break;};
}-radiansToDegrees((a+b)/2)+180;
Reply to this Discussion! Login or Sign Up
