I've been gone for a couple of days working on getting computers set up for a couple of people. THis project is getting to the point where it is difficult which is anoter reason that I have been lax on returning to it.
To rehash what I have done to this point: in the learning of the java 3d api I have learned the basics of how a scene graph is constructed and how transformation matrices operate. I have explored the operation of the work that Andy has done and I understand what the joints are in the robot and how they operate. In robotics in general I have researched puma's and have a pretty good idea of what they look like, how they move and what they are good for. Also, I have a opretty good grasp on how intrpolators work and how to use behaviors in general. Also, I have been working with another puma simulator in java 3d and have gotten it so that it will compile though it still will not load completely. Also, I have found out some about 3d modeling and the importing of geometry in java 3d. All of this is, of course, a much simplified version of my work. If you would like to see it in toto, go to the beginning.
Where does this leave for me to go? I hope to get the other robot simulator working, or at least check the geometry that it loads (it uses non-native geometry unlike this project) and see if that is a better way to go. I hope to get the robot to animate, thought this means working through Andy's source code which I am still not quite up to. Also, the parser still needs work, but I am not going to pick up any new things to think about right now.
To understand Andy's work I first need to understand the creation of geometry in java 3d. To this end I am working throught the second chapter of the tutorial. It begins with a basic explanation of objects known as geometric primitives which are subclasses of com.sun.j3d.Group. Apparently ColorCube is a special and unusual object in java 3d in that the user doesn't have to worry about the creation of lights and things. Usually this is an issue and their example for this is a yo-yo formed from two cones. Here is it's code:
import com.sun.j3d.utils.geometry.*; import javax.media.j3d.*; import javax.vecmath.*; /** * ConeYoYo.java from the java 3d tutorial. */ public class ConeYoYo { private BranchGroup yoyoGroup; public ConeYoYo() { yoyoGroup = new BranchGroup(); Transform3D rotationTransform = new Transform3D(); Transform3D translationTransform = new Transform3D(); Appearance appearance = new Appearance(); rotationTransform.rotZ(Math.toRadians(90)); TransformGroup rotateGroupOne = new TransformGroup(rotationTransform); translationTransform.set(new Vector3f((float).1, (float)0, (float)0)); TransformGroup translateGroupOne = new TransformGroup(translationTransform); Cone coneOne = new Cone((float).6, (float).2); coneOne.setAppearance(appearance); yoyoGroup.addChild(rotateGroupOne); rotateGroupOne.addChild(translateGroupOne); translateGroupOne.addChild(coneOne); rotationTransform.rotZ(Math.toRadians(-90)); TransformGroup rotateGroupTwo = new TransformGroup(rotationTransform); translationTransform.set(new Vector3f((float)-.1, (float)0, (float)0)); TransformGroup translateGroupTwo = new TransformGroup(translationTransform); Cone coneTwo = new Cone((float).6, (float).2); coneTwo.setAppearance(appearance); yoyoGroup.addChild(rotateGroupTwo); rotateGroupTwo.addChild(translateGroupTwo); translateGroupTwo.addChild(coneTwo); yoyoGroup.compile(); } public BranchGroup getBranchGroup() { return yoyoGroup; } }this code is not in the tutorial, but I think that it will work for the createSceneGraph() function:
private BranchGroup createSceneGraph() { ConeYoYo yoyo = new ConeYoYo(); return yoyo.getBranchGroup(); }This can be used in the generic driver that I presented before. I'll do it again so you don't have to hunt for it:
import java.awt.*; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.geometry.*; import javax.media.j3d.*; import javax.vecmath.*; public class TestApplet extends java.applet.Applet { public TestApplet() { Canvas3D drawingCanvas = new Canvas3D(null); setLayout(new BorderLayout()); add("Center", drawingCanvas); BranchGroup cubeScene = createSceneGraph(); cubeScene.compile(); SimpleUniverse simpleUniverse = new SimpleUniverse(drawingCanvas); simpleUniverse.getViewingPlatform().setNominalViewingTransform(); simpleUniverse.addBranchGraph(cubeScene); } private BranchGroup createSceneGraph() { } public static void main(String[] args) { new MainFrame(new TestApplet(), 256, 256); } }Just replace the createSceneGraph() function with whatever scene graph you are testing out and it ought to display... It does and the results look like this:
import com.sun.j3d.utils.geometry.*; import javax.media.j3d.*; import javax.vecmath.*; /** * ConeYoYo.java from the java 3d tutorial. */ public class ConeYoYo extends javax.media.j3d.BranchGroup { public ConeYoYo() { Transform3D rotationTransform = new Transform3D(); Transform3D translationTransform = new Transform3D(); Appearance appearance = new Appearance(); rotationTransform.rotZ(Math.toRadians(90)); TransformGroup rotateGroupOne = new TransformGroup(rotationTransform); translationTransform.set(new Vector3f((float).1, (float)0, (float)0)); TransformGroup translateGroupOne = new TransformGroup(translationTransform); Cone coneOne = new Cone((float).6, (float).2); coneOne.setAppearance(appearance); addChild(rotateGroupOne); rotateGroupOne.addChild(translateGroupOne); translateGroupOne.addChild(coneOne); rotationTransform.rotZ(Math.toRadians(-90)); TransformGroup rotateGroupTwo = new TransformGroup(rotationTransform); translationTransform.set(new Vector3f((float)-.1, (float)0, (float)0)); TransformGroup translateGroupTwo = new TransformGroup(translationTransform); Cone coneTwo = new Cone((float).6, (float).2); coneTwo.setAppearance(appearance); addChild(rotateGroupTwo); rotateGroupTwo.addChild(translateGroupTwo); translateGroupTwo.addChild(coneTwo); compile(); } }And then you could just stick the yoyo straigh into the scene graph or the createSceneGraph function would look like this:
private BranchGroup createSceneGraph() { return new ConeYoYo(); }Also, in order to get a better picture of the yoyo I think that adding a rotation interpolator ahead of the yoyo in the scene graph ought to set it spinning. Let me see, the only possibility is that the transformations will screw up how it spins. Actually if I am right the ConeYoYo object is a bit misnamed becasue it is not really a ConeYoYo but really a scene containing a yoyo. The yoyo ought to be at (0, 0, 0) by default IMHO. Let me check though and make sure that it doesn't rotate right.
private BranchGroup createSceneGraph() { BranchGroup root = new BranchGroup(); TransformGroup rotateGroup = new TransformGroup(); rotateGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Alpha alpha = new Alpha(-1, 4500); RotationInterpolator rotatorBehavior = new RotationInterpolator(alpha, rotateGroup); rotatorBehavior.setSchedulingBounds(new BoundingSphere()); root.addChild(rotateGroup); rotateGroup.addChild(new ConeYoYo()); rotateGroup.addChild(rotatorBehavior); return root; }This one works because it is rotating along the y-axis where there hasn't been and translation. Let me try rotating it along the x-axis where where has been a .1 unit transformation.
private BranchGroup createSceneGraph() { BranchGroup root = new BranchGroup(); TransformGroup rotateGroup = new TransformGroup(); rotateGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); Alpha alpha = new Alpha(-1, 4500); Transform3D xAxis = new Transform3D(); xAxis.rotZ(Math.toRadians(90)); RotationInterpolator rotatorBehavior = new RotationInterpolator( alpha, rotateGroup, xAxis, (float)Math.toRadians(0), (float)Math.toRadians(360)); rotatorBehavior.setSchedulingBounds(new BoundingSphere()); root.addChild(rotateGroup); rotateGroup.addChild(new ConeYoYo()); rotateGroup.addChild(rotatorBehavior); return root; }And it is messed up a bit. If you were rotating a yoyo through its x-axis you would expect it to just spin in place. This yoyo moves in a circle as it spins. If I were able to show you I would, but my best attempts at getting the plug-in with j3d suport to work have been unsuccessful. It works for the regualr java 2 stuff, but the 3d won't intialize. Regardless, my point with the yoyo is that it is y shifted and I think that it ought not to be that way. I am going to revise it to fix it. It's too squatty too. I think it ought to look like this:
Arrg... *thump**thump**thump* Nevermind all of that last little bit. Yes the yoyo is not centered on the its axis, but it is not centered because when a new cone is created it is created with its base parallell to the x-axis. Dammit. This is not what I was thinnking; h / 2 is +y and h / 2 is -y so spinning it 90° along z = 0 ought to put it with h / 2 at +x and h / 2 at -x why then does it not work right?
Why? Becasue I was careless. Just after I went on about it the importance of order in translations and rotations I don't pay attention to the order in the example, so what happened was the reason for both of the problems of the misaligned axis and the squattiness was me. Becasue I switched the order from rotate 90°, translate .1 to translate .1, rotate 90° the two cones were put a total of .2 closer together and moved up .1. So here is the fixed code and the fixed picture:
import com.sun.j3d.utils.geometry.*; import javax.media.j3d.*; import javax.vecmath.*; /** * ConeYoYo.java from the java 3d tutorial. */ public class ConeYoYo extends javax.media.j3d.BranchGroup { public ConeYoYo() { Transform3D rotationTransform = new Transform3D(); Transform3D translationTransform = new Transform3D(); Appearance appearance = new Appearance(); rotationTransform.rotZ(Math.toRadians(90)); TransformGroup rotateGroupOne = new TransformGroup(rotationTransform); translationTransform.set(new Vector3f((float).1, (float)0, (float)0)); TransformGroup translateGroupOne = new TransformGroup(translationTransform); Cone coneOne = new Cone((float).6, (float).2); coneOne.setAppearance(appearance); addChild(translateGroupOne); translateGroupOne.addChild(rotateGroupOne); rotateGroupOne.addChild(coneOne); rotationTransform.rotZ(Math.toRadians(-90)); TransformGroup rotateGroupTwo = new TransformGroup(rotationTransform); translationTransform.set(new Vector3f((float)-.1, (float)0, (float)0)); TransformGroup translateGroupTwo = new TransformGroup(translationTransform); Cone coneTwo = new Cone((float).6, (float).2); coneTwo.setAppearance(appearance); addChild(translateGroupTwo); translateGroupTwo.addChild(rotateGroupTwo); rotateGroupTwo.addChild(coneTwo); compile(); } }
I am going to go to another lab where I can print out Andy's source and hopefully get it fixed up tomorrow. My supervisor is wanting to meet with me and at this point all that I have done is lots of learning. Which is nice and all, but not very pragmatic.
I am in the process of mangling Andy's code now, but I think that the best way for me to make progress at tis point is to do that rather than try to wait until I understand more. Some notes as I go:
Each joint has a transformation matrix associated with it. It is a pretty complex matrix and I am wondering if this is just a robotics thing or if it is somehow related to my transformation matrix. Here is the matrix:
t = the angle being roatated by a = a value that he looked up somewhere l = a looked up value d = another value that he looked up somewhere cos t -(cos a * sin t) sin a * sin t a * cos t sin t cos a * cos t sin a * cos t a * sin t 0 sin a cos a d 0 0 0 1I have no idea why this needs to be that complex, certainly I don't understand why table lookups are necessary. It seems to me that I could just use graphics transforms to produce the right picture. I am going to see if that is possible.
Ok, it's 9:45 now and I have a pretty good sketch working except for one thing; I need to override a final method; ick. I'll work on it more tomorrow. I've had enough java for the night.
Ok, I have been working for the last little bit, though much slower since I am not compiling over the network, and I think I have a rough outline for how I think this project ought to be laid out. It is a bit more class based than what Andy had and I am still not sure if it will work.
A robot consists of a number of links and a number of joints, also at one end there is a base and at the other end there is an end effector, in this case a claw. My primary concerns at this point are the links and the joints. Each one can be considered essentially a straight object which then connects at a certain angle to another object. In this robot for instance, the herarchy is:
Ok, I think that I have a working construct of how to lay out this project design. There will be a set of constituent extensions of branch group.
I have a basic program written using this layout right now and it really does alot to clean up the code; here is the entirety of my robot consrtuction minus the claw which I didn't want to add yet:
/* Create the joints */ joint[0] = new Joint(0, 360); joint[1] = new Joint(30, 270); joint[2] = new Joint(30, 270); joint[3] = new Joint(30, 280); joint[4] = new Joint(30, 200); joint[5] = new Joint(30, 532); /* Create the bars; this bit I am just making up. */ bar[0] = new Bar((float).1, (float).7, barColor); bar[1] = new Bar((float).1, (float).7, barColor); bar[2] = new Bar((float).1, (float).7, clawColor); /* Create the other bits */ base = new Base(baseColor); /* Then build the robot */ addChild(base); base.addChild(joint[0]); joint[0].addToEnd(bar[0]); bar[0].addToEnd(joint[1]); joint[1].addToEnd(bar[1]); bar[1].addToEnd(joint[2]); joint[2].addToEnd(joint[3]); joint[3].addToEnd(bar[2]); bar[2].addToEnd(joint[4]); joint[4].addToEnd(joint[5]);
Right what this produces is really crappy. It does produce a scene graph, but it is just a cylinder, well 3 cylinders stacked on top of each other with varying sizes. This is becasue my development of the link and joint classes is not done.
Actually joint is just about done. It will be done once I confirm a suspicion about how a joint operates in robotics. What I am thinking is that a joint is just a motor which rotates so as to change the orientation of one part in relation to another. If this is true then any joint can be represented as operating in two-space; essentially that it rotates in a plane around an axis. If this is true then I will make it so that a joint it sdefined simply as a rotation around the y-axis with its counter-clockwise most position at 0° x.
You may notice the constructor for Joint in the exapmple above. It is Joint(int initRotate, int bound) the first number is an initial offset from the 0 point and the second specifies how far it may rotate in the clockwise direction. Another thing that will be helpful about this design is that the necessary behavior can be encapsulated in the joint so I don't have to screw with it.
The code that is going to be a bit more difficult to develop is the Link code (above the class is called Bar but I am renaming it.) What the Link cade will have to do is create a branch graph which has at its orign the docking point in the piece of the robot where the preceeding part (be it base, joint or claw) connects and has as its end the docking point where the postceeding part connects. Also these docking points will have to be rotated so that when a joint is attached it is connected with the 0 position correctly set.
Really this ought not to be all that hard. My little test bit for the Links is a simple cylinder with the preceeding part attaching in the middle of the bottom and the postceeding part attaching in the middle of the top. This is why when I run my test program it makes a stack of cylinders. Setting offsets and stuff shouldn't be that hard.
What I hope to do soon though is change link to an abstract superclass and then use the object loader to import realistic bits of geometry to make the robot look better. What I am going to do fisrt though is make a couple of different types of links and see if I can get a rough representation of the robot that Andy made.
I have a bit of mail out to Andy asking if he knows good places to find out real informtion about stuff like the dimentions on these parts or the mounting orientations. Hopefully finding that stuff out won't prove to be too big a problem to overcome.