Skip to main content

Simulate and optimize planar leg mechanisms using PSO and GA

Project description

leggedsnake

This package aims to provide reliable computation techniques in Python to build, simulate and optimize planar leg mechanisms. It is divided in three main parts:

  • Linkage conception in simple Python and kinematic optimization relying on pylinkage.
  • Leg mechanism definition, with Walker heriting from the Linkage class.
  • Dynamic simulation and its optimization thanks to genetic algorithms.

Installation

Using pip

The package is hosted on PyPi as leggedsnake, use: pip install leggedsnake

Setting up Virtual Environment

We provide an environment.yml file for conda. Use conda env update --file environment.yml --name leggedsnake-env to install the requirements in a separate environment.

Requirements

Python 3, numpy for calculation, matplotlib for drawing, and standard libraries.

For kinematic optimization you can either use the built-in algorithm, or PySwarms, under MIT license. PySwarms is a much more complexe package which provides quick calculations, however with modern laptops the built-in swarm optimization should be quick enough to fit your needs.

Dynamic optimization relies on multiple packages. First of all it uses Pymunk, made by Victor Blomqvist, as a physics engine. Then you can either use the built-in algorithm, or the GA module from PyGAD. PyGAD is a complete library providing much more than genetic algorithms, so it might be heavy. PyGAD is more complete than the built-in however, so I haven't decided to continue on PyGAD or switch for another solution in the future.

Usage

The demo script is strider.py, which demonstrates all the techniques about the Strider linkage.

Defining a Walker

First, you need to define joints for your Walker as described in pylinkage documentation. Once your joints (let's say they are in a joint object), you should have something like that:

from pylinkage.linkage import Static, Pivot, Fixed, Crank

from leggedsnake.walker import Walker

# Center of the Walker
A = Static(x=0, y=0, name="A")
B = Crank(1, 0, distance=1, angle=0.31, name="Crank")
# etc... let's say with have joints up to E
my_walker = Walker(
  joints=(A, B, C, D, E),
  name="My Walker"
)

Walker is just a herited class of Linkage, with some useful methods, and behaves quite the same way.

Kinematic optimization using Particle Swarm Optimization (PSO)

No change compared to a classic linkage optimization. You should use the step and stride method from the utility module as fitness functions. This set of rules should work well for a stride maximisation problem: #. Rebuild the Walker with the provided set of dimensions, and do a complete turn. #. If the Walker raise an UnbuildableError, its score is 0 (or - float('inf') if you use other evaluation functions. #. Verify if it can pass a certain obstacke using step function. If not, its score is 0. #. Eventually mesure the length of its stide with the stride function. Return this length as its score.

Dynamic Optimization using Genetic Algorithm (GA)

Kinematic optimization is fast, however it can return weird results, and it has no sense of gravity while walking heavily relies on gravity. This is why you may need to use dynamic optimization thanks to Pymunk. However the calculation is much more slower, and you can no longer tests millions of linkages as in PSO (or you will need time). This is why we use genetic algorithm, because it can provide good results with less parents.

We handle everything almost evything world definition to linkage conversion. Appart from the GA parameters, you just have to define a fitness function. Here are the main steps for a maximisation problem:

  1. Create a function of two arguments, the first one should be the paramaters of the linkage, the second the initial positions for the joints.
  2. Try to do a revolution in kinematic simulation. If the Walker raises an UnbuildableError set its score to -float('inf').
  3. Otherwise use this procedure
from leggedsnake import physicsengine as pe

def dynamic_linkage_fitness(walker):
  """
  Make the dynamic evalutaion of a Walker.
  
  Return yield and initial position of joints.
  """
  world = pe.World()
  # We handle all the conversions
  world.add_linkage(walker)
  # Simulation duration (in seconds)
  duration = 40
  # Somme of yields
  tot = 0
  # Motor turned on duration
  dur = 0
  n = duration * pe.params["camera"]["fps"]
  n /= pe.params["simul"]["time_coef"]
  for j in range(int(n)):
      efficiency, energy = world.update(j)
      tot += efficiency
      dur += energy
  if dur == 0:
      return - float('inf'), list()
  print("Score:", tot / dur)
  # Return 100 times average yield, and initial positions as the final score
  return tot / dur, pos

And now, relax while your computer recreates a civilisation of walking machines!

Visualization

For this part we will focus on the Strider linkage, an exemple file is provided at strider.py. The linkage looks like this: A Kinematic representation of Strider linkage

Looks cool? Let's simulate it dynamically!

Dynamic one-leg-pair Strider being tested

Oops! Here is what you get when you forget to add more legs! There is real danger here, because your walker crawls well, you will be able to optimize efficiently the "crawler", which may be not your goal.

Let's add three more leg pairs. Why three? Many legs means more mass and constraints, so less yield and more intensive computations. On the other hand, we always want the center of mass over the support line, which means that if the walker begins to lift a foot (let's say a front foot), and another doesn't come on the ground ahead of it, the linkage will to fall nose to the ground. With more foots we make the "snooping" time shorter, and a total of four leg pairs is a minimum for this unoptimized version.

Let's have a look at the artist:

Dynamic four-leg-pair unoptimized Strider

Advice

Use the vizualisation tools provided! The optimization tools should always give you a score with a better fitness, but it might not be what you expected. Tailor your optimization and then go for a long run will make you save a lot of time.

Do not use optimized linkages from the start! The risk is to fall to quickly into a suboptimal solution. They are several mechanisms to prevent that (starting from random position), however it can always have an impact on the rest of the optimization.

Try to minimize the number of elements in the optimizations! You can often use some linkage's properties to reduce the number of simulation parameters. For instance, the Strider linkage has an axial symmetry. While it is irrelevant to use this property in dynamic simulation, you can use "half" your Strider in a kinematic optimization, which is much faster: A Kinematic half Strider

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

leggedsnake-0.1.1.tar.gz (95.9 kB view hashes)

Uploaded Source

Built Distribution

leggedsnake-0.1.1-py3-none-any.whl (90.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page