Overview of the IK Solution and Gait Engine
NUKE generates a full inverse kinematics solution and a gait engine for your robot. However, you may want to tune it by hand. Before you can tune a system though, you will need to know how it works.
NUKE exports 4 files:
- nuke.h - header file for IK and gait engine
- nuke.cpp - contains the IK engine
- gaits.h - contains the gait engine
- something.pde - your sketch, this is where you will put the robot's task-related code.
The main loop of your program, in something.pde will look like this
void loop(){
// put your task code here
// make sure it doesn't take too long to execute each cycle
if(bioloid.interpolating == 0){
// last step is done, do the next
doIK();
bioloid.interpolateSetup(tranTime);
}
bioloid.interpolateStep();
Your code will interact with the gait engine using several global variables, which can be set at any time, from anywhere in your code:
- Xspeed - the forward speed to walk at, in millimeters/second. Forward is positive.
- Yspeed - the sideways speed to walk at, in millimeters/second. Right is positive.
- Rspeed - the speed to turn at, in radians/second.
The body IK engine also relies on several other variables:
- bodyPosX, bodyPosY - offset of the center of body in the air, in millimeters.
- bodyRotX, bodyRotY, bodyRotZ - rotation of body about axis, in radians.
The most important function is clearly doIK() which ties everything from NUKE together. doIK() generates the IK solution for each leg's servos, taking into account the default positions (created in setupIK()), gait requests, and the bodyIK parameters such as body yaw or pitch. You should not need to alter the doIK(), bodyIK() or legIK(). Most of the optimization that end users can do is in setupIK() and the gait generators.
Basic Gaits
Basic gaits are cyclic. We can see that as a robot moves forward, it moves it's legs in some cyclic order. NUKE uses a gait generator function to create these movements. By passing in the leg ID and the step variable, the gait generator creates a set of offsets (X,Y,Z,rotation about Z) for the given leg at that step. The step variable counts from 0 to the number of steps in the currently selected gait -- this number is known as the stepsInCycle. For each cycle, every leg will move the desired distance (which is controlled by the speed variables).
A basic gait generator looks like this:
ik_req_t DefaultGaitGen(int leg){
// TODO: add code here!!!!
}
By default, NUKE generates continuous gaits. Continuous gaits are such that the body moves in the desired direction at a continuous rate. A discontinuous gait is one that moves the body only when all feet are on the ground. When a gait is not stable enough, especially over terrain, creating a discontinuous gait may be of help.
Included Gaits
A number of gaits are included, which can be selected using the SelectGait() function: (NOTE: SOME GAITS NOT YET IN BETA)
- Ripple gaits move only one leg at a time:
- RIPPLE - the simplest, default gait. 8 steps per cycle (12 for a hexapod). Each leg is raised, and lowered, in order.
- SMOOTH_RIPPLE - similar but with as twice as many steps as a RIPPLE. Makes better foot paths.
- FAST_RIPPLE - 4 steps per cycle, 6 for a hexapod. As a leg lowers, another is already rising. Can be faster than RIPPLE, but may be very jerky or unsteady.
- Amble gaits move two alternate legs at a time:
- AMBLE - 4 steps per cycle, each pair of legs is raised and moved forward in one step, then dropped in the next step.
- SMOOTH_AMBLE - similar to an AMBLE, but with twice as many steps per cycle.
- Tripod gaits move three legs at a time (For hexapods only):
- TRIPOD - 4 steps per cycle, like an AMBLE, but using 3 legs in a group.
- Geometric gaits are the most stable for quadrupeds, but may be slower (For quadrupeds only):
- RIPPLE_GEO - a geometrically confined ripple, 8 steps per cycle. (Not included in PyPose/NUKE V1.1)
Default Stance, Length of Stride as an Optimization Factor
NUKE computes the Configuration Space of your robot's legs. The configuration space is the region of space where the legs can actually touch without any servo going out of range. From this, it can find what the default stance should be in order to maximize stride.
For most quadrupeds and hexapods, this is a good starting place. However, you may find yourself wanting to tune the default stance. This can be done by editing the setupIK() function. setupIK sets the position of the servos when the robot first starts up, and this position is what we add gait requests and body rotation requests to when we compute the final leg positions at each step in our cycle.
Future versions of NUKE may also allow optimizations for maximal stability rather than stride length, however, at this point you would have to hand optimize for this, a first step would be the use of a Geometrically Stable gait.
Geometric Stability
This section describes a feature available only in NUKE V1.2 and above.
NUKE can generate a geometrically stable gait, that is, the Center-of-Gravity of the robot is always within the Support Polygon created by the feet that remain on the ground.
The Stability Margin is the shortest length from the COG to the support polygon as projected along the direction of gravity. What the heck does that mean? On an incline, your stability margin is less than on flat ground. Frequently, the stability margin may be difficult or impossible to determine, and so approximations are often used.
TODO: add images of stability margin/etc
Creating New Gait Generators
There are two steps to creating a new gait. First, you must create a new gait generator and possibly a new gait setup, and then add the gait to the SelectGait function.
TODO: add discussion of creating Gait Generators and Setup functions, the use of tranTime, etc
After creating your new gait, you need to add the ability to select the gait. To add a new gait to your SelectGait function, you will typically add to the end of the long set of if/else statements:
...
}else if(GaitType == MY_NEW_GAIT){
gaitSetup = &MyGaitSetup;
gaitGen = &MyGaitGenerator;
gaitLegNo[RIGHT_FRONT] = 0;
gaitLegNo[LEFT_FRONT] = 2;
gaitLegNo[RIGHT_REAR] = 4;
gaitLegNo[LEFT_REAR] = 6;
pushSteps = 6;
stepsInCycle = 8;
}
Your code must define:
- stepsInCycle - the number of steps in a complete cycle
- pushSteps - the number of steps in a cycle where the leg is on the ground, and thus pushing in the desired direction. From a theoretical standpoint, the duty factor of each leg (time on the ground) = pushSteps/stepsInCycle.
- gaitLegNo - defines the order in which legs are moved. How this is used depends on the gait generator and gait setup functions selected.
- gaitSetup - the gait setup function to call at the beginning of each cycle. DefaultGaitSetup is a default, and empty, gait setup function.
- gaitGen - the gait generator to call for each leg. DefaultGaitGen is a default gait generator, which all non-geometric built-in gaits are currently using.
Optionally, you may also define:
- tranTime- the time, in milliseconds, taken to do the interpolation from one position to the next. In a steady-period gait, the time taken for a cycle is simply tranTime*stepsInCycle.
- cycleTime - the time, in seconds, taken to complete a cycle. Will normally be set to (stepsInCycle*tranTime)/1000.0. However, if you are changing tranTime inside your custom gait generator, you need to set cycleTime explicitly!
Other Hacking
TODO: add what values mean, out of range issues, etc
Under development in V2.0/SVN-LATEST is a new gait file format. Gait files (.gait) contain the following:
REQUIRES: leg 4 6
REQUIRES: ik lizard3 mammal3
GAIT:MY_GAIT_NAME
gaitGen = &NewGaitGen;
gaitSetup = &DefaultGaitSetup;
gaitLegNo[RIGHT_FRONT] = 0;
gaitLegNo[LEFT_MIDDLE] = 0;
gaitLegNo[RIGHT_REAR] = 0;
gaitLegNo[LEFT_REAR] = 2;
gaitLegNo[LEFT_FRONT] = 2;
gaitLegNo[RIGHT_REAR] = 2;
pushSteps = 2;
stepsInCycle = 4;
GENERATOR: NewGaitGen, This is a new gait generator
if( MOVING ){
...
}
SETUP: NewGaitSetup, This is a new setup function
...
GLOBAL: variableIneed
The first line is a requirements statement, that this gait is only for 4 or 6 legged robots. The second line is an additional statement that this gait is only to be used for the mammal3 or lizard3 IK specifications.
Where MY_GAIT_NAME would be something like AMBLE_SMOOTH. This is followed by the actual gait generation code. We then have defined a GENERATOR, which has a name, and a description (which will be used as a comment), followed by the body of the function.
This file format will be used to generate the gaits.h file automatically.