// // Inverse Kinematics // // Fred Chen & Loren Tsai // CS184 Fall 98 import vrml.*; import vrml.node.*; import vrml.field.*; import java.io.*; import java.util.*; public class arm2InvKin extends Script { // fields private SFNode Arm; private SFFloat UpperLength; private SFFloat LowerLength; // eventOuts private SFVec3f position_changed; private SFRotation Up; private SFRotation Side; private SFRotation Out; private SFRotation LowerArm; // internal variables private SFRotation init_up; private SFRotation init_side; private SFRotation init_out; private SFRotation init_arm; private boolean first_val = true; private float init_position[] = new float[3]; private float last_position[] = new float[3]; private float next_position[] = new float[3]; private float l1; private float l2; private float l3; private double alpha; private double beta; private double phi; private double uprange[] = new double[2]; private double siderange[] = new double[2]; private double outrange[] = new double[2]; private double armrange[] = new double[2]; private SFVec3f Path[]; private int steps = 20; private int iter = 0; private float x; private float y; private float z; // This method is called when the script is loaded public void initialize() { // Get handles to fields from the VRML environment Arm = (SFNode) getField("Arm"); UpperLength = (SFFloat) getField("UpperLength"); LowerLength = (SFFloat) getField("LowerLength"); // Get handles to eventOuts from the VRML environment position_changed = (SFVec3f) getEventOut("position_changed"); Up = (SFRotation) getEventOut("Up"); Side = (SFRotation) getEventOut("Side"); Out = (SFRotation) getEventOut("Out"); LowerArm = (SFRotation) getEventOut("LowerArm"); // Initialize internal variables init_up = (SFRotation) ((Node) Arm.getValue()).getExposedField("UpperarmUp"); init_side = (SFRotation) ((Node) Arm.getValue()).getExposedField("ShoulderSide"); init_out = (SFRotation) ((Node) Arm.getValue()).getExposedField("ShoulderOut"); init_arm = (SFRotation) ((Node) Arm.getValue()).getExposedField("LowerarmUp"); l1 = UpperLength.getValue(); l2 = LowerLength.getValue(); l3 = l1+l2; for(int i=0;i<3;i++) { init_position[i] = 0; } for(int i=0;i<2;i++) { if (i==0) { uprange[i] = -1.57; siderange[i] = -1.6; outrange[i] = 0; armrange[i] = 0; } else if (i==1) { uprange[i] = 2.3; siderange[i] = 0.1; outrange[i] = 1.57; armrange[i] = 2.6; } } // Initialize Path to walk /*Path = new SFVec3f[steps]; float temp[] = new float[3]; double angle = 2; double netHeight = 3; for(int i=0;i<steps;i++) { Path[i] = new SFVec3f(); if (i<steps/4) { temp[0] = 0; temp[1] = (float) (i*netHeight*4/steps); temp[2] = (float) (-(l1+l2)*Math.sin(4*angle*i/steps)); } else if (i< (3*steps/4)) { temp[0] = 0; temp[1] = (float) netHeight; temp[2] = (float) (4*i*(l1+l2)*Math.sin(angle)/steps); } else if (i<steps) { temp[0] =0; temp[1] = (float) netHeight*(1 - ((4*i-3*steps)/steps)); temp[2] = (float) (-(l1+l2)*Math.sin(4*angle*(1 - (4*i-3*steps)/steps))); } Path[i].setValue(temp); }*/ } //eventIns private void set_position(ConstSFVec3f newpos) { if(first_val == true) { newpos.getValue(init_position); newpos.getValue(last_position); first_val = false; } else { newpos.getValue(next_position); for(int i=0;i<3;i++) last_position[i] = last_position[i] + next_position[i]; x = next_position[0] - init_position[0]; y = next_position[1] - init_position[1]; z = next_position[2] - init_position[2]; x = 3*x/10; // scale factor of Hand object y = 4*y/10; z = 2*z/10; l3 = (float) Math.sqrt((l1+l2-y)*(l1+l2-y) + x*x); //l3 = (float) Math.sqrt(y*y + z*z); if ( (Math.abs(y) > l1+l2) ) { } else { beta = Math.acos((l3*l3 - l1*l1 - l2*l2)/(2*l1*l2)); alpha = Math.atan((z+l2*Math.sin(beta))/(l1+l2*Math.cos(beta))); //if (z < 0) //alpha = -alpha; position_changed.setValue(next_position); } } } private void set_upperarmup(ConstSFVec3f newpos) { float temp[] = new float[4]; if (alpha < uprange[0]) alpha = uprange[0]; else if (alpha > uprange[1]) alpha = uprange[1]; init_up.getValue(temp); temp[3] = (float) alpha; Up.setValue(temp); } private void set_shoulderout(ConstSFVec3f newpos) { l3 = (float) Math.sqrt(l1*l1 + l2*l2 + 2*l1*l2*Math.cos(beta)); } private void set_shoulderside(ConstSFVec3f newpos) { float temp[] = new float[4]; l3 = (float) Math.sqrt(l1*l1 + l2*l2 + 2*l1*l2*Math.cos(beta)); phi = Math.atan(x/(l1+l2-y)); if (phi < siderange[0]) phi = siderange[0]; else if (phi > siderange[1]) phi = siderange[1]; init_side.getValue(temp); temp[3] = (float) phi; Side.setValue(temp); } private void set_arm(ConstSFVec3f newpos) { float temp[] = new float[4]; //float x = next_position[0] - init_position[0]; //float y = next_position[1] - init_position[1]; //float z = next_position[2] - init_position[2]; //x = x/5; // scale factor of Foot object //y = y/5; //z = z/5; //beta = 3.14-Math.acos((y*y + z*z - l1*l1 - l2*l2)/(2*l1*l2)); if (beta < armrange[0]) beta = armrange[0]; else if (beta > armrange[1]) beta = armrange[1]; init_arm.getValue(temp); temp[3] = (float) beta; LowerArm.setValue(temp); } private void nextStep(float frac) { float temp[] = new float[3]; Path[iter].getValue(next_position); iter = iter+1; if (iter >= steps) iter = 0; position_changed.setValue(temp); } public void processEvent (Event e) { String EventName = e.getName(); if (EventName.equals("set_position")) set_position((ConstSFVec3f)e.getValue()); else if (EventName.equals("set_upperarmup")) set_upperarmup((ConstSFVec3f)e.getValue()); else if (EventName.equals("set_shoulderout")) set_shoulderout((ConstSFVec3f)e.getValue()); else if (EventName.equals("set_shoulderside")) set_shoulderside((ConstSFVec3f)e.getValue()); else if (EventName.equals("set_arm")) set_arm((ConstSFVec3f)e.getValue()); else if (EventName.equals("nextStep")) nextStep(((ConstSFFloat)e.getValue()).getValue()); } }