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.
  • params → WorldConfig 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.

Metadata

Release files for leggedsnake 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for leggedsnake 0.6.1
File Size Uploaded Provenance Actions
leggedsnake-0.6.1.tar.gz 178.2 kB Without provenance Details for leggedsnake-0.6.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for leggedsnake 0.6.1
File Interpreter ABI Platform Actions
leggedsnake-0.6.1-py3-none-any.whl Python 3 none any Details for leggedsnake-0.6.1-py3-none-any.whl

Total release size: 303.4 kB

Release files / leggedsnake-0.6.1.tar.gz

Download URL leggedsnake-0.6.1.tar.gz
Size 178.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b9dd82201b4598eab7c9a7a2adfeaa77e1aef788699ec0b1cb405b126aeba0c9
BLAKE2b-256 checksum
How to use checksums
078c27609929d7d6a1701a3dcede5b62f6ea1900ab58443fad6a8dd4541a460c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / leggedsnake-0.6.1-py3-none-any.whl

Download URL leggedsnake-0.6.1-py3-none-any.whl
Size 125.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b4cddfc354e71877cf9d104465248898f6a268c8a8e7f08f114d278cef8770d1
BLAKE2b-256 checksum
How to use checksums
fcb2a63ab001407f51a4fb7dded52630979edb08c8b6c7839bfb5595c851a947
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for leggedsnake 0.6.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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