Friday, May 18, 2012

Mech: Legs designed in 3D

I had to work a few more bugs out of the location computing and rendering systems. I think the image is still flipped but I'll deal with that later.

For now, I have the legs and hip sections modeled. Not just their current location, but even their kinematics are modeled in this rendering system: If I adjust the actuators the entire structure will move and react. And all in about 70 lines of code, including constants and comments.

#Leg attributes

actThighInit = 1.0

actCalfInit = 1.0

actHipDis = 1.0

actThighDis = 1.0

actKneeDis = 1.0

actCalfDis = 1.0

thighLen = 5.0

calfLen = 5.0

legBoneDis = 2.0

hipWidth = 8.0


leftLegDispProp = displayProperties([100,100,255],2)

rightLegDispProp = leftLegDispProp

actDispProp = displayProperties([255,255,100],4)

hipDispProp = displayProperties([255,100,100],2)

leftHipBack = location(0,0,0)

leftHipActuator = location(actHipDis,0,0)

self.struct = structureSeed(leftHipBack,leftHipActuator)

s = self.struct


leftThighActuator = s.addJoint(leftHipBack,actThighDis,leftHipActuator,actThighInit,location(0,1,0),'f',dispPropA=leftLegDispProp,dispPropB=actDispProp)

leftKneeBack = s.addJoint(leftHipBack,thighLen,leftThighActuator,dispPropA=leftLegDispProp)

leftHipFront = s.addJoint(leftHipActuator,legBoneDis+actHipDis,leftHipBack,dispPropA=leftLegDispProp)

leftKneeFront = s.addJoint(leftHipFront,thighLen,leftKneeBack,legBoneDis,leftHipBack,'f',dispProp=leftLegDispProp)

leftKneeBrace = s.addJoint(leftKneeBack,math.sqrt(1.0+legBoneDis*legBoneDis),leftKneeFront,1.0,leftHipBack,'n',dispProp=leftLegDispProp)

leftKneeActuator = s.addJoint(leftKneeBrace,math.sqrt(1.0+actKneeDis*actKneeDis),leftKneeFront,actKneeDis,leftKneeBack,'f',dispProp=leftLegDispProp)

leftCalfActuator = s.addJoint(leftKneeActuator,actCalfInit,leftKneeFront,actCalfDis,leftKneeBrace,'f',dispPropA=actDispProp,dispPropB=leftLegDispProp)

leftAnkleFront = s.addJoint(leftKneeFront,calfLen,leftCalfActuator,dispProp=leftLegDispProp)

leftAnkleBack = s.addJoint(leftAnkleFront,legBoneDis,leftKneeBack,calfLen,leftKneeActuator,'f',dispProp=leftLegDispProp)


legHipSupportLen = 1.0

legHipWingLen = 0.5

hipPostLowerPoint = 0.1

hipPostUpperPoint = 1.0

hipCockpitDis = 1.0

cockpitWidth = 6.0

actHipInit = sqrt(sq(hipCockpitDis)+sq(actHipDis))

# Main leg supports

leftHipSupportBack = s.addJoint(leftHipBack,legHipSupportLen,leftHipActuator, sqrt( sq(legHipSupportLen) + sq(actHipDis)),leftThighActuator, sqrt(sq(actThighDis)+sq(legHipSupportLen)),dispProp=leftLegDispProp)

leftSupportAttachFront = s.addJoint(leftHipFront,actThighDis,leftKneeFront,dispProp=leftLegDispProp)

leftHipSupportFront = s.addJoint(leftHipFront,legHipSupportLen,leftHipBack, sqrt(sq(legBoneDis)+sq(legHipSupportLen)),leftSupportAttachFront, sqrt(sq(actThighDis)+sq(legHipSupportLen)),dispProp=leftLegDispProp)

# Hip post

leftHipWingBack = s.addJoint(leftThighActuator,sqrt(sq(actThighDis)+sq(legHipWingLen)),leftHipBack,legHipWingLen,leftHipFront,sqrt(sq(legBoneDis)+sq(legHipWingLen)),dispProp=leftLegDispProp)

leftHipPostUpper = s.addJoint(leftHipBack,hipPostUpperPoint,leftHipFront,sqrt(sq(legBoneDis)+sq(hipPostUpperPoint)),leftHipWingBack,sqrt(sq(legHipWingLen)+sq(hipPostUpperPoint)),dispProp=leftLegDispProp)

leftHipActuatorPost = s.addJoint(leftHipBack,sqrt(sq(hipPostUpperPoint)+sq(actHipDis)),leftHipActuator,hipPostUpperPoint,leftHipPostUpper,actHipDis,dispProp=leftLegDispProp)

# Hip center

