Category Archives: Uncategorized

Updated design for 8DOF quadruped robot

I got a new 3D printer, the amazing Prusa I3MK2. I really can recommend this machine (http://shop.prusa3d.com/en/3d-printers/59-original-prusa-i3-mk2-kit.html). The heated bed provides a perfect 1 layer every time. I don’t need to “babysit” my prints anymore =).

One of the first thing I have printed is a new design for my 8DOF small quadruped robot. I like the embossed details on the hip pieces and the battery holder mech.

PartsOverview

You can download the files from Pinshape or Thingiverse:

https://pinshape.com/items/34918-3d-printed-quadruped-robot-v2

http://www.thingiverse.com/thing:2283149

You are welcome to customise or edit the CAD design in OnShape, the project is shared using this link:

https://cad.onshape.com/documents/0accd1a24676e15bf99fd11e/w/0962067c20c6b1476c426a1c/e/33ba89d76935e0f2094cbde6

IMG_2339

Walking

Let’s review how to we get Felix a 3D printed quadruped robot to walk. Start by downloading or cloning the code from GitHub (https://github.com/Traverso/Felix3D).

If you haven’t done it yet, get Node.js and install/setup Johnny-Five to communicate with your microcontroller/board.

Getting Felix to walk properly requires some tweaking. We will try to compensate in software for a number of small imperfections in hardware that eventually add up.

You have (or should had) already done a rough calibration of the servos and leg assembly. Now let’s test one leg at a time.

To increase precision get a sheet of graph paper, glue it to some cardboard to add stiffness. Place it between Felix legs like this:

img_1728

Now copy/write your calibration offset to the index.js file

var config = {
  granularity:3,
  speed:40,
  geometry:{ femur:44, tibia:74, height:110, 
             step_height:10, step_width:26 },
  gait: [ //expected order FR, FL, BR, BL 
          [1,2,3,4],
          [2,3,4,1],
          [3,4,1,2],
          [4,1,2,3]
        ],
  legs:[  //expected order FR, FL, BR, BL
                      {
                         id:'FR',
                         label:'Front right',
                         origin:{x:10,y:0},
                         hip:{ pin:0, offset:2, invert:false },
                         knee:{ pin:1, offset:4, invert:false }
                      },
                      {
                         id:'FL',
                         label:'Front left',
                         origin:{x:15,y:0},
                         hip:{ pin:2, offset:3, invert:true },
                         knee:{ pin:3, offset:-4, invert:true }
                      },
                      {
                         id:'BR',
                         label:'Back right',
                         origin:{x:10,y:0},
                         hip:{ pin:4, offset:-2, invert:true },
                         knee:{ pin:5, offset:-6, invert:true }
                      },
                      {
                         id:'BL',
                         origin:{x:0,y:0},
                         label:'Back left',
                         hip:{ pin:6, offset:-3, invert:false },
                         knee:{ pin:7, offset:-4, invert:false }
                      }
                   ]
              };

Run the index.js file. A reference to felix is injected to the REPL.
From the REPL you can call:

screen-shot-2016-12-18-at-13-57-04

img_1729

Update the values directly in the REPL and recalibrate until you get it right:
Screen Shot 2016-12-18 at 13.56.34.png

Now, control the home position of the leg:

screen-shot-2016-12-18-at-14-02-42

Use the graph to check that the tip of the leg hit it’s mark: directly 110 millimeter beneath the hip joint.

IMG_1730.JPG

Next, control the two furthest points of the step:

screen-shot-2016-12-18-at-14-08-42

If the home position and the step-pose position are off, you can tweak the leg’s origin values:

screen-shot-2016-12-18-at-14-12-19

Once you are satisfied with your angles offsets and your origin offset, remember to update the values in the index file.  Repeat this steps for the next tree legs.

Now let’s try some walking. Press the “arrow up” key and Felix will start a creeping gait by running the forward method. Press the space bar to pause and resume the walk.

Felix.prototype.forward = function(){
  if(this.state == 'forward_pause')
  {
    this._runSchedule();
    this.state = 'forward';
    return;
  }

  var c = this._genwalk();
  c.push({cmd:'loop',count:-1});
  this.schedule = c;
  this.cycle_idx = 0;
  this.scheduleIdx = 0;
  this._runSchedule();
  this.state = 'forward';
}

This method generates a walk cycle based on the current step properties, set the state and start running the scheduler.

The scheduler consumes an array of “frames”. The rate at which the frames are processed is controlled by the “speed” configuration value.

A frame consist of a command and a payload. Currently they are two types of frames, a control frame like:

{cmd:'loop',count:-1}

When the scheduler encounter this frame it loops back to the start of the scheduler and decrements the count value. If the count value reach zero the schedule continues with the next frame. For an infinite loop the count value can be set to -1.

The other type of frame is a “pose”:

{ cmd:'pose', angles:[{hip:int, knee:int}, {hip:int, knee:int},
{hip:int, knee:int}, {hip:int, knee:int} ] }

When the scheduler encounter this frame, it will position each leg joint to the provided angles.

The generated walk cycle is a creeping gait (or static stable gait) where the body is moved forward at the same time that the stepping leg is being lifted.

An alternative (more stable, but slower cycle) can be implemented by shifting the center of mass first and then  lifting the stepping leg.

To generate the cycle, a step is divided into four key-poses. From pose one to four the legs push the ground behind shifting the body along. In pose four the leg is lifted in a semicircle back to pose one.

A gait  is described as an array of poses:

//expected leg order FR, FL, BR, BL
gait: [
   [1,2,3,4],
   [2,3,4,1],
   [3,4,1,2],
   [4,1,2,3]
]

Felix currently master two creep gaits, the “cat” and the “deer”.  In the cat gait the sequence of lifted legs is:

  1. front-right
  2. back-left
  3. front-left
  4. back-right

In the deer  gait the sequence is:

  1. front-right
  2. back-right
  3. front-left
  4. back-left

From one pose to the next the needed transition points are generated by two methods: “_linearTrajectory” and “_ellipticalTrajectory”.

Felix.prototype._linearTrajectory = function(line,
                                             granularity,
                                             skip_start_point){
    var trajectory = [];
    var granularity = granularity || 8;

    //find the slope/delta
    var delta_x = line.b.x - line.a.x;
    var delta_y = line.b.y - line.a.y;

    //calculate the distance between the two points
    var distance = Math.sqrt( ((delta_x) * (delta_x)) +
                              ((delta_y) * (delta_y)) );

    if(distance == 0) return [];

    //divide the line int the required number of points
    //decrease the granularity one step to be able to include 
    //the end point
    var skip = (skip_start_point)? 0:1;

    var step_size = distance / (granularity - skip);
    var c_step = (skip_start_point)? step_size:0;

    for(var i=0;i < granularity;i++){
        var inc = c_step / distance;

        trajectory.push({
                          x:Math.round(line.a.x +
                           (inc * delta_x)),
                          y:Math.round(line.a.y + 
                            (inc * delta_y))
                        });
        c_step+= step_size;
     }
     return trajectory; 
}

Felix.prototype._ellipticalTrajectory = function(arc,
                                                 granularity,
                                                 skip_start){
      var trajectory = [];
      granularity = granularity || 8;

      //divide the angles int the required number of points
      //decrease the granularity one step to be able to include 
      //the end point
      var skip = (skip_start)? 0:1;
      var step_size = (arc.end_angle - arc.start_angle) / 
                      (granularity - skip);
      var c_angle = arc.start_angle;
      
      if(skip_start_point) c_angle+= step_size;
      
      for(var i=0;i < granularity;i++){
        var x = arc.origin.x + arc.radius.x * 
                Math.cos(Math.radians(c_angle));

        var y = arc.origin.y + arc.radius.y * 
                Math.sin(Math.radians(c_angle));

        trajectory.push({ x:Math.round(x),y:Math.round(y) });
        c_angle+= step_size;
      }
      return trajectory;
}

The number of transition points in both methods are governed by the configuration variable “granularity”.

The points generated for the poses and transitions are then converted to angles using the Inverse kinematics method described in a previous post. This angles are added to the frame, and the frame is added to the scheduler.

This is a video of the cat style creep gait:


And the “deer” style creep gait:

 

 

Initial servo calibration and leg position

Calibrating the servos and getting the initial position of the legs right is quite important in order to get a smooth walking experience.

After setting op your Node.js and Johnny-Five environment create a new directory and add the following script:

var five = require("johnny-five");
var board = new five.Board();

var legs = [
              {
                 id:'FR',
                 lable:'Front right',
                 hip:{ pin:0, offset:0, invert:false },
                 knee:{ pin:1, offset:0, invert:false }
              },
              {
                 id:'FL',
                 lable:'Front left',
                 hip:{ pin:2, offset:0, invert:true },
                 knee:{ pin:3, offset:0, invert:true }
              },
              {
                 id:'BR',
                 lable:'Back right',
                 hip:{ pin:4, offset:0, invert:true },
                 knee:{ pin:5, offset:0, invert:true }
              },
              {
                 id:'BL',
                 lable:'Back left',
                 hip:{ pin:6, offset:0, invert:false },
                 knee:{ pin:7, offset:0, invert:false }
              }
           ];

board.on("ready", function() {

  for(var i = 0; i < legs.length; i++){
    legs[i].hip.servo = new five.Servo({
                          controller: "PCA9685",
                          address: 0x40,
                          invert:legs[i].hip.invert,
                          pin: legs[i].hip.pin
                        });

    legs[i].knee.servo = new five.Servo({
                          controller: "PCA9685",
                          address: 0x40,
                          invert:legs[i].knee.invert,
                          pin: legs[i].knee.pin
                        });
  }

  for(var i = 0 ; i < legs.length; i++){
    legs[i].hip.servo.to(90 + legs[i].hip.offset );
    legs[i].knee.servo.to(90 + legs[i].knee.offset );
  }

  this.repl.inject({
    legs:legs
  });

});

For the next step is best not to have the thighs/femurs attached (to avoid the risk of striping the servos gears).

Edit the pin number in the script (legs.hip.pin, etc) to match your setup’s connections and run the script. This will set all servos to 90 degrees.

Now attach the thighs/femurs. The femurs should form a 90 degrees angle in relation to the body.

The shins should also form a 90 degrees angle, but be aware that the shin is slightly lifted as the angle should be from the tip of the shin to the femur (as seen in the graphic).

Due to the coarseness of the teeth on the servo horns the resulting angles  might be off by a couple of degrees. To get it as close as possible edit the offset values in the script (legs.hip.offset, etc). For example if the front right femur is off by 2 degrees to the left set the offset value to legs.hip.offset = -2.

Run the script again and check (preferably with an angle ruler) that all segments are correctly positioned.

Step by step assembly guide

This is a short step by step assembly guide for those of you who have downloaded (https://pinshape.com/items/27304-3d-printed-quadruped-robot) and printed Felix the quadruped robot.

You will need the following parts:

parts

First, press-fit the four hip elements into the two body parts:

step_1

Next, join the two body subassemblies using the belt piece:

step_2

Now take the servos and press them into the thighs. If they are too loose, shim them up with some tape.

step_3

Connect the thigh subassembly to the hip using the servo horn, add the horn screw but don’t tighten it just yet. Repeat for the four legs.

step_4

Attach all the shin in the same way:

step_5

Your robot should now look like this:

step_6

The next post will guide you through connecting the electronics and the initial calibration of the servos.

 

Here comes the BOM

This are the electronic part you will need to build your own Felix. I’ve created a Wishlist at Adafruit for your convenience: http://www.adafruit.com/wishlists/417109

Quantity Item URL price (USD)
1 8-Channel PWM or Servo FeatherWing Add-on For All Feather Boards PID:2928 https://www.adafruit.com/products/2928 9.95
1 Adafruit Feather M0 Bluefruit LE PID: 2995 https://www.adafruit.com/products/2995 29.95
1 Lithium Ion Polymer Battery – 3.7v 150mAh PID: 1317 https://www.adafruit.com/products/1317 5.95
1 4 x AA Battery Holder with On/Off Switch PID: 830 https://www.adafruit.com/products/830 2.95
1 3×4 Right Angle Male Header – 4 pack PID: 816 https://www.adafruit.com/products/816 2.95
1 Feather Header Kit – 12-pin and 16-pin Female Header Set PID: 2886 https://www.adafruit.com/products/2886 0.95
1 Feather Stacking Headers – 12-pin and 16-pin female headers PID: 2830 https://www.adafruit.com/products/2830 1.25
8 Micro Servo – MG90S High Torque Metal Gear PID: 1143 https://www.adafruit.com/products/1143 79.60
2 Mini Panel Mount DPDT Toggle Switch PID: 3220 https://www.adafruit.com/products/3220 2.50
Total: 136.05

Or you can download an Excel file bom.

img_1533

Computing the inverse kinematics of a two links planar system

This is a short explanation of how to calculate the leg angles in our quadruped robot using basic trigonometry. If you don’t need the explanation but just want an example implementation scroll to the bottom to see the code sample.

ik

As you can see in the graphic above, we want to find the angles A1 and A4:

  • A1 is the rotation angle of our first segment around the hip joint
  • A4 is the rotation angle of our second segment around the knee joint

What we know is L1, L2, P1 and P2 where:

  • L1 is the length of our femur
  • L2 is the length of our tibia
  • P1 is the origin point, or position of our hip (0,0)
  • P2 is the requested end position (or destination) for the feet

So, basically we want to how (much) does our hip and knee need to rotate in order for our feet to reach the requested end position.

We can calculate our knee angle using the law of cosines (https://en.wikipedia.org/wiki/Law_of_cosines). But to do so we need to know the length of the tree sides of the triangle L1, L2 & K.

So we start calculating our missing side K. We find the to segments H1 and H2 using the delta between our origin (P1) and our destination (P2):


int H1 = P2.x - P1.x; //delta on the x axis
int H2 = P2.y - P1.y; //delta on the y axis

Because H1 and H2 create a right-angled triangle, we can use the Pythagorean Theorem (http://www.mathplanet.com/education/pre-algebra/right-triangles-and-algebra/the-pythagorean-theorem) to find K (the hypothenuse):


float K = sqrt( pow(H1,2) + pow(H2,2));

Now we can get the knee angle:


//angle between L1 & L2 - the to segments, femur and tibia
float A1 = acos(( pow(L1,2) + pow(L2,2) - pow(K,2))/ (2 * L1 * L2));

Getting our hip angle is bit more convoluted. We need to find the angle A2 (no problem, having the tree sides is just more law of cosines), and A3 (another right-angled triangle – more Pythagoras).


//get the angle between the hypothenuse and the first segment (femur)
float A2 = acos( (pow(K,2) + pow(L1,2) - pow(L2,2)) / (2 * K * L1));

//get the angle between the hypothenuse and the x axis

float A3 = asin(H1/K);

Then we add this to angles and subtract the sum from 180 degrees and we are left with our hip angle.


float A4 = (PI / 2) - (A2 + A3);

Below you can see a function implemented for an Arduino sketch.


/**********************************************************
* Inverse Kinematic function for a two link planar system.
* Given the size of the two links an a desired position,
* it returns a pose struct with angles for both links
**********************************************************/
struct pose IK(int L1, int L2, struct point P2)
{
struct pose a;
struct point P1 = { HIP_ORIGIN_X, HIP_ORIGIN_Y }; //origin point (hip)

int H1 = P2.x – P1.x; //delta on the x axis
int H2 = P2.y – P1.y; //delta on the y axis

//this is the hypothenuse between the origin and the target
float K = sqrt( pow(H1,2) + pow(H2,2));

//the hypothenuse can not be larget the the sum of the segments
if( K > (L1 + L2 )) K = L1 + L2;

//knee rotational angle
float A1 = acos(( pow(L1,2) + pow(L2,2) – pow(K,2))/ (2 * L1 * L2));

//convert from radians to degrees and cast as an integer
float A1_ = A1 * RAD_TO_DEG;
int A1__ = (int) A1_;

//get the angle between the hypothenuse and the first segment (femur)
float A2 = acos( (pow(K,2) + pow(L1,2) – pow(L2,2)) / (2 * K * L1));

//get the angle between the hypothenuse and the x axis
float A3 = asin(H1/K);

//get the hip rotational angle
float A4 = (PI / 2) – (A2 + A3); //add the two angles, substract it from half a circle

float A4_ = A4 * RAD_TO_DEG;
int A4__ = (int) A4_;

a.hip_angle = A4__;
a.knee_angle = A1__;

return a;
}

 

3D printable Quadruped robot

A contest on Pinshape (https://pinshape.com/contests/design-for-electronics-contest) got me to simplify the design of Felix and optimise it for 3D printing. The focus was on minimal support material, fast print time and optimal orientation on the print bed for best first layer adhesion. Other concerns where easy of assembly and sturdinnes of the final robot.

screen-shot-2016-10-16-at-21-49-34

You can download and print the design from Pinshape (https://pinshape.com/items/27304-3d-printed-quadruped-robot)

If you want to edit/customise the 3D model, you are free to copy my OnShape project using this link: https://cad.onshape.com/docume…

Screen Shot 2016-10-16 at 22.49.40.png

There ain’t much room for my current electronics setup. The servo connectors require a lot of space – even using angled pins. So I have ordered a feather board and a servo feather wing from Adafruit. The feather board has the added bonus that it can be controlled via Iphone/Android using Bluetooth.

3D Printing

Last year I finally bought a 3D printer. In retrospect I should have done this a long time ago.
I used to believe that you needed a high-end machine to create usable parts,
and that anything less was a waste of time. There where toys only capable of churning out useless trinkets.

Boy I was wrong. Anybody interested in mechanical engineering or industrial design should get one immediately.

I got a Printrbot metal simple kit. My appreciation for 3D technology is colored by my personal experience with this particular machine, that turned out be an amazing piece of equipment.
Sturdy, reliable, elegant and honest in its design, the simple metal has performed well beyond my expectations.

One of the reasons I was holding back my purchase, was that I was afraid that after a couple of week of tinkering, the machine will be collecting dust on a corner. But to the chagrin of the rest of my family, the Printrbot is constantly churning out parts.

Currently, I’m even considering getting a Ultimaker or a Lulzbot Taz, not to replace my Printrbot but to extend my build size and printing capacity.

Setup

At the same time last year I start evaluating OnShape a cloud based professional CAD solution. I have used Autodesk Fusion 360 on and off for some time, but the chemistry wasn’t there. I do think Fusion is an amazing piece of software and I still use their CAM and rendering features, but modeling on OnShape just “clicked” with me from day one.
My current workflow looks like this:
I’ll do my modeling on OnShape, export the part to STL, slice the part in Simplify3D and sent the G-code to Octoprint.

On a side note, before upgrading your hardware get Simplify3D!

Design

Having a 3D printer at hand allows you to develop your designs skills at a fast pace.
You can iterate over small aspects of your design until you get them right.
Say, two parts need a snap-click assembly. You can isolate the snap-click features and print only the relevant sections, until you get the tolerances and amount of material right. Then you add those sections to your main parts.
You will learn a lot about designing within the constrains of a production method.
In 3D printing, orientation plays a crucial role.
Orientation impacts the level of precision you can achieve on a given surface.
Because parts consists of layers, the forces they can withstand vary depending on the direction applied.
In order to get the ideal orientation for a critical aspect of your design, you will sometimes need to split a part into discrete components.
The filament (type of material) and the chosen extrusion settings can have an impact in tolerances.
For mechanical parts where you need a higher level of precision, you are better of with slower speeds and low heat.

When you get orientation right, the (usually unwelcome) striation,
suddenly became an esthetic asset that reinforce the structural ideas behind your design.

Holding such a piece in your hand with the original digital model still on-screen is remarkably satisfying.
It’s and idea materializing out of thin air, and it feels like magic.
If you already have or want to buy a 3D printer, don’t forget that it’s not about the technology, but about what you can imagine.

Resources

Hardware
I own a Simple metal, but have I played with, and can recommend the Ultimaker and the Taz.

– Printrbot Simple Metal

Assembled Printrbot Simple

For Europeans I can recommend ordering from RoboSavy
https://robosavvy.com/store/assembled-printrbot-simple.html

– Ultimaker 2+
https://ultimaker.com/en/products/ultimaker-2-plus

– Lulzbot Taz 5
https://www.lulzbot.com/store/printers/lulzbot-taz-5

Filament
Don’t be cheap on the filament. You are not going to use that much, and quality shows. Recommended brands are Colorfabb & Monsterfil.

First layer adhesion
I start using blue tape (3M ScotchBlue 2090 Painter’s tape from Amazon or from Adafruit ) with mixed results. Printing larger flat surfaces without warping was a challenge, until I start heating the printer bed with a heat gun.
Because the bed on the Printrbot is solid metal, it could accumulate enough heat to get me a solid foundation. But applying the tape quickly became annoying.

Then I got the Zebra Plate from PRINTinZ! I can not recommend this enough. No preheating, or taping or warping.
The only problem is that sometimes parts can be difficult to pray of the board.
If you can wait you can put the plate on the freezer for some minutes.

One trick for the first layer is to add small pieces of paper under the bed. If the first layer is too squashy you can take them out while the brim is still printing.
It not squashy enough you can remove the center clip. This will give you enough wiggle room to compensate for small z calibration issues.

CAD Software
OnShape
Fusion360
Meshmixer

Slicers
Cura
Simplyfy3D
– Even if you don’t use Simplify3D check their quality guide.
This is a great resource to understand how to improve your prints.

Print servers
Astrobox
Simple UI, to get you started but you’ll be long for more control pretty soon.
Adafruit starter package.

Octoprint
Full feature solution with lots of plugins
Adafruit starter package.

YouTube Channels
There are a lot of 3D printing channels on YouTube. My favourites:
Makers Muse
Thomas Sanladerer
Noah & Pedro Ruiz (from Adafruit)

Web sites and 3D repositories
Pinshape
Thingiverse
YouMagine

CAD Mashups

In the “old days”, if you wanted to display video on a web page you have to upload it to a server
and hope that people had the right media plugin to handle your video format. YouTube changed that by not only hosting and encoding the files, but also by allowing you to embed their viewer into your website. By “playing ball” with the rest of the web YouTube became an integral part of it (cats may have played a role as well).

Something similar happened with maps. By allowing third-party websites to embed their maps (and by providing a formal API) Google Maps evolved from a novel web-version of a classical desktop-app to a structural part of the web.

Currently I’m intrigued by the future of OnShape, a web & cloud base 3D CAD system.
They are openly developing the product at a furious pace (https://www.onshape.com/cad-blog).
At this rate they could soon reach feature parity with their nearest competitors.

But what’s really interesting is that the system doesn’t doesn’t depend on a plugin. It’s all in the browser, pushing the envelope. It is entirely possible for OnShape to allow other sites to use their tech as an integrated service. And they seem to be open to the idea: https://forum.onshape.com/discussion/comment/6562#Comment_6562

Recently I ran into a relevant scenario.  “Enabling the future” is a global network of volunteers that donate 3D print time to create prosthetics for amputees. They have created a great web app, the “Hand-o-matic“. The app let you customise the design of a prosthetic hand and will mail you the generated STL documents based on the supplied parameters.
They use OpenSCAD (an open source CAD modeller) in command line mode to generate still-images of the parts (and to generate STL files).

Screen Shot 2015-08-17 at 17.23.18

And embedable CAD system could power a much richer experience for this and many other sites where there is a need for visualising and editing parametric 3D designs.

OnShape has the potential to enable a new kind of web application hybrids (Mashups), that take CAD and the Web to new places.

OLED Eyes

The update rate of my OLED screen via IC2 is to slow to do proper animation. Redrawing the eyes on a new position every 12 times a seconds was out of the question.

Luckily the oled-js library supports a scroll method. So I went with that and implement the movement of the eyes by controlling the scroll direction and timing the start-stop sequence with temporal. Because the entire screen buffer is pushed around by the hardware, the eyes don’t need to be so simplistic as I initially made them. They could as well be a bitmap with a set of mesmerising cat eyes, but for now this will do.