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.1.tar.gz (178.2 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.1-py3-none-any.whl (125.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: leggedsnake-0.6.1.tar.gz
  • Upload date:
  • Size: 178.2 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.1.tar.gz
Algorithm Hash digest
SHA256 b9dd82201b4598eab7c9a7a2adfeaa77e1aef788699ec0b1cb405b126aeba0c9
MD5 6366c4d9dbc3cb520f703dba46a95b13
BLAKE2b-256 078c27609929d7d6a1701a3dcede5b62f6ea1900ab58443fad6a8dd4541a460c

See more details on using hashes here.

File details

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

File metadata

  • Download URL: leggedsnake-0.6.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b4cddfc354e71877cf9d104465248898f6a268c8a8e7f08f114d278cef8770d1
MD5 5b083bc1171e024965da44de57bc9b89
BLAKE2b-256 fcb2a63ab001407f51a4fb7dded52630979edb08c8b6c7839bfb5595c851a947

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.6.1 This release

2 files

0.6.0

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