feduni / caliko Goto Github PK
View Code? Open in Web Editor NEWThe Caliko library is an implementation of the FABRIK inverse kinematics algorithm in Java.
License: MIT License
The Caliko library is an implementation of the FABRIK inverse kinematics algorithm in Java.
License: MIT License
Request: a "Hello World" caliko guide, or maybe the right tests to copy code from.
I have what (I think) is a pretty straightforward 2d need, but I wasn't sure where to start.
(Imagine clasping your hands together above your head: your neck is the origin, your shoulders are the -5,+5, your upper arms are the 15, your forearms are the 10s, you are holding a single spray paint can with both of your hands, and you are spray painting the wall using just your shoulder rotation muscles)
Do I start with the demos? The tests?
Hello
Thank you for your generous sharing!
When I was learning your code, I didn’t quite understand the meaning of these functions, such as createRotationMatix, projectOntoPlane.
Especially this process :
Mat3f m = Mat3f.createRotationMatrix( mChain.get(loop-1).getDirectionUV() )
Vec3f relativeHingeRotationAxis = m.times( thisBoneJoint.getHingeRotationAxis() ).normalise()
thisBoneOuterToInnerUV = thisBoneOuterToInnerUV.projectOntoPlane(relativeHingeRotationAxis);
Looking forward to your reply!
If you're busy, could you recommend me some papers to understand this process?
Thanks!
hello in FabrikChain3D.java
on solveIK Backward pass
end GLOBAL_HINGE and LOCAL_HINGE have
Utils.approximatelyEquals(cwConstraintDegs , FabrikJoint3D.MAX_CONSTRAINT_ANGLE_DEGS, 0.01f)
but should be
Utils.approximatelyEquals(cwConstraintDegs , -FabrikJoint3D.MAX_CONSTRAINT_ANGLE_DEGS, 0.01f)
Hello,
I'm probably just bad at Gradle but doing
dependencies{ implementation("au.edu.federation.caliko:caliko:1.3.6") implementation("au.edu.feduni.caliko.visualisation:caliko-visualisation:1.3.6")
gives me
`A problem occurred evaluating root project 'BaseElbow'.
Could not resolve all files for configuration ':runtimeClasspath'.
Could not find au.edu.federation.caliko:caliko:1.3.6.
Searched in the following locations:
- https://jitpack.io/au/edu/federation/caliko/caliko/1.3.6/caliko-1.3.6.pom
- https://jitpack.io/au/edu/federation/caliko/caliko/1.3.6/caliko-1.3.6.jar
- https://repo.maven.apache.org/maven2/au/edu/federation/caliko/caliko/1.3.6/caliko-1.3.6.pom
- https://repo.maven.apache.org/maven2/au/edu/federation/caliko/caliko/1.3.6/caliko-1.3.6.jar
Required by:
project :
Could not find au.edu.feduni.caliko.visualisation:caliko-visualisation:1.3.6.
Searched in the following locations:
- https://jitpack.io/au/edu/feduni/caliko/visualisation/caliko-visualisation/1.3.6/caliko-visualisation-1.3.6.pom
- https://jitpack.io/au/edu/feduni/caliko/visualisation/caliko-visualisation/1.3.6/caliko-visualisation-1.3.6.jar
- https://repo.maven.apache.org/maven2/au/edu/feduni/caliko/visualisation/caliko-visualisation/1.3.6/caliko-visualisation-1.3.6.pom
- https://repo.maven.apache.org/maven2/au/edu/feduni/caliko/visualisation/caliko-visualisation/1.3.6/caliko-visualisation-1.3.6.jar
Required by:
project :
`
What should I use instead?
au.edu.federation
is empty on Maven, have you guys taken it down?
I'm not sure I'm following the right steps to run the jar files provided with the releases (I don't have a proper environment for building java solutions in my machine, so I just wanted to test the built solutions), but this is the output of my attempts on Windows 10:
java -jar caliko-demo-1.3.6-jar-with-dependencies.jar
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: au/edu/federation/caliko/demo/Application has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
This is my version of java:
java -version
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)
The library requires Java 1.8 in order to build. However, most (all?) versions of Android are limited to Java 1.7 (with only very limited support of certain 1.8 features). This makes the distribution .jar files useless for Android development.
The compilation problems are not very serious. In au.edu.federation.utils.Util there is a reference to Float.BYTES that only exists in 1.8. Hardcoding that value to "4" fixes the issue. I've only done this in my local copy of the core, but it appears during the maven build that similar issues exist in demo and visualization as well.
In forward or backward phase of FABRIK algorithm, it should be check that the target is not out of the ellipsoidal shape according to the paper you mentioned:
Aristidou, A., & Lasenby, J. (2011). FABRIK: a fast, iterative solver for the inverse kinematics problem. Graphical Models, 73(5), 243-260.
But in your code, you're just checking the angle between two vectors and rotating the vector that relates to the target.
I think this is not the correct way that FABRIK solves it. The algorithm should check the position of the target according to an ellipsoidal shape, as explained in the paper.
Hi,
This is a really cool library. How are the joint angles output from this library?
For example, I setup a moving target of a particular path and the structure with a single chain works like an arm manipulator. At each step, I would like to know what the 3D joint angle (roll, pitch, and yaw) are throughout the entire motion. What are the necessary steps for this output?
Thank you
Hi Al,
First of all - Big thank you for this library and making it free to use and play with. For the last few days I've been rewriting it to C++ and learning how to use it but I've found this potential issue.
I'm trying to use it for character IK where I'll set the ends of all limbs and let the IK solve my skeleton, but while playing with the code I've found that you use only single target location for every chain.
It would be easy change to pass separate target to each chain, that's not a problem, but I'm not too familiar with the FABRIC itself yet so I'm not sure if I won't break anything else.
Do you think that just passing a different targets could work?
BTW I'm sorry I'm asking you by creating an Issue, but I couldn't find any other way to post a message :(. Feel free to delete this Issue to keep your repo clean.
Regards,
kolenda
Hello, maybe I found the bug of the FABRIK algorithm or your code, so I want to discuss this bug with you and get your advice if you want.
Based on Demo 7, I built a chain as shown below. The start and end positions of each bone are: [0, 0, 0] [0, 0, 40]; [0, 0, 40], [0, 0, 80]; [0, 0, 80], [0, 0, 120]. The target that I want to solve is [0, 0, 100]. I have tried to change the joint limit many times, but all the results were all problematic. This chain is always along the z-axis, and the end of the last bone is not placed at the target position. The ideal configuration of this chain should be like this:
Did I make a mistake? Looking forward to your reply!
Code:
public class LocalHingesWithReferenceAxisConstraints extends CalikoDemoStructure3D {
@Override
public void setup() {
this.structure = new FabrikStructure3D("Demo 7 - Local Hinges with Reference Axis Constraints");
int numChains = 1; // 3
Vec3f hingeRotationAxis = new Vec3f();
Vec3f hingeReferenceAxis = new Vec3f();
Vec3f baseBoneConstraintAxis = new Vec3f();
float baseBoneConstraintAngleDegs = 90.0f;
baseBoneConstraintAxis = X_AXIS;
float rotStep = 360.0f / (float)numChains;
for (int loop = 0; loop < numChains; loop++)
{
// Set colour and axes
Colour4f chainColour = new Colour4f();
switch (loop % 3)
{
case 0:
chainColour = Utils.RED;
hingeRotationAxis = new Vec3f(X_AXIS);
hingeReferenceAxis = new Vec3f(Y_AXIS);
break;
case 1:
chainColour = Utils.GREEN;
hingeRotationAxis = new Vec3f(Y_AXIS);
hingeReferenceAxis = new Vec3f(X_AXIS);
break;
case 2:
chainColour = Utils.BLUE;
hingeRotationAxis = new Vec3f(Z_AXIS);
hingeReferenceAxis = new Vec3f(Y_AXIS);
break;
}
FabrikChain3D chain = new FabrikChain3D();
Vec3f startLoc = new Vec3f(0.0f, 0.0f, 0.0f);
startLoc = Vec3f.rotateYDegs(startLoc, rotStep * (float)loop);
Vec3f endLoc = startLoc.plus( defaultBoneDirection.times(base_BoneLength) ); // base_BoneLength = 40
FabrikBone3D basebone = new FabrikBone3D(startLoc, endLoc);
basebone.setColour(chainColour);
chain.addBone(basebone);
chain.setRotorBaseboneConstraint(FabrikChain3D.BaseboneConstraintType3D.GLOBAL_ROTOR, baseBoneConstraintAxis, baseBoneConstraintAngleDegs);
float constraintAngleDegs_1 = 120.0f;
chain.addConsecutiveHingedBone(defaultBoneDirection, (float) 40, JointType.LOCAL_HINGE, hingeRotationAxis, constraintAngleDegs_1, constraintAngleDegs_1, hingeReferenceAxis, Utils.GREY);
chain.addConsecutiveHingedBone(defaultBoneDirection, (float) 40, JointType.LOCAL_HINGE, hingeRotationAxis, constraintAngleDegs_1, constraintAngleDegs_1, hingeReferenceAxis, Utils.GREY);
this.structure.addChain(chain);
}
}
Hi!
I was confused about the hingeRefetenceAxis, so I want to discuss it with you.
When I create a bone that the default direction is the z-axis and the HingeRotationAxis is the y-axis, then the problem comes.
If I set the direction of the HingeReferenceAxis as the x-axis and its constraintAngleDeg is ±30 degs (for example). At this time,
if we execute this Vec3f.getSignedAngleBetweenDegs function to measure the rotation angle of this bone, the obtained value is 90 degs.
But this bone doesn't rotate, so should I set the direction of the HingeReferenceAxis to be the same as the defaultBoneDirection?
I remember that the hinge rotation axis should be on the same plane as the reference axis. Is there a contradiction?
Looking forward to your reply!
IK solutions when using local hinges, especially with references constraints, exhibit discontinuities in the solutions. This isn't necessarily to say that the solutions are bad - they aren't - but that they can 'snap' from one side of a constraint to another, which may have knock-on effects on other bones in the same chain, resulting in 'jumps' in the chain's solution.
The issue may also be exacerbated by the fact that bone directions are not kept in quaternions (which would enable smooth 'closest-path-to' interpolation [i.e. lerp] from one vector to another) - they are held as plain start and end points, from which a direction is determined and used for the generation of axes. However, a single directional vector does not contain enough information to allow for the generation of 100% consistent perpendicular axes, as when the direction of the bone is the same as the what is used for the 'up' vector when generating an orthonormal basis, an alternate vector must be used which may also add to the 'jump' in chain configuration.
Resolving this issue with code to avoid snapping through constraints would introduce a form of joint-lock where you can't get there from here, which is undesirable - but storing bone directions either in quaternions or along with their own per-bone Model matrix could mitigate orthonormal axis generation issues which I believe add to the observed discontinuities in the solutions to chains involving local hinges.
I've thought out the basis of a comparative investigation of local-hinge algorithm modifications, and I would love to complete it in 2016 - but it depends on what interest there is in this library, as it forms only the very first research artefact of my PhD through publication, and I have only 17 months left to publish another five papers. For perspective, this library took me 18 months to write.
This function returns the following output (not a rotation matrix) when it gets Vec3f(0.0f, -1.0f, 0.0f)
X Axis: 0.000, 0.000, 0.000
Y Axis: 0.000, 0.000, 0.000
Z Axis: 0.000, -1.000, 0.000
As far as I read this code, this function fails in coping with Y-axis singularity.
I think it should be the following
X Axis: 1.000, 0.000, 0.000
Y Axis: 0.000, 0.000, -1.000
Z Axis: 0.000, -1.000, 0.000
This is my implementation suggestion I wrote to fix this.
I replaced this section
`
if (referenceDirection.y == 1.0f) {
referenceDirection.y -= 0.0001f;
referenceDirection.normalise();
}
by
if (Math.abs(referenceDirection.y) > 0.9999f) {
rotMat.setZBasis(referenceDirection);
rotMat.setXBasis( new Vec3f(1.0f, 0.0f, 0.0f));
rotMat.setYBasis( Vec3f.crossProduct( rotMat.getXBasis(), rotMat.getZBasis()).normalised());
return rotMat;
}`
Thank you.
On 64-bit Arch Linux (Kernel 4.3.3-3) using Nvidia 358.16-1 and jdk8-openjdk 8.u72-1, libGL.so may cause the demo application to crash on startup. This issue does not appear to be specific to Caliko - even a simple LWJGL3 program that initialises and then immediately terminates causes the same crash behaviour.
A workaround for this issue is to run the demo application from source code in an IDE such as Eclipse and choose to run it via "Debug As..." rather than "Launch As..." - quite why this works while a standard launch does not is currently unknown.
The Windows platform does not exhibit this issue.
Error log:
hs_err_pid9892.log.txt
Forum discussion with LWJGL3 developer regarding the issue:
http://forum.lwjgl.org/index.php?topic=6048.0
First thank you for your excellent work and great project.
I was looking through previous issues and you said you were not interested in sonatype maven central distribution.
Would you be interested in publishing to your github project ?
You can turn it into a repo as well - https://gist.github.com/fernandezpablo85/03cf8b0cd2e7d8527063
Best Regards,
GroG
Hi! Thank u for your excellent work so that I can learn and improve on your basis.
When studying LocalHingesWithReferenceAxisConstraints.java, I was confused about some settings.
The original code:
`float constraintAngleDegs = 90.0f;
for (int boneLoop = 0; boneLoop < 6; boneLoop++)
{
if (boneLoop % 2 == 0)
{
chain.addConsecutiveHingedBone(defaultBoneDirection, defaultBoneLength, JointType.LOCAL_HINGE, hingeRotationAxis, constraintAngleDegs, constraintAngleDegs, hingeReferenceAxis, Utils.GREY);
}
else
{
chain.addConsecutiveBone(defaultBoneDirection, defaultBoneLength, chainColour);
}
}
`
The modified code:
`float constraintAngleDegs = 0.0f;
for (int boneLoop = 0; boneLoop < 6; boneLoop++)
{
chain.addConsecutiveHingedBone(defaultBoneDirection, defaultBoneLength, JointType.LOCAL_HINGE, hingeRotationAxis, constraintAngleDegs, constraintAngleDegs, hingeReferenceAxis, Utils.GREY);
}
`
Therefore, all the bone rotation axes in the chain of case 3 are z-axes and can’t rotate because the constraint angle of each rotation axis is zero. The initial direction of this chain is the z-axis in world space. Since the rotation axis of each bone in this chain is z-axis and the rotation angle limit is zero, shouldn’t this chain remain straight? But when I run this demo, this chain (the blue one) act like this:
Looking forward to your reply!
I'd been racking my brain as to why certain solutions don't seem to be calculated... even though the demo works perfectly in similar conditions. So to debug it, I just changed the demo to the 2-bone structure I'm using. The relevant demo codes looks like:
FabrikBone2D basebone;
basebone = new FabrikBone2D(new Vec2f(0,0), new Vec2f(0,6*boneLength));
basebone.setClockwiseConstraintDegs(90.0f);
basebone.setAnticlockwiseConstraintDegs(90.0f);
chain.addBone(basebone);
// Fix the base bone to its current location, and constrain it to the positive Y-axis
chain.setFixedBaseMode(true);
chain.setBaseboneConstraintType(BaseboneConstraintType2D.GLOBAL_ABSOLUTE);
chain.setBaseboneConstraintUV( new Vec2f(0.0f, 1.0f) );
// Create and add the second bone - 135 clockwise, 0 anti-clockwise
chain.addConsecutiveConstrainedBone(new Vec2f(1.0f, 0.0f), 8*boneLength, 135.0f, 0);
And the demo plots it like this:
It will work correctly for all points right of (0,0). But if you click to the left of 0,0 you get unreachable even though with the set constraints, a solution should be possible.
You can actually get to the solution if you DRAG the effector over to the desired point. But it would be better if the solution was correctly calculated with a single touch.
I looked at the source code, but the cause of the problem wasn't immediately apparent. So I'm kicking it over the fence.
Hello again !
I was wondering if there is a way to easily extract angles between the bones ?
I've been playing around with Caliko for a little bit, and can see how to iterate through the bones ..
for (FabrikBone3D bone : chains.get("default").getChain()) {
bone.getStartLocation().getGlobalPitchDegs();
bone.getStartLocation().getGlobalYawDegs();
Vec3f.getDirectionUV(bone.getStartLocation(), bone.getEndLocation());
System.out.println("Bone X: " + bone.getStartLocation().toString());
}
but didn't find any methods for computed angles.
Would I need to get the start and end vector of each bone then compute it again ?
Digging deeper I saw this for local hinges, and tried adding the calculation for the local angle
case LOCAL_HINGE:
// Local hinges get constrained to the hinge rotation axis, but not the reference axis within the hinge plane
// Construct a rotation matrix based on the previous bones inner-to-to-inner direction...
Mat3f m = Mat3f.createRotationMatrix( mChain.get(loop-1).getDirectionUV() );
// ...and transform the hinge rotation axis into the previous bones frame of reference.
Vec3f relativeHingeRotationAxis = m.times( thisBoneJoint.getHingeRotationAxis() ).normalise();
// Project this bone's outer-to-inner direction onto the plane described by the relative hinge rotation axis
// Note: The returned vector is normalised.
thisBoneOuterToInnerUV = thisBoneOuterToInnerUV.projectOntoPlane(relativeHingeRotationAxis);
// Calculate the dot product between the two vectors
float dotProduct = Vec3f.dotProduct(thisBoneOuterToInnerUV, relativeHingeRotationAxis);
// Use the dot product to calculate the angle (in radians) between the vectors
float localHingeAngle = (float)Math.acos(dotProduct);
// If you want the angle in degrees, you can convert it
float localHingeAngleDegrees = (float)Math.toDegrees(localHingeAngle);
System.out.println(String.format("angle: %f", localHingeAngleDegrees));
break;
Heh, it gave me nothing but 90 degrees 🙄
angle: 90.000008
angle: 89.999992
angle: 90.000000
angle: 90.000000
angle: 90.000000
angle: 90.000000
angle: 90.000008
angle: 89.999992
angle: 90.000000
angle: 90.000000
angle: 90.000000
angle: 90.000000
angle: 90.000008
Bone X: x: 0.000, y: 10.000, z: 0.000
Bone X: x: -14.142, y: 10.000, z: 0.000
Bone X: x: -19.066, y: 9.132, z: 0.000
Bone X: x: -15.811, y: -9.328, z: 6.974
The big picture is, I would like an IK solver to solve servo positions for a robot project called InMoov.
I've roughed out the right arm.
To begin with I'd like to control 4 servos at 4 joints, but I need the local angles.
The joints in order from top to bottom are:
chain.addConsecutiveFreelyRotatingHingedBone(getAxis(directionUV), length, JointType.LOCAL_HINGE, getAxis(hingeRotationAxis), getColor(color));
Appreciate any help.
Regards,
GroG
How do we represent a linear slide in caliko?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.