leftHipCockpitUpper = s.addJoint(leftHipPostUpper,hipCockpitDis,leftHipActuatorPost,actHipInit,leftHipBack,sqrt(sq(hipCockpitDis)+sq(hipPostUpperPoint)),dispPropA=actDispProp,dispPropB=hipDispProp,dispPropC=hipDispProp)

leftHipCockpitLower = s.addJoint(leftHipCockpitUpper,hipPostUpperPoint,leftHipBack,hipCockpitDis,leftHipPostUpper,sqrt(sq(hipCockpitDis)+sq(hipPostUpperPoint)),dispProp=hipDispProp)

rightHipCockpitUpper = s.addJoint(leftHipPostUpper,cockpitWidth+hipCockpitDis,leftHipCockpitUpper,dispProp=hipDispProp)

rightHipCockpitLower = s.addJoint(leftHipBack,cockpitWidth+hipCockpitDis, leftHipCockpitLower,dispProp=hipDispProp)

rightHipPostUpper = s.addJoint(rightHipCockpitUpper,hipCockpitDis,rightHipCockpitLower,sqrt(sq(hipCockpitDis)+sq(hipPostUpperPoint)),leftHipCockpitLower,'f',dispProp=hipDispProp)

rightHipBack = s.addJoint(rightHipCockpitLower,hipCockpitDis,rightHipCockpitUpper,sqrt(sq(hipCockpitDis)+sq(hipPostUpperPoint)),leftHipCockpitUpper,'f',dispProp=hipDispProp)

# Hip post

rightHipActuatorPost = s.addJoint(rightHipBack,sqrt(sq(actHipDis)+sq(hipPostUpperPoint)),rightHipPostUpper,actHipDis,rightHipCockpitUpper,actHipInit,dispPropA=rightLegDispProp,dispPropB=rightLegDispProp,dispPropC=actDispProp)

rightHipActuator = s.addJoint(rightHipActuatorPost,hipPostUpperPoint,rightHipBack,actHipDis,rightHipPostUpper,sqrt(sq(hipPostUpperPoint)+sq(actHipDis)),dispProp=rightLegDispProp)


rightHipWingBack = s.addJoint(rightHipPostUpper,sqrt(sq(hipPostUpperPoint)+sq(legHipWingLen)),rightHipActuator,sqrt(sq(legHipWingLen)+sq(actHipDis)),rightHipBack,legHipWingLen,dispProp=rightLegDispProp)

rightThighActuator = s.addJoint(rightHipActuator,actThighInit,rightHipBack,actThighDis,rightHipWingBack,sqrt(sq(legHipWingLen)+sq(actThighDis)),dispPropB=rightLegDispProp,dispPropA=actDispProp,dispPropC=rightLegDispProp)

rightKneeBack = s.addJoint(rightHipBack,thighLen,rightThighActuator,dispPropA=rightLegDispProp)

rightHipFront = s.addJoint(rightHipActuator,legBoneDis+actHipDis,rightHipBack,dispPropA=rightLegDispProp)

rightKneeFront = s.addJoint(rightHipFront,thighLen,rightKneeBack,legBoneDis,rightHipBack,'f',dispProp=rightLegDispProp)

rightKneeBrace = s.addJoint(rightKneeBack,math.sqrt(1.0+legBoneDis*legBoneDis),rightKneeFront,1.0,rightHipBack,'n',dispProp=rightLegDispProp)

rightKneeActuator = s.addJoint(rightKneeBrace,math.sqrt(1.0+actKneeDis*actKneeDis),rightKneeFront,actKneeDis,rightKneeBack,'f',dispProp=rightLegDispProp)

rightCalfActuator = s.addJoint(rightKneeActuator,actCalfInit,rightKneeFront,actCalfDis,rightKneeBrace,'f',dispPropA=actDispProp,dispPropB=rightLegDispProp)

rightAnkleFront = s.addJoint(rightKneeFront,calfLen,rightCalfActuator,dispProp=rightLegDispProp)

rightAnkleBack = s.addJoint(rightAnkleFront,legBoneDis,rightKneeBack,calfLen,rightKneeActuator,'f',dispProp=rightLegDispProp)

rightSupportAttachFront = s.addJoint(rightHipFront,actThighDis,rightKneeFront,dispProp=rightLegDispProp)

rightHipSupportFront = s.addJoint(rightHipBack,sqrt(sq(legBoneDis)+sq(legHipSupportLen)),rightHipFront,legHipSupportLen,rightSupportAttachFront,sqrt(sq(actThighDis)+sq(legHipSupportLen)),dispProp=rightLegDispProp)

