Skip to main content

leggedsnake

PyPI version fury.io Downloads License: MIT

LeggedSnake is a Python toolkit for designing, simulating, and optimizing planar walking linkages. It layers a pymunk physics engine and multi-objective optimizers on top of pylinkage's kinematic model, so you can go from a mechanism sketch to an evolved walker in a few lines of code.

Strider optimized over 10 generations

One Strider mechanism optimized over 10 generations of a genetic algorithm, rendered walking on flat ground with 4 phase-offset legs (2 per side, mirrored).

Installation

From PyPI:

pip install leggedsnake

From source with uv:

git clone https://github.com/hugofara/leggedsnake
cd leggedsnake
uv sync

Quick start

A walker in five lines — the canonical Theo Jansen "Strandbeest" built from the Holy Numbers, mirrored left/right and cloned into four phase-offset pairs for stance stability, rendered in a live pyglet window:

import leggedsnake as ls

walker = ls.Walker.from_jansen(scale=0.1)
walker.add_opposite_leg()            # mirror for left/right pair
walker.add_legs(3)                   # 4 legs per side → 8-leg Strandbeest
ls.video(walker, duration=10)        # live simulation

Theo Jansen Strandbeest walking

Fewer legs pitch 10–20° and can tip over; four legs per side keeps at least two feet in stance at every crank angle, which is why real Strandbeests have many legs.

Other classical mechanisms ship as one-line factories too: Walker.from_strider, Walker.from_klann, Walker.from_chebyshev, Walker.from_watt, and Walker.from_catalog (pylinkage's topology catalog).

If you know the foot path you want rather than the mechanism, let pylinkage synthesize one and hand the result straight to Walker.from_synthesis:

from pylinkage.synthesis import path_generation

result = path_generation(
    precision_points=[(0, -3), (2, -3), (1, -1)],   # flat stance, arched swing
    max_solutions=10,
)
walker = ls.Walker.from_synthesis(result)           # index= picks a candidate

To build a custom mechanism, declare its topology (nodes + edges) and dimensions separately:

from math import tau
import leggedsnake as ls
from leggedsnake import (
    HypergraphLinkage, Node, Edge, NodeRole,
    Dimensions, DriverAngle, Walker,
)

hg = HypergraphLinkage(name="MyWalker")
for node_id, role in [
    ("frame", NodeRole.GROUND), ("frame2", NodeRole.GROUND),
    ("crank", NodeRole.DRIVER),
    ("upper", NodeRole.DRIVEN), ("foot", NodeRole.DRIVEN),
]:
    hg.add_node(Node(node_id, role=role))
for edge in [
    ("frame_crank", "frame", "crank"), ("frame2_upper", "frame2", "upper"),
    ("crank_upper", "crank", "upper"),
    ("crank_foot", "crank", "foot"), ("upper_foot", "upper", "foot"),
]:
    hg.add_edge(Edge(*edge))

dims = Dimensions(
    node_positions={
        "frame": (0, 0), "frame2": (2, 0),
        "crank": (1, 0), "upper": (1, 2), "foot": (1, 3),
    },
    edge_distances={
        "frame_crank": 1.0, "frame2_upper": 2.24,
        "crank_upper": 2.0, "crank_foot": 3.16, "upper_foot": 1.0,
    },
    driver_angles={"crank": DriverAngle(angular_velocity=-tau / 12)},
)

walker = Walker(hg, dims, name="My Walker")
walker.add_opposite_leg(axis_x=1.0)  # mirror for left/right pair
walker.add_legs(1)                   # add a phase-offset copy
ls.video(walker)

What you can do with it

Capability Entry points
Build mechanisms Walker, HypergraphLinkage, Walker.from_strider/jansen/klann/chebyshev/watt/catalog
Kinematic fitness leggedsnake.utility.stride, leggedsnake.utility.step
Physics simulation World, video, all_linkages_video, video_debug
Dynamic fitness DistanceFitness, EfficiencyFitness, StrideFitness, StabilityFitness, CompositeFitness
Single-objective GA GeneticOptimization, genetic_algorithm_optimization
Multi-objective (NSGA) nsga_walking_optimization, NsgaWalkingConfig
Topology co-design topology_walking_optimization, optimize_walking_mechanism
Gait & stability analyze_gait, StabilityTimeSeries, compute_tip_over_margin
Export to_urdf (ROS), save_walker (JSON), save_walker_svg
Plotting plot_pareto_front, plot_gait_diagram, plot_foot_trajectories, plot_optimization_dashboard

Documentation

  • Concepts guide — orientation to the three core ideas: topology + dimensions = walker, the DynamicFitness protocol, and the optimizer landscape from fast-kinematic to dynamic-multi-objective.
  • paramsWorldConfig migration guide — for code written against the legacy global params dict.
  • Full API reference — modules grouped by capability (Mechanism, Physics, Evaluation, Optimization, I/O & Plotting).

Tutorials and deeper examples

Start with the numbered notebooks — they walk through the full pipeline end to end:

  1. examples/01_walkers_gallery.ipynb — build and inspect the classical linkages.
  2. examples/02_physics_and_fitness.ipynb — physics simulation and fitness evaluation.
  3. examples/03_genetic_optimization.ipynb — evolve a walker with the genetic algorithm.
  4. examples/04_multi_objective_and_gait.ipynb — NSGA Pareto fronts plus gait / stability analysis.
  5. examples/05_topology_co_optimization.ipynb — topology + dimensions co-optimization, plus the Phase 8.3 evolve_offsets chromosome that co-evolves gait pattern alongside structure and geometry.
  6. examples/06_export_and_share.ipynb — JSON serialization, URDF export for ROS / Gazebo, SVG snapshots, and interactive plotly visualization.

The examples/tools/ directory holds maintenance scripts, not tutorials: verify_mechanisms.py renders foot-trajectory plots for every classical builder (Walker.from_jansen / from_klann / from_chebyshev) as a smoke test, and generate_readme_gifs.py regenerates the two animated GIFs above deterministically via matplotlib PillowWriter (headless).

Tips for faster experiments

  • Visualize early and often. Every optimizer will hand you a linkage with a better score; only the animation tells you whether it walks the way you wanted.
  • Don't start from a hand-tuned optimum. A random starting population is more robust against collapsing into a nearby suboptimum.
  • Exploit symmetry. A Strider half-leg has the same kinematic stride as the full mechanism and evaluates an order of magnitude faster. Use kinematic PSO on the reduced problem, then hand off the winner to a dynamic GA on the full mechanism. Kinematic half Strider
  • Checkpoint long runs. GeneticOptimization(..., startnstop="run.json") resumes automatically on the next launch.
  • Wrap optimization scripts in if __name__ == "__main__": — the GA and NSGA optimizers spawn worker processes.

Contributing

Contributions, feature requests, and "look at this weird walker" submissions are all welcome. See CONTRIBUTING.md for the developer workflow, or drop by the GitHub discussions. A star or a link to your favourite walker also helps.

Quick links

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.6.0.tar.gz (177.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

leggedsnake-0.6.0-py3-none-any.whl (125.2 kB view details)

Uploaded Python 3

File details

Details for the file leggedsnake-0.6.0.tar.gz.

File metadata

  • Download URL: leggedsnake-0.6.0.tar.gz
  • Upload date:
  • Size: 177.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for leggedsnake-0.6.0.tar.gz
Algorithm Hash digest
SHA256 f70dc1c0fd72dff082c4ddeb47210155a3d5d9f515e11fad761fda38bf891fcb
MD5 7070cbe99fb4a1bae1494bf2fe3ca626
BLAKE2b-256 4f4ab51a3053ec48dbdbd166f7631210a4b87c709206ee75d91b44bca20ea30f

See more details on using hashes here.

File details

Details for the file leggedsnake-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: leggedsnake-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 125.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for leggedsnake-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c0fbc7037a5667f56ea39314c6501e4b9b1dad1c061205a72d23ffb82dd1df6a
MD5 24fb27b8bbb439d17b07a4aa2fa81d16
BLAKE2b-256 07c270f5e288e4193339463eec38ea2f979c390cdd7294325db537b1abf7ea24

See more details on using hashes here.

Release history Release notifications | RSS feed

0.6.1

2 files

This release

0.6.0 This release

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page