{"id":96,"date":"2013-06-19T18:53:52","date_gmt":"2013-06-19T22:53:52","guid":{"rendered":"http:\/\/projectsofdan.com\/?p=96"},"modified":"2013-07-13T15:39:03","modified_gmt":"2013-07-13T19:39:03","slug":"phase-3-body-kinematics-i-e-body-translationrotation-with-the-feet-planted","status":"publish","type":"post","link":"https:\/\/projectsofdan.com\/?p=96","title":{"rendered":"Phase 3: Body Kinematics, i.e., Body Translation\/Rotation with the Feet Planted"},"content":{"rendered":"<p>The next thing I wanted to accomplish was being able to translate and rotate the body while keeping the feet planted. For now this will simple enable the robot to wiggle around and &#8220;dance&#8221;, but eventually these movements will be necessary inputs for traversing uneven terrain.<\/p>\n<p>The concept for this is pretty straightforward. If i want the body to translate right while keeping the feet planted, you simply move all the feet to the left relative to the body:<\/p>\n<pre>newFootPositionX = initialFootPositionX - translateX\r\nnewFootPositionY = initialFootPositionY - translateY\r\nnewFootPositionZ = initialFootPositionZ - translateZ<\/pre>\n<p>I&#8217;m subtracting the translation because the feet are moving opposite the direction i want the body to go in. &#8216;translateY&#8217; could be an input from your controller. I using the Bioloid Commander library for easy access to the Commander controller inputs.<\/p>\n<p>Rotations aren&#8217;t quite as simple. The concept is to take an angular input, and provide the X,Y,Z offsets necessary for each leg to create that body rotation. A perfect job for the rotation matrix!<\/p>\n<div style=\"width: 196px\" class=\"wp-caption alignright\"><img loading=\"lazy\" decoding=\"async\" class=\" \" alt=\"\" src=\"http:\/\/upload.wikimedia.org\/math\/2\/8\/5\/2851c9dc2031127e6dacfb84b96446d8.png\" width=\"186\" height=\"228\" \/><p class=\"wp-caption-text\">Rotation Matrices<\/p><\/div>\n<p>Here is some good background info on\u00a0<a title=\"Rotation Matrix Wiki\" href=\"http:\/\/en.wikipedia.org\/wiki\/Rotation_matrix\" target=\"_blank\">rotation matrices<\/a>. Its not nearly as hard as it looks. You simply apply one rotation matrix per axis of rotation. I wanted to be able to rotate on all three axis so i strung all three together.<\/p>\n<pre>(X,Y,Z)rotated = (X,Y,Z)initial*Rx*Ry*Rz<\/pre>\n<p>The angle pheta in each matrix is the input rotation angle for that axis. You do need some sort of software to crunch this up into closed form equations. I used Matlab which can do the symbolic matrix multiplication. Once I got my equations i was able to calculate my (X,Y,Z)rotated offsets and add them into the equations above to get:<\/p>\n<pre>newFootPositionX = initialFootPositionX - translateX - rotatedX\r\nnewFootPositionY = initialFootPositionY - translateY - rotatedY\r\nnewFootPositionZ = initialFootPositionZ - translateZ - rotatedZ<\/pre>\n<p>This *almost* works worked perfectly. The issue is that my corner legs were behaving funny. That i realized was because my math wasn&#8217;t taking into account their mounting angle. \u00a0Basically each corner points 45 degrees out. I need to rotate all my coordinates for these legs and there&#8217;s no better tool than&#8230; the rotation matrix! This time its easier because this is a single axis rotation so there is only one matrix, Rz.<\/p>\n<pre>(X,Y,Z)coxaCorrected = (X,Y,Z)newFootPosition*Rz<\/pre>\n<p>Note that the 45deg input is the angle for the front right leg. The right rear leg would be 135deg, the left rear would be 225deg, and the upper left would be 315deg as you go around the clock.<\/p>\n<p>Here&#8217;s the code:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/**********************************************************************************************************\r\n    fodyFK()\r\n    Calculates necessary foot position (leg space) to acheive commanded body rotations, translations, and gait inputs\r\n***********************************************************************************************************\/\r\nvoid bodyFK(){\r\n\r\n    float sinRotX, cosRotX, sinRotY, cosRotY, sinRotZ, cosRotZ;\r\n    int totalX, totalY, totalZ;\r\n    int tempFootPosX&#x5B;6], tempFootPosY&#x5B;6], tempFootPosZ&#x5B;6];\r\n    int bodyRotOffsetX&#x5B;6], bodyRotOffsetY&#x5B;6], bodyRotOffsetZ&#x5B;6];\r\n\r\n    sinRotX = sin(radians(-commanderInput.bodyRotX));\r\n    cosRotX = cos(radians(-commanderInput.bodyRotX));\r\n    sinRotY = sin(radians(-commanderInput.bodyRotY));\r\n    cosRotY = cos(radians(-commanderInput.bodyRotY));\r\n    sinRotZ = sin(radians(-commanderInput.bodyRotZ));\r\n    cosRotZ = cos(radians(-commanderInput.bodyRotZ));\r\n\r\n    for( int legNum=0; legNum&lt;6; legNum++){\r\n\r\n        totalX = leg&#x5B;legNum].initialFootPos.x + leg&#x5B;legNum].legBasePos.x;\r\n        totalY = leg&#x5B;legNum].initialFootPos.y + leg&#x5B;legNum].legBasePos.y;\r\n        totalZ = leg&#x5B;legNum].initialFootPos.z + leg&#x5B;legNum].legBasePos.z;\r\n\r\n        bodyRotOffsetX&#x5B;legNum] = round(( totalY*cosRotY*sinRotZ + totalY*cosRotZ*sinRotX*sinRotY + totalX*cosRotZ*cosRotY - totalX*sinRotZ*sinRotX*sinRotY - totalZ*cosRotX*sinRotY) - totalX);\r\n        bodyRotOffsetY&#x5B;legNum] = round(  totalY*cosRotX*cosRotZ - totalX*cosRotX*sinRotZ         + totalZ*sinRotX         - totalY);\r\n        bodyRotOffsetZ&#x5B;legNum] = round(( totalY*sinRotZ*sinRotY - totalY*cosRotZ*cosRotY*sinRotX + totalX*cosRotZ*sinRotY + totalX*cosRotY*sinRotZ*sinRotX + totalZ*cosRotX*cosRotY) - totalZ);\r\n\r\n        \/\/ Calculated foot positions to acheive xlation\/rotation input. Not coxa mounting angle corrected\r\n        tempFootPosX&#x5B;legNum] = leg&#x5B;legNum].initialFootPos.x + bodyRotOffsetX&#x5B;legNum] - commanderInput.bodyTransX + leg&#x5B;legNum].footPos.x;\r\n        tempFootPosY&#x5B;legNum] = leg&#x5B;legNum].initialFootPos.y + bodyRotOffsetY&#x5B;legNum] - commanderInput.bodyTransY + leg&#x5B;legNum].footPos.y;\r\n        tempFootPosZ&#x5B;legNum] = leg&#x5B;legNum].initialFootPos.z + bodyRotOffsetZ&#x5B;legNum] - commanderInput.bodyTransZ + leg&#x5B;legNum].footPos.z;\r\n    }\r\n\r\n    \/\/ Rotates X,Y about coxa to compensate for coxa mounting angles.\r\n    leg&#x5B;0].footPosCalc.x = round( tempFootPosY&#x5B;0]*cos(radians(COXA_ANGLE))   - tempFootPosX&#x5B;0]*sin(radians(COXA_ANGLE)) );\r\n    leg&#x5B;0].footPosCalc.y = round( tempFootPosY&#x5B;0]*sin(radians(COXA_ANGLE))   + tempFootPosX&#x5B;0]*cos(radians(COXA_ANGLE)) );\r\n    leg&#x5B;0].footPosCalc.z =        tempFootPosZ&#x5B;0];\r\n    leg&#x5B;1].footPosCalc.x = round( tempFootPosY&#x5B;1]*cos(radians(COXA_ANGLE*2)) - tempFootPosX&#x5B;1]*sin(radians(COXA_ANGLE*2)) );\r\n    leg&#x5B;1].footPosCalc.y = round( tempFootPosY&#x5B;1]*sin(radians(COXA_ANGLE*2)) + tempFootPosX&#x5B;1]*cos(radians(COXA_ANGLE*2)) );\r\n    leg&#x5B;1].footPosCalc.z =        tempFootPosZ&#x5B;1];\r\n    leg&#x5B;2].footPosCalc.x = round( tempFootPosY&#x5B;2]*cos(radians(COXA_ANGLE*3)) - tempFootPosX&#x5B;2]*sin(radians(COXA_ANGLE*3)) );\r\n    leg&#x5B;2].footPosCalc.y = round( tempFootPosY&#x5B;2]*sin(radians(COXA_ANGLE*3)) + tempFootPosX&#x5B;2]*cos(radians(COXA_ANGLE*3)) );\r\n    leg&#x5B;2].footPosCalc.z =        tempFootPosZ&#x5B;2];\r\n    leg&#x5B;3].footPosCalc.x = round( tempFootPosY&#x5B;3]*cos(radians(COXA_ANGLE*5)) - tempFootPosX&#x5B;3]*sin(radians(COXA_ANGLE*5)) );\r\n    leg&#x5B;3].footPosCalc.y = round( tempFootPosY&#x5B;3]*sin(radians(COXA_ANGLE*5)) + tempFootPosX&#x5B;3]*cos(radians(COXA_ANGLE*5)) );\r\n    leg&#x5B;3].footPosCalc.z =        tempFootPosZ&#x5B;3];\r\n    leg&#x5B;4].footPosCalc.x = round( tempFootPosY&#x5B;4]*cos(radians(COXA_ANGLE*6)) - tempFootPosX&#x5B;4]*sin(radians(COXA_ANGLE*6)) );\r\n    leg&#x5B;4].footPosCalc.y = round( tempFootPosY&#x5B;4]*sin(radians(COXA_ANGLE*6)) + tempFootPosX&#x5B;4]*cos(radians(COXA_ANGLE*6)) );\r\n    leg&#x5B;4].footPosCalc.z =        tempFootPosZ&#x5B;4];\r\n    leg&#x5B;5].footPosCalc.x = round( tempFootPosY&#x5B;5]*cos(radians(COXA_ANGLE*7)) - tempFootPosX&#x5B;5]*sin(radians(COXA_ANGLE*7)) );\r\n    leg&#x5B;5].footPosCalc.y = round( tempFootPosY&#x5B;5]*sin(radians(COXA_ANGLE*7)) + tempFootPosX&#x5B;5]*cos(radians(COXA_ANGLE*7)) );\r\n    leg&#x5B;5].footPosCalc.z =        tempFootPosZ&#x5B;5];\r\n\r\n}\r\n\r\n<\/pre>\n<p>NOW it works!<\/p>\n<p>&lt;insert video here&gt;<\/p>\n<p>Head back to the beginning of <a title=\"Intro to Project B.E.T.H. (Unit 3021)\" href=\"http:\/\/projectsofdan.com\/?p=10\">Project B.E.T.H.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The next thing I wanted to accomplish was being able to translate and rotate the body while keeping the feet planted. For now this will simple enable the robot to wiggle around and &#8220;dance&#8221;, but eventually these movements will be necessary inputs for traversing uneven terrain. The concept for this is pretty straightforward. If i [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[5,7,34,6],"class_list":["post-96","post","type-post","status-publish","format-standard","hentry","category-b-e-t-h","tag-hexapod","tag-phantomx","tag-b-e-t-h","tag-robot"],"_links":{"self":[{"href":"https:\/\/projectsofdan.com\/index.php?rest_route=\/wp\/v2\/posts\/96","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/projectsofdan.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/projectsofdan.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/projectsofdan.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/projectsofdan.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=96"}],"version-history":[{"count":9,"href":"https:\/\/projectsofdan.com\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions"}],"predecessor-version":[{"id":221,"href":"https:\/\/projectsofdan.com\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions\/221"}],"wp:attachment":[{"href":"https:\/\/projectsofdan.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/projectsofdan.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/projectsofdan.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}