rightHipSupportBack = s.addJoint(rightHipActuator,sqrt(sq(actHipDis)+sq(legHipSupportLen)),rightHipBack,legHipSupportLen,rightThighActuator,sqrt(sq(actThighDis)+sq(legHipSupportLen)),dispProp=rightLegDispProp)

Friday, May 11, 2012

Mech: The 3D rendering and image export works

I've got the new 3-d rendering system online, rendering, and exporting images. The image shown here was built using the code below

The first three lines of this code are the basic bootstrapping. We put two locations in space. We build out structure seed from that. I then define a display property to be able to highlight one of the spans. Then, the first two 'add joint' commands are using the 2D building ability. When building an object from only two points, I have to make up a third one in order to define what plane the new point should be in. I also need to say 'far' or 'near' relative to the made-up point that defines the plane since there are usually two possible solution points. The last 'add joint' is a regular 3D joint, made from three of the other joints.

You might notice that we constructed this pyramid without all of the pieces. In designing machines, this will actually be a valuable feature since it prevents you from making machines that *can* bind. This way, you must make models that are minimally determined and thus maximally able to move when their joints move.

nearL = location(0,0,0)

nearR = location(1,0,0)

s = structureSeed(nearL,nearR)

highlightDisProp = displayProperties([100,100,255],7)

farL = s.addJoint(nearL,1,nearR,math.sqrt(2),location(0,0,1),'f')

farR = s.addJoint(nearL,math.sqrt(2),nearR,1,location(0,0,1),'f')

top = s.addJoint(nearL,1,nearR,1,farL,1,dispPropA=highlightDisProp)

Lastly, I've uploaded the code for this. It requires both pygame and imagemagick (just to apt-get installs on them). Run the command 'python' to make it do it's thing.

Monday, May 7, 2012

Mech: Building the 3D simulator

I needed a 3D simulator. There are lots of programs that let you draw objects and place them. I didn't see offhand any that have the simulator compute the locations of things based on their distances from other things. And it would have taken me a while to find the right one with the right APIs so I just didn't.

Instead I'm making a 3D simulator. Like the 2D version I already made it computes locations based on relative distances from other locations. I've added compatibility with 2D as well as lines for convenience.

Today, I got it computing locations even for the complex 3D cases. The interesting part of this was doing a bunch of rotations until the points were in a plane where I could compute the solutions to them.

I solve the problem in two major parts. Each part is essentially solving for the intersection of two points. So let's say I have joints A,B,C and distance dA,dB,dC from the new joint D that we're going to place. I start with joint A and joint B. I solve for where D is relative to them. But in a 3D world that's actually a circle. Based on the location of C and dC I can find a specific point on the circle D. Below are the exact steps:

  • STEP 0: Copy initial points so they never drift with repeated transformations
  • STEP 1: Translate to make point 1 the origin
  • STEP 2: Rotate around Y axis till point 2 lies in Z=0 plane
  • STEP 3: Rotate around Z axis till point 2 lies in Y=0 plane (now must be on the X-axis)
  • STEP 4: Solve for point 4(new point)'s to find the X and Y. The X here will end up being the real X in this space. The Y is simply the radius.
  • STEP 5: The problem now starts over, remaking a new point A and B based on the X,Y we solved and point 3
  • STEP 6: Translate to make point newA's X=0
  • STEP 7: Rotate around Y axis 90 degrees to make the solution circle lie at Z=0
  • STEP 8: Rotate around Z axis till point newB lies on the Y=0 plane (it now must be on the X-axis)
  • STEP 9: Solve for point 4(new point)'s to find the new X and Y locations. The transformations we've already done will fill out all the other data found along the way.
  • STEP 10: Build the solution
  • STEP 11: Back out all transformations

If you spend a few minutes thinking about this, you'll notice that the points and distances is not enough to determine an exact point. It determines one of two points. As with the 2D system, I'm solving this by using the right hand rule. If you list the points clockwise from your perspective, whatever perspective you choose, the plane those points in will be between you and the new point. Take a sec to think about it.

To give an example test case I run:

#Test case: 3D joint

j = joint()

j.jointA = location(1.0,0,0)

j.jointB = location(0.0,1.0,0.0)

j.jointC = location(0.0,0.0,1.0)

j.spanA = span(1.0)

j.spanB = span(math.sqrt(1+1+1))

j.spanC = span(1.0)


if(j.x > 1.01 or j.x < 0.99 or j.y > 0.01 or j.y < -0.01 or j.z > 1.01 or j.z < 0.99):

\t p = False

\t print "ERROR on test case 8: %s"%j.toString()

I've decided to call the new rendering and computing engine MindFuck3D. From this post, I hope you can begin to see why. Once I try to actually design in this new language I think it will really win it's name. It will be difficult to get good at but very quick and powerful once I have it down.