Buoyed by the success of my 6 DOF biped I decide to take the next step (no pun intended).

I purchased another Dynamixel AX-12A servo for each leg to give me eight degrees of freedom (DOF) in total. The hope was that this would result in a much more life like walking gait. Whilst ordering the servos, I also bought some more Robotis plastic frames to ease bolting this lot together.

The new servos and frames were fixed together similar to the previous design, but now with an enhanced ankle joint. With 8 DOF, I could no longer work out joint ankles in my head. It was time to break out some inverse kinematics!

Designing a walking gait from scratch is not that simple. I started by watching how people walk and tried to establish some simple rules I could emulate in code. My first observation was that humans have a really efficient walking gait. Our bodies carry a large mass above the waistline and we tend to keep that fairly stable whilst walking.

Rule #1: The robot’s hip height should remain constant.

Secondly, we raise and lower our feet very smoothly, just enough to achieve forward movement, which peaks in the middle of our stride.

Rule #2: The robot’s feet should follow clipped sine wave.

With these two rules established I could now generate a system of triangles to calculate all servo positions at each point of the stride. I could solve any missing angles using the law of cosines. To help me with this job I wrote a C# application to crunch the numbers and visualise the task. The result was a [52, 8] matrix of servo positions that I could paste into a very small Arduino program.

I will walk through the C# application in detail in my next post.

The resulting Arduino code is posted below. Like before, the program refers to my Dynamixel class created in a previous post.

I’m really pleased with the results. Here is a video of my new 8 DOF biped walking across a glass table – it looks and sounds pretty sinister…

Code Snippet
  1. #include “Dynamixel.h”
  2. #include “Wire.h”
  3. #define WALK_SWITCH  8
  4. Dynamixel servo;
  5. int pos[52][8] = {
  6. {-95, -138, 43, -45, 41, 138, -97, -45},
  7. {-93, -140, 47, -45, 50, 151, -101, -45},
  8. {-92, -141, 49, -45, 59, 164, -105, -45},
  9. {-90, -143, 53, -45, 67, 174, -107, -45},
  10. {-88, -144, 56, -45, 74, 184, -110, -45},
  11. {-85, -145, 60, -45, 80, 192, -112, -45},
  12. {-83, -146, 63, -45, 87, 198, -111, -45},
  13. {-81, -147, 66, -45, 92, 204, -112, -45},
  14. {-78, -147, 69, -45, 97, 207, -110, -45},
  15. {-76, -147, 71, -45, 101, 210, -109, -45},
  16. {-73, -148, 75, -45, 104, 210, -106, -45},
  17. {-70, -147, 77, -45, 107, 210, -103, -45},
  18. {-67, -147, 80, -45, 109, 207, -98, -45},
  19. {-64, -147, 83, -45, 110, 204, -94, -45},
  20. {-61, -146, 85, -45, 110, 198, -88, -45},
  21. {-58, -145, 87, -45, 110, 192, -82, -45},
  22. {-55, -144, 89, -45, 109, 184, -75, -45},
  23. {-52, -143, 91, -45, 106, 174, -68, -45},
  24. {-48, -141, 93, -45, 103, 164, -61, -45},
  25. {-45, -140, 95, -45, 100, 151, -51, -45},
  26. {-45, -140, 95, -33, 100, 150, -50, -33},
  27. {-44, -140, 95, -20, 99, 148, -49, -20},
  28. {-44, -140, 95, -7, 98, 146, -48, -7},
  29. {-43, -139, 96, 6, 98, 144, -47, 6},
  30. {-43, -139, 96, 19, 97, 142, -46, 19},
  31. {-42, -139, 96, 32, 96, 140, -45, 32},
  32. {-41, -138, 97, 45, 95, 138, -43, 45},
  33. {-50, -151, 101, 45, 93, 140, -47, 45},
  34. {-59, -164, 105, 45, 92, 141, -49, 45},
  35. {-67, -174, 107, 45, 90, 143, -53, 45},
  36. {-74, -184, 110, 45, 88, 144, -56, 45},
  37. {-80, -192, 112, 45, 85, 145, -60, 45},
  38. {-87, -198, 111, 45, 83, 146, -63, 45},
  39. {-92, -204, 112, 45, 81, 147, -66, 45},
  40. {-97, -207, 110, 45, 78, 147, -69, 45},
  41. {-101, -210, 109, 45, 76, 147, -71, 45},
  42. {-104, -210, 106, 45, 73, 148, -75, 45},
  43. {-107, -210, 103, 45, 70, 147, -77, 45},
  44. {-109, -207, 98, 45, 67, 147, -80, 45},
  45. {-110, -204, 94, 45, 64, 147, -83, 45},
  46. {-110, -198, 88, 45, 61, 146, -85, 45},
  47. {-110, -192, 82, 45, 58, 145, -87, 45},
  48. {-109, -184, 75, 45, 55, 144, -89, 45},
  49. {-106, -174, 68, 45, 52, 143, -91, 45},
  50. {-103, -164, 61, 45, 48, 141, -93, 45},
  51. {-100, -151, 51, 45, 45, 140, -95, 45},
  52. {-100, -150, 50, 33, 45, 140, -95, 33},
  53. {-99, -148, 49, 20, 44, 140, -95, 20},
  54. {-98, -146, 48, 7, 44, 140, -95, 7},
  55. {-98, -144, 47, -6, 43, 139, -96, -6},
  56. {-97, -142, 46, -19, 43, 139, -96, -19},
  57. {-96, -140, 45, -32, 42, 139, -96, -32}
  58. };
  59. int centre = 512;
  60. byte p = 0;
  61. void setup() {
  62.   pinMode(WALK_SWITCH, INPUT);
  63.   Serial.begin(1000000);
  64. }
  65. void loop() {
  66.   if (digitalRead(WALK_SWITCH)) {
  67.     update(p++);
  68.     delay(38);
  69.     if (p > 51) p = 0;
  70.   }
  71. }
  72. void update(byte p) {
  73.   int fix = 0;
  74.   for (byte i = 0; i < 8; i++)
  75.   {
  76.     if (i==0) fix = -120;
  77.     else if (i==4) fix = 120;
  78.     else fix = 0;
  79.     servo.setPos(i + 1, centre + pos[p][i] + fix, 0);
  80.   }
  81. }