leapFrame.js defines a function that helps you read and act on a single frame of leap data.
The leap device passes 'frames' of data as it sees objects in the world. A single frame of data has information on how many objects are seen, what direction they're pointing, where they're located in 3D space etc. Take time and look at leapFrame.js and the functions it provides:
- palm position
- palm direction
- palm normal vector
- finger position
- finger angle
- delta finger position
If you need some help figuring out what some of these vectors look like, take a look at the leap documentation, they have nice pictures showing all the axis etc.
joint.js defines a function that helps create and move joints. In the sample code sent me, you see a joint constructed like this:
var middle = new Joint({
minPos: 70,
maxPos: 220,
pin: 6,
range: [60,150]
});
The range is quite important, this is where you specify the range of motion in degrees of the servo. The servo above is being set to 60 degrees minimum, 150 degrees maximum.
minPos, maxPos - These define the minimum and maximum value for the leap property that is being used to move this servo. For instance, in the code above, you can see the minPos and maxPos values being set to 70 and 220. 70 and 220 are values you'll be getting from the leap device for whatever part/property of the hand you choose. In the example, the palm's height is being used:
middle.move(frame.palmPosition.y);
Remember that middle is a Joint, and here you see that from the frame data, the palmPosition Y value is being passed to the joint move function. What happens to the value passed into middle.move?
var _move = function(pos, constraint) {
var angle;
if (constraint) {
pos = constraint(pos);
}
angle = _scale(pos);
_servo.move(angle);
};
You can see that without a second argument, the call to move basically just calls scale(pos)
and stores the value.
Let's see what scale does:
var _scale = function(pos) {
if (pos<minPos) {
pos = minPos;
}
else if (pos>maxPos) {
pos = maxPos;
}
return Math.floor(five.Fn.map(pos, minPos, maxPos, _servo.range[0], _servo.range[1]));
};
This function clamps the position passed in to the minPos and maxPos values that were defined when constructing the joint. It then interpolates the value across the min/max servo range.
The code you sent me is definitely using pointables and not fingers. Every frame, the leap device returns everything it saw:
You can use the direction vector of the pointables to determine how much they are bent (http://leapmotion.github.io/leapjs/Leap.Pointable.html). For instance you might want to take the cross product of the direction vector with a vector pointing straight down and see how close to zero the magnitude is (zero means the vectors are parallel).
_isValid is called every time app.js calls
frame = new LeapFrame(data);
, and changing it to frame.hand won't do what you want. Frame is this (http://leapmotion.github.io/leapjs/Leap.Frame.html#Frame) look at the data structures in there and you'll see where frame.pointables and frame.hands come from.Unfortunately the code you sent only tracks a single pointable. You'd need to make some changes to track more than a single pointable. Also, if you want to map a specific finger to a specific control then you will probably need some type of calibration phase where you can identify a single finger at a time and store the ID of that finger...
Otherwise you might have 5 fingers on screen, then you might lose site of 1 finger and your finger enumerations will change. So what you thought was the pinky may now be in index 3 instead of index 4.