leggedsnake


Nameleggedsnake JSON
Version 0.4.0 PyPI version JSON
download
home_pagehttps://hugofara.github.io/leggedsnake/
SummarySimulate and optimize planar leg mechanisms using PSO and GA
upload_time2023-06-21 08:02:12
maintainer
docs_urlNone
authorHugo Farajallah
requires_python>=3.7
licenseMIT License
keywords linkage leg mechanism optimization leggedsnake walking linkage
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # leggedsnake

[![PyPI version fury.io](https://badge.fury.io/py/leggedsnake.svg)](https://pypi.python.org/pypi/leggedsnake/)
[![Downloads](https://static.pepy.tech/personalized-badge/leggedsnake?period=total&units=international_system&left_color=grey&right_color=green&left_text=downloads)](https://pepy.tech/project/leggedsnake)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg )](https://raw.githubusercontent.com/HugoFara/leggedsnake/main/LICENSE.rst)

LeggedSnake makes the simulation of walking linkages fast and easy.
We believe that building walking linkages is fun and could be useful.
Our philosophy is to provide a quick way of building, optimizing and testing walking linkages.

## Overview

First, you will define a linkage to be optimized. 
Here we use the [strider linkage](https://www.diywalkers.com/strider-linkage-plans.html) by [Wade Wagle and Team Trotbot](https://www.diywalkers.com/).


![Dynamic four-leg-pair unoptimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20unoptimized%20strider.gif)

*Dimensions are intentionally wrong, so that the robots fails to walk properly.*

Let's take several identical linkages, and make them reproduce and evolve through many generations.
Here is how it looks:

![10 optimized striders](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Striders%20run.gif)

Finally, we will extract the best linkage, and here is our optimized model that do not fall.

![Dynamic optimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20optimized%20strider.gif)


## Installation

The package is hosted on PyPi as [leggedsnake](https://pypi.org/project/leggedsnake/), use:

```bash
pip install leggedsnake
```

## Build from source

Download this repository.

```shell
git clone https://github.com/hugofara/leggedsnake
```

### Conda Virtual Environment

We provide an [environment.yml](https://github.com/HugoFara/leggedsnake/blob/main/environment.yml) file for conda.

```shell
conda env update --file environment.yml --name leggedsnake-env
``` 
It will install the requirements in a separate environment.

### Other installation

If you are looking for a development version, check the GitHub repo under
[HugoFara/leggedsnake](https://github.com/HugoFara/leggedsnake).

## Usage

First, you define the linkage you want to use. 
The demo script is [strider.py](https://github.com/HugoFara/leggedsnake/blob/main/docs/examples/strider.py), which
demonstrates all the techniques about the [Strider linkage](https://www.diywalkers.com/strider-linkage-plans.html).

In a nutshell, the two main parts are:

1. Define a Linkage.
2. Run the optimization. 


### Defining a ``Walker``
you need to define joints for your ``Walker`` as described in [pylinkage](https://github.com/HugoFara/pylinkage)
documentation. 
You may use a dictionary, that looks like that:
```python3
import leggedsnake as ls

# Quick definition of a linkage as a dict of joints
linkage = {
    "A": ls.Static(x=0, y=0, name="A"),
    "B": ls.Crank(1, 0, distance=1, angle=0.31, name="Crank")
    # etc...
}
# Conversion to a dynamic linkage
my_walker = ls.Walker(
    joints=linkage.values(),
    name="My Walker"
)
# It is often faster to add pairs of legs this way
my_walker.add_legs(3)


# Then, run launch a GUI simulation with
ls.video(my_walker)
```
It should display something like the following.

![Dynamic four-leg-pair unoptimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20unoptimized%20strider.gif)


### Optimization using Genetic Algorithm (GA)

The next step is to optimize your linkage. We use a genetic algorithm here.

```python
# Definition of an individual as (fitness, dimensions, initial coordinates)
dna = [0, list(my_walker.get_num.constraints()), list(my_walker.get_coords())]
population = 10

def total_distance(walker):
    """
    Evaluates the final horizontal position of the input linkage.
    
    Return final distance and initial position of joints.
    """
    pos = tuple(walker.step())[-1]
    world = ls.World()
    # We handle all the conversions
    world.add_linkage(walker)
    # Simulation duration (in seconds)
    duration = 40
    steps = int(duration / ls.params["simul"]["physics_period"])
    for _ in range(steps):
        world.update()
    return world.linkages[0].body.position.x, pos


# Prepare the optimization, with any fitness_function(dna) -> score 
optimizer = ls.GeneticOptimization(
        dna=dna, 
        fitness=total_distance,
        max_pop=population,
)
# Run for 100 iterations, on 4 processes
optimized_walkers = optimizer.run(iters=100, processes=4)

# The following line will display the results
ls.all_linkages_video(optimized_walkers)
```
For 100 iterations, 10 linkages will be simulated and evaluated by fitness_function.
The fittest individuals are kept and will propagate their genes (with mutations).

Now you should see something like the following.

![10 optimized striders](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Striders%20run.gif)

This is a simulation from the last generation of 10 linkages. 
Most of them cover a larger distance (this is the target of our ``fitness_function``).

### Results

Finally, only the best linkage at index 0 may be kept.

```python
# Results are sorted by best fitness first, 
# so we use the walker with the best score
best_dna = optimized_walkers[0]

# Change the dimensions
my_walker.set_num_constraints(best_dna[1])
my_walker.set_coords(best_dna[2])

# Once again launch the video
ls.video(my_walker)
```

![Dynamic optimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20optimized%20strider.gif)

So now it has a small ski pole, does not fall and goes much farther away!

### Kinematic optimization using Particle Swarm Optimization (PSO)

You may need a kinematic optimization, depending solely on pylinkage. 
You should use the ``step`` and ``stride`` method from the
[utility module](https://github.com/HugoFara/leggedsnake/blob/main/leggedsnake/utility.py) as fitness functions.
This set of rules should work well for a stride **maximisation** problem:

1. Rebuild the Walker with the provided set of dimensions, and do a complete turn.
2. If the Walker raises an UnbuildableError, its score is 0 (or ``-float('inf')`` if you use other evaluation functions).
3. Verify if it can pass a certain obstacle using ``step`` function. If not, its score is 0.
4. Eventually measure the length of its stride with the ``stride`` function. Return this length as its score.

## Main features

We handle planar [leg mechanisms](https://en.wikipedia.org/wiki/Leg_mechanism) in three main parts:

* Linkage conception in simple Python relies on [pylinkage](https://github.com/HugoFara/pylinkage).
* *Optional* kinematic optimization with ``Walker`` class, inherits from pylinkage's ``Linkage`` class.
* Dynamic simulation and its optimization use genetic algorithms.

## Advice

Use the visualisation 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), but 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 properties to reduce the
number of simulation parameters. For instance, the Strider linkage has 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](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Kinematic%20half-Strider.gif)

## Contribute

This project is open to contribution and actively looking for contributors.
You can help making it better!

### For everyone

You can [drop a star](https://github.com/HugoFara/leggedsnake/stargazers),
[fork this project](https://github.com/HugoFara/leggedsnake/forks) or simply share the link to your best media.

The more people get engaged into this project, the better it will develop!

### For developers

You can follow the guide at [CONTRIBUTING.md](CONTRIBUTING.md). Feel free to me any pull request.

## Quick links

* For the documentation, check the docs at [hugofara.github.io/leggedsnake](https://hugofara.github.io/leggedsnake/)!
* Source code is hosted on GitHub as [HugoFara/leggedsnake](https://github.com/HugoFara/leggedsnake)
* We also provide a Python package on PyPi, test [leggedsnake](https://pypi.org/project/leggedsnake/).
* If you just want to chill out looking at walking linkages striving to survive, join the [discussions](https://github.com/HugoFara/leggedsnake/discussions).

Contributors are welcome!

            

Raw data

            {
    "_id": null,
    "home_page": "https://hugofara.github.io/leggedsnake/",
    "name": "leggedsnake",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "linkage,leg mechanism,optimization,leggedsnake,walking linkage",
    "author": "Hugo Farajallah",
    "author_email": "Hugo Farajallah <leggedsnake@hugofara.net>",
    "download_url": "https://files.pythonhosted.org/packages/7f/da/3d58ebce705b1dceab8c5ac8c3b17babec4357f278c4db97379886dd206c/leggedsnake-0.4.0.tar.gz",
    "platform": null,
    "description": "# leggedsnake\n\n[![PyPI version fury.io](https://badge.fury.io/py/leggedsnake.svg)](https://pypi.python.org/pypi/leggedsnake/)\n[![Downloads](https://static.pepy.tech/personalized-badge/leggedsnake?period=total&units=international_system&left_color=grey&right_color=green&left_text=downloads)](https://pepy.tech/project/leggedsnake)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg )](https://raw.githubusercontent.com/HugoFara/leggedsnake/main/LICENSE.rst)\n\nLeggedSnake makes the simulation of walking linkages fast and easy.\nWe believe that building walking linkages is fun and could be useful.\nOur philosophy is to provide a quick way of building, optimizing and testing walking linkages.\n\n## Overview\n\nFirst, you will define a linkage to be optimized. \nHere we use the [strider linkage](https://www.diywalkers.com/strider-linkage-plans.html) by [Wade Wagle and Team Trotbot](https://www.diywalkers.com/).\n\n\n![Dynamic four-leg-pair unoptimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20unoptimized%20strider.gif)\n\n*Dimensions are intentionally wrong, so that the robots fails to walk properly.*\n\nLet's take several identical linkages, and make them reproduce and evolve through many generations.\nHere is how it looks:\n\n![10 optimized striders](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Striders%20run.gif)\n\nFinally, we will extract the best linkage, and here is our optimized model that do not fall.\n\n![Dynamic optimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20optimized%20strider.gif)\n\n\n## Installation\n\nThe package is hosted on PyPi as [leggedsnake](https://pypi.org/project/leggedsnake/), use:\n\n```bash\npip install leggedsnake\n```\n\n## Build from source\n\nDownload this repository.\n\n```shell\ngit clone https://github.com/hugofara/leggedsnake\n```\n\n### Conda Virtual Environment\n\nWe provide an [environment.yml](https://github.com/HugoFara/leggedsnake/blob/main/environment.yml) file for conda.\n\n```shell\nconda env update --file environment.yml --name leggedsnake-env\n``` \nIt will install the requirements in a separate environment.\n\n### Other installation\n\nIf you are looking for a development version, check the GitHub repo under\n[HugoFara/leggedsnake](https://github.com/HugoFara/leggedsnake).\n\n## Usage\n\nFirst, you define the linkage you want to use. \nThe demo script is [strider.py](https://github.com/HugoFara/leggedsnake/blob/main/docs/examples/strider.py), which\ndemonstrates all the techniques about the [Strider linkage](https://www.diywalkers.com/strider-linkage-plans.html).\n\nIn a nutshell, the two main parts are:\n\n1. Define a Linkage.\n2. Run the optimization. \n\n\n### Defining a ``Walker``\nyou need to define joints for your ``Walker`` as described in [pylinkage](https://github.com/HugoFara/pylinkage)\ndocumentation. \nYou may use a dictionary, that looks like that:\n```python3\nimport leggedsnake as ls\n\n# Quick definition of a linkage as a dict of joints\nlinkage = {\n    \"A\": ls.Static(x=0, y=0, name=\"A\"),\n    \"B\": ls.Crank(1, 0, distance=1, angle=0.31, name=\"Crank\")\n    # etc...\n}\n# Conversion to a dynamic linkage\nmy_walker = ls.Walker(\n    joints=linkage.values(),\n    name=\"My Walker\"\n)\n# It is often faster to add pairs of legs this way\nmy_walker.add_legs(3)\n\n\n# Then, run launch a GUI simulation with\nls.video(my_walker)\n```\nIt should display something like the following.\n\n![Dynamic four-leg-pair unoptimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20unoptimized%20strider.gif)\n\n\n### Optimization using Genetic Algorithm (GA)\n\nThe next step is to optimize your linkage. We use a genetic algorithm here.\n\n```python\n# Definition of an individual as (fitness, dimensions, initial coordinates)\ndna = [0, list(my_walker.get_num.constraints()), list(my_walker.get_coords())]\npopulation = 10\n\ndef total_distance(walker):\n    \"\"\"\n    Evaluates the final horizontal position of the input linkage.\n    \n    Return final distance and initial position of joints.\n    \"\"\"\n    pos = tuple(walker.step())[-1]\n    world = ls.World()\n    # We handle all the conversions\n    world.add_linkage(walker)\n    # Simulation duration (in seconds)\n    duration = 40\n    steps = int(duration / ls.params[\"simul\"][\"physics_period\"])\n    for _ in range(steps):\n        world.update()\n    return world.linkages[0].body.position.x, pos\n\n\n# Prepare the optimization, with any fitness_function(dna) -> score \noptimizer = ls.GeneticOptimization(\n        dna=dna, \n        fitness=total_distance,\n        max_pop=population,\n)\n# Run for 100 iterations, on 4 processes\noptimized_walkers = optimizer.run(iters=100, processes=4)\n\n# The following line will display the results\nls.all_linkages_video(optimized_walkers)\n```\nFor 100 iterations, 10 linkages will be simulated and evaluated by fitness_function.\nThe fittest individuals are kept and will propagate their genes (with mutations).\n\nNow you should see something like the following.\n\n![10 optimized striders](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Striders%20run.gif)\n\nThis is a simulation from the last generation of 10 linkages. \nMost of them cover a larger distance (this is the target of our ``fitness_function``).\n\n### Results\n\nFinally, only the best linkage at index 0 may be kept.\n\n```python\n# Results are sorted by best fitness first, \n# so we use the walker with the best score\nbest_dna = optimized_walkers[0]\n\n# Change the dimensions\nmy_walker.set_num_constraints(best_dna[1])\nmy_walker.set_coords(best_dna[2])\n\n# Once again launch the video\nls.video(my_walker)\n```\n\n![Dynamic optimized Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Dynamic%20optimized%20strider.gif)\n\nSo now it has a small ski pole, does not fall and goes much farther away!\n\n### Kinematic optimization using Particle Swarm Optimization (PSO)\n\nYou may need a kinematic optimization, depending solely on pylinkage. \nYou should use the ``step`` and ``stride`` method from the\n[utility module](https://github.com/HugoFara/leggedsnake/blob/main/leggedsnake/utility.py) as fitness functions.\nThis set of rules should work well for a stride **maximisation** problem:\n\n1. Rebuild the Walker with the provided set of dimensions, and do a complete turn.\n2. If the Walker raises an UnbuildableError, its score is 0 (or ``-float('inf')`` if you use other evaluation functions).\n3. Verify if it can pass a certain obstacle using ``step`` function. If not, its score is 0.\n4. Eventually measure the length of its stride with the ``stride`` function. Return this length as its score.\n\n## Main features\n\nWe handle planar [leg mechanisms](https://en.wikipedia.org/wiki/Leg_mechanism) in three main parts:\n\n* Linkage conception in simple Python relies on [pylinkage](https://github.com/HugoFara/pylinkage).\n* *Optional* kinematic optimization with ``Walker`` class, inherits from pylinkage's ``Linkage`` class.\n* Dynamic simulation and its optimization use genetic algorithms.\n\n## Advice\n\nUse the visualisation tools provided! The optimization tools should always give you a score with a better fitness,\nbut it might not be what you expected. Tailor your optimization and *then* go for a long run will make you save a lot\nof time.\n\n**Do not** use optimized linkages from the start! The risk is to fall to quickly into a suboptimal solution. They are\nseveral mechanisms to prevent that (starting from random position), but it can always have an impact on the rest of\nthe optimization.\n\nTry to minimize the number of elements in the optimizations! You can often use some linkage properties to reduce the\nnumber of simulation parameters. For instance, the Strider linkage has axial symmetry. While it is irrelevant to use\nthis property in dynamic simulation, you can use \"half\" your Strider in a kinematic optimization, which is much faster.\n\n![A Kinematic half Strider](https://github.com/HugoFara/leggedsnake/raw/main/docs/examples/images/Kinematic%20half-Strider.gif)\n\n## Contribute\n\nThis project is open to contribution and actively looking for contributors.\nYou can help making it better!\n\n### For everyone\n\nYou can [drop a star](https://github.com/HugoFara/leggedsnake/stargazers),\n[fork this project](https://github.com/HugoFara/leggedsnake/forks) or simply share the link to your best media.\n\nThe more people get engaged into this project, the better it will develop!\n\n### For developers\n\nYou can follow the guide at [CONTRIBUTING.md](CONTRIBUTING.md). Feel free to me any pull request.\n\n## Quick links\n\n* For the documentation, check the docs at [hugofara.github.io/leggedsnake](https://hugofara.github.io/leggedsnake/)!\n* Source code is hosted on GitHub as [HugoFara/leggedsnake](https://github.com/HugoFara/leggedsnake)\n* We also provide a Python package on PyPi, test [leggedsnake](https://pypi.org/project/leggedsnake/).\n* If you just want to chill out looking at walking linkages striving to survive, join the [discussions](https://github.com/HugoFara/leggedsnake/discussions).\n\nContributors are welcome!\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "Simulate and optimize planar leg mechanisms using PSO and GA",
    "version": "0.4.0",
    "project_urls": {
        "Changelog": "https://github.com/me/spam/blob/master/CHANGELOG.md",
        "Documentation": "https://github.com/HugoFara/leggedsnake/blob/main/CHANGELOG.md",
        "Homepage": "https://hugofara.net/leggedsnake-retro-ingeneering-evolution/",
        "Repository": "https://github.com/HugoFara/leggedsnake"
    },
    "split_keywords": [
        "linkage",
        "leg mechanism",
        "optimization",
        "leggedsnake",
        "walking linkage"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e240a88c58bdd6765ebebefaec30ed4d9cf8ddc3fd838d780490628da003c35d",
                "md5": "cff89a0c87535abce145f5e55809fa51",
                "sha256": "5859be416dd1eb88c545e3d8d1cf70a1ce6735f33f9dab517b32ca5561abcfdb"
            },
            "downloads": -1,
            "filename": "leggedsnake-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cff89a0c87535abce145f5e55809fa51",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 27987,
            "upload_time": "2023-06-21T08:02:09",
            "upload_time_iso_8601": "2023-06-21T08:02:09.807167Z",
            "url": "https://files.pythonhosted.org/packages/e2/40/a88c58bdd6765ebebefaec30ed4d9cf8ddc3fd838d780490628da003c35d/leggedsnake-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7fda3d58ebce705b1dceab8c5ac8c3b17babec4357f278c4db97379886dd206c",
                "md5": "24c96405a50b8527f84367f4022994e6",
                "sha256": "b0e398959f381d383336c034d8f8a53df9caa32808d7714cf2b7817fa3246475"
            },
            "downloads": -1,
            "filename": "leggedsnake-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "24c96405a50b8527f84367f4022994e6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 61458,
            "upload_time": "2023-06-21T08:02:12",
            "upload_time_iso_8601": "2023-06-21T08:02:12.064229Z",
            "url": "https://files.pythonhosted.org/packages/7f/da/3d58ebce705b1dceab8c5ac8c3b17babec4357f278c4db97379886dd206c/leggedsnake-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-21 08:02:12",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "me",
    "github_project": "spam",
    "github_not_found": true,
    "lcname": "leggedsnake"
}
        
Elapsed time: 2.85678s