Jan 26

The program this simulates the snake moving around is finished and it can be downloaded here. When it starts the code “reads” the servo positions, based on these the previous tail position is calculated as explained in a previous post. Also two points in front of the snake are calculated and the spline of the snake is drawn. This spline is used as the path to follow.

The most difficult part was to define a good algorithm how to advance the full snake for a specific distance over this path. It finally turned out to be very simple; the function that executes this is called FindNextPosition.

The same formula for calculating the spline between two points using two control points is used. This requires an Index value that ranges from 1 down to 0 and calculating the length of the vector between the start point and the point on the spline at a given Index value. The value of Index is decreased with 0.01 until the length of the vector matches the required distance. The (X, Y) position of the point at the found Index is the point to which the snake will move forward for that specific segment of the snake.

This process is done for all segments from head to tail. As a result all servo positions are known on the spline with a specific distance to the previous stored servo positions. The servo positions are only stored when the snake moved one serve length forward. The snake stops moving until you click with the mouse in front of the snake. The angle between the tip of the head and the location you clicked is used for calculating the new target position to reach one servo length in front of the snake.

I made a screen capture of the program using a trail version of Camtasia Studio while using it and uploaded the video to YouTube. If you watch the movie, please give it a five star rating when finished so it scores higher in the search results!

When watching the movements it looks to be a vary promising method, the resulting spline looks vary natural and it almost makes me wonder if snakes can calculate splines as well….

Jan 25

The first steps have been made to calculate a vector based model of the snake based on the servo positions and the servo length as definied previously. The code is indeed simple, based on:

  ServoPositions [0]  := 570;
  ServoPositions [1]  := 692;
  ServoPositions [2]  := 440;
  ServoPositions [3]  := 372;
  ServoPositions [4]  := 405;
  ServoPositions [5]  := 665;
  ServoPositions [6]  := 598;
  ServoPositions [7]  := 664;
  ServoPositions [8]  := 350;
  ServoPositions [9]  := 349;
  ServoPositions [10] := 582;

below snake is drawn:

using below procedure to calculate the joint positions:

procedure TMainWindow.CalculateJoints;
var Servo  : Integer;
    dAngle : Real;
    dX     : Real;
    dY     : Real;
  JointLocations [0].X := 0;  // Tip of the head is reference point
  JointLocations [0].Y := 0;
  JointLocations [1].X := (0-cv_ServoLength);
  JointLocations [1].Y := 0;

  dAngle := 180;

  for Servo := 0 to (cv_MaxServo-1) do
      dAngle := (dAngle + ((((1023-ServoPositions [Servo])/3.41)+30)-180));
      dX     := (Cos((dAngle/360)*(2*Pi))*cv_ServoLength);
      dY     := (Sin((dAngle/360)*(2*Pi))*cv_ServoLength);

      JointLocations [Servo+2].X := (JointLocations [Servo+1].X+dX);
      JointLocations [Servo+2].Y := (JointLocations [Servo+1].Y+dY);

In order to map the splines over the joints two additional points are needed. One point one servo length behind the tip of the tail and one point one servo length in front of the tip of the head. The point behind the tail is not known when the snake is powered on, by default the mirrored point can be used. As a result a curved spline is drawn, when the snake moved one servo length forward that the previous tail position can be used.

The point in front of the snake is also not known but this should be on the path to follow. As a result a “path to follow” generator needs to be developed, although at this point I have no idea how this should look like it is clear this will be an important part of the snake. It should map a basic sine but change the sine if obstacles are in the way or if a corner must be taken.

Jan 24

When writing the code for calculating the (X,Y) coordinates of the servo’s it became clear that the servo positions or servo angles can not simply be used. Since all coordinates must use (0, 0) as the reference point (tip of the snake’s head) the angle of the second servo is the sum of the first servo angle and the second servo angle. For the third servo it’s even more complex since this is the sum of three angles.

I remember that I ones needed to study vector based calculated, after some refreshing this is what needs to be used. The first servo is always parallel with the X-axe; it starts at (0, 0) and end at (-CL, 0) where CL stands for ServoLength. The delta angle that the second servo makes relative to a straight line (180 degrees angle) is needed for calculating the total angle of the servo compared to the positive direction of the X-axe. In below image dB is +45 degrees. The angle used for the servo is opposite to the direction of the servo that has a positive rotation CCW, this is needed to simplify the dX and dY calculations.

By adding the delta in angle to the previous servo angle the absolute angle is found. Using this angle dX and dY can be calculated referenced to (0, 0). The absolute (X, Y) can be found by adding these values to the previous servo position.

This process can be repeated for all servos, angles larger than 360 degrees can remain as they are since the sine and cosine of these angles automatically compensate for this.

Jan 21

Since the amount of memory (RAM) is limited in a micro controller (4k in a ATmega64) the theory of storing a list of servo positions that match the path to follow is not very appealing. Having 11 servo’s that each are 70mm long would require 11*70*2=1540 bytes of memory compared to 11*2=22 bytes in case of only storing the servo positions.

In theory below routine could work to determine the next servo positions:

  • Read current servo angles
  • Based on the angle and length of the servo all (X, Y) positions can be calculated with respect to the head at location (0, 0)
  • From head tot tail servo do below using the spline functions:
    • Start with Index=1
    • while distance between current point and new point is less than 1mm do decrease index with 0.01

This will find all (dX, dY) of the servo’s when the snake moved forward 1mm along it’s path. Based on this list of new (X, Y) positions and the length of the servo all the servo angles/positions can be calculated again.

This will only work IF the old spline representing the full snake matches exactly the new spline (except of course the new part of the head and the last part of the tail. In order to simulate this the existing spline simulation program can be modified.

Thinking about it a bit more, this will work if the old calculated (X, Y) coordinates are stored and ONLY replaced with new coordinates if the servo moved exactly 1 length along it’s path which is the case when Index reaches 0 in the formula. In this way the spline will never change since the points in which it is based will never change. As a result the amount of bytes needed for storing the path of the snake is limited to storing 11 points each requiring 8 bytes (2 float variables of 4 bytes each). In order to optimize the routines an additional variable is required that holds the last used value of Index. Also the tip of the head and the tail (control points for the first and last spline) must be store next to a new target postion 1 servo length in front of the snake. In total this requires (11+3+1)*8=120 bytes.

Below image shows the translation of servo positions to servo angles and finally to (dX, dY).

In the next coming days I will extend the SplineSim program to test this theory.

Jan 20

In order to draw a spline 4 points are needed: a start and enpoint of the spline and two control points. The control points define the vector or direction in which the spline starts and ends. Based on this the formula for calculating (X, Y) at interval Index is listed below:

      X := Round ((StartPoint.X*Index) + (EndPoint.X*(1-Index)) + (Weight*(EndPoint.X-ControlPointTwo.X)*(1-Index)*(1-Index)*Index) + (Weight*(StartPoint.X-ControlPointOne.X)*(1-Index)*Index*Index));

      Y := Round ((StartPoint.Y*Index) + (EndPoint.Y*(1-Index)) + (Weight*(EndPoint.Y-ControlPointTwo.Y)*(1-Index)*(1-Index)*Index) + (Weight*(StartPoint.Y-ControlPointOne.Y)*(1-Index)*Index*Index));

The interval ranges from 0 to 1 in real numbers, to find the middle point on the curve the value of Index should be 0.5. By sampling the equation more frequently the spline will be smoother. The value of Weight controls the tension of the spline or tangency towards the vectors. If set to 0 a straight line is drawn between the start and end point, it can be set larger than 1 although I’m not sure what the effect will be.

I wrote a small program in Delphi 7 to see how to use these functions; it can be downloaded here. When executed you see a white image, click with the left mouse button on the image to set a servo location, a red cross appears on that spot. Do this in total 11 times after which 9 splines are drawn to indicate the shape of the snake based on the provided servo positions. Why 9 splines? The first spline uses 4 points (point 1, 2, 3 and 4) where 1 is a control point, 2 and 3 the start/end points and 4 is the second control point. For the next spline points 2, 3, 4 and 5 are used resulting in a spline between points 2 and 3.

Below image shows a screen shot of several snakes that I drew. Try to keep the distance between the points the same to mimic the actual situation of the servo’s linked together. The Weight value can be changed in the code after which you need to recompile the project.

In order to study the effect of the Weight value I modified the program a bit so the same snake is drawn using various weight factors, below image shows the result.

When a snake moves forward with a constant speed it moves it’s head from left-to-right and right-to-left in a constant speed. As a result it follows a perfect sine is drawn, I added a function that fills the ServoPoints, draws the snake and also draws a perfect sine through those points. This function is placed under the Weight button that is hidden during design time. Make it visible if you want to play with is and re-compile the program.

After a couple of test runs it seems that the most optimal value for Weight is 0.65; it’s also clear that this value should be defined as a constant value in the final embedded software so that the playing can be repeated to see how the actual movement of the snake can be optimized.

Jan 19

A snake has between 100 and 400 vertebrae in his backbone, each of them form a ball-and-socket joint with additional parts that prevent torsion motion of the backbone. The horizontal angle that they can have compared to each other is limited to 10..20 degrees and the vertical angle is limited to 2..3 degrees. All vertebrae’s are the same, the only differ in size.

Lateral undulation is the most frequently used form of snake locomotion for most snakes. All parts of the body move simultaneously, experiencing continuous sliding contact with the ground. During lateral undulation, the snake pushes against minimal three contact points in the environment to facilitate forward movement. Each vertebrae follows the exact same path as the vertebrae in front of it.

A snake uses dynamic friction to move forward, this is not as inefficient as it might first appear. The skin of the snake is very elastic and is made out of highly polished scales which overlap each other with a friction coefficient between 0.3 and 0.4. The scales are pointing backwards providing low forward friction and high backward friction. The scales are not used for “walking”, forward motion is only done by muscle contraction.

Jan 19

A snake has several methods of moving forward:

Lateral undulation

Waves of muscular contraction and relaxation propagate from front to rear. Each point of the body slides along a single track on the ground without any static contact.

  • efficient way to progress
  • needs wide space
  • does not work on smooth surface
  • movement hindered by great body mass

Concertina progression

Sequential folding and unfolding of the body used differences in static and dynamic friction along different parts of the body.

  • works even in narrow spaces
  • inefficient

Side winding

Continuous alternating waves of lateral bending while maintaining only two contact points to the ground. Thus the body is shifted to the side.

  • relatively efficient
  • useful on soft grounds
  • not in narrow locations

Slide pushing

Quick waves from head to tail propels the body as a reaction to slip friction. The belly scales provide the outcome of a forward movement.

  • works on low friction surfaces
  • very ineffective

Rectilinear motion

Muscles shift the skeleton with respect to the skin. Waves of muscular contraction along the body propels the whole body. Traction to the ground is enabled by belly scales.

  • works with heavy bodies
  • effective
Jan 19

I modifed the stylesheet so that the area for text is larger allowing a larger font size to be used and larger images. Specially the screenshots in Generate the G-code page are imrpoved by this action.

Also minor changes are made to the grafics, for example the bullet is now more in-line with the rest and the icon on top allowing you to sign up for RSS feeds and to log in has been increased.

Jan 19

I spend the last 8 months on learning how the mill a part for the robots. Main goal was to build a CNC machine and figure out the process from designing a part in 3D all the way to autometed milling of the part. This process is documented in the page Machining parts.

Jan 18

After milling the first parts I got hold of a piece of very nice plastic called POM, this turned out to be perfect! It mills three times as fast as aluminum and the mills stay perfectly sharp. It’s a hard plastic so the forces that can be applied to the part are high, I would definitively advice you to use this material.

For aluminum type 5083 the milling speed is typical 100mm/min for a 6mm endmill using a 1.5mm depth per pass and 2mm stepover. For POM this can be 200mm/min for a 6mm endmill using 3.0mm depth per pass and 2mm stepover. In a single pass 2 times the amount of material is removed with 2 times the speed.

« Previous Entries