Skip to main content

Robot Locomotion & Morphology Framework — universal legged-robot API

Project description

rlmf — Robot Locomotion & Morphology Framework

PyPI Python License: MIT Tests

A universal robot body model and locomotion API.
Define any legged robot in YAML, then call robot.walk().

from rlmf import Robot

robot = Robot.load("hexapod.yaml")
robot.walk()
robot.turn_left(45)
robot.climb()
robot.follow_path([(0.5, 0), (0.5, 0.5), (0, 0.5)])

The API is identical regardless of morphology — 4-leg, 6-leg, 8-leg, 12-leg.
No gait code. No IK math. No synchronization logic. No motor coordination code.


Installation

pip install rlmf

With Raspberry Pi hardware support (PCA9685 + GPIO servos):

pip install "rlmf[pi]"

Quickstart

from rlmf import Robot
import rlmf.robots as robots

# Use a bundled robot definition
robot = Robot.load(robots.get("hexapod"))

# Or load your own YAML
robot = Robot.load("my_robot.yaml")

# Behaviours — same API for any morphology
robot.walk()
robot.turn_left(45)
robot.turn_right(30)
robot.climb()
robot.stop()
robot.follow_path([(0.5, 0.0), (0.5, 0.5)])

# Low-level access
robot.reach("leg_0", (0.20, 0.05, -0.10))   # IK to world target
robot.move_joint("leg_0.hip", 30.0)          # direct joint control

Morphology Description Language

Define any robot in YAML — the framework handles the rest:

name: HexaBot
body:
  segments: [thorax]
  length: 0.30
  width: 0.18
  height: 0.09
limbs:
  - type: leg
    count: 6
    joints:
      hip:   {min: -90, max: 90}
      knee:  {min: 0,   max: 120}
      ankle: {min: -45, max: 45}
    segment_lengths: [0.07, 0.12, 0.10]
physics:
  mass: 1.2kg

After loading, the full model is immediately introspectable:

robot.topology.family        # "hexapod"
robot.topology.limb_count    # 6
robot.topology.total_joints  # 18
robot.mass                   # 1.2
robot.limbs                  # List[Limb]
robot.joints                 # Dict[str, JointDef]

Bundled robots

import rlmf.robots as robots

robots.list_robots()          # ['centipede', 'hexapod', 'quadruped', 'spider']
path = robots.get("hexapod")  # Path to bundled hexapod.yaml

Architecture

User API          robot.walk() / robot.turn_left() / robot.climb()
     ↓
Gait Engine       TripodGait / WaveGait / RippleGait / TrotGait
     ↓
Kinematics        solve_ik() / solve_fk() per limb
     ↓
Balance Engine    support polygon · stability margin · tip risk
     ↓
Motor Layer       SimulatedDriver / PCA9685 / your hardware

Gait engine

Gait Class Best for Duty factor
tripod TripodGait hexapods, fast walking 0.50
wave WaveGait any, climbing 0.83
ripple RippleGait octopods, medium speed 0.67
trot TrotGait quadrupeds 0.50

Gait selection is automatic — robot.walk() picks the right pattern for your morphology.
Override it when needed:

from rlmf import select_gait, TrotGait

gait = select_gait("hexapod", "climb")          # → WaveGait
frames = robot.get_gait_frames("ripple", num_frames=60)

Balance engine

state = robot.balance_state()

state.center_of_mass        # (x, y, z) world space
state.support_polygon       # convex hull of stance feet
state.stability_margin      # metres to nearest polygon edge (>0 = stable)
state.is_stable             # bool
state.tip_risk              # 0.0 (safe) … 1.0 (falling)

Motor abstraction

Swap the hardware driver without touching any robot code:

from rlmf import Robot, MotorAbstractionLayer
from my_hardware import MyServoDriver       # your implementation

robot = Robot(
    Robot.load("hexapod.yaml")._model,
    motor_layer=MotorAbstractionLayer(driver=MyServoDriver()),
)
robot.walk()   # drives your hardware

Implement MotorDriver for any servo bus:

from rlmf import MotorDriver

class MyDriver(MotorDriver):
    def set_angle(self, joint_id, angle_deg, speed=1.0): ...
    def get_angle(self, joint_id) -> float: ...
    def enable(self, joint_id): ...
    def disable(self, joint_id): ...

CLI

rlmf robots                        # list bundled robots
rlmf describe hexapod              # print topology
rlmf describe path/to/mybot.yaml   # your own robot
rlmf walk hexapod --gait wave      # simulate gait, print stats
rlmf balance quadruped             # print balance state

Raspberry Pi deployment

Install with hardware extras:

pip install "rlmf[pi]"

Wire a PCA9685 to the Pi over I2C, then:

from adafruit_servokit import ServoKit
from rlmf import Robot, MotorAbstractionLayer
from rlmf.motors import MotorDriver

class PCA9685Driver(MotorDriver):
    def __init__(self):
        self._kit = ServoKit(channels=16)
        self._map = {}

    def assign(self, joint_id, channel):
        self._map[joint_id] = channel

    def set_angle(self, joint_id, angle_deg, speed=1.0):
        ch = self._map.get(joint_id)
        if ch is not None:
            self._kit.servo[ch].angle = max(0, min(180, angle_deg + 90))

    def get_angle(self, joint_id): return 0.0
    def enable(self, joint_id): pass
    def disable(self, joint_id): pass

driver = PCA9685Driver()
driver.assign("leg_0.hip", 0)
# … assign all 18 joints …

import rlmf.robots as robots
robot = Robot(
    Robot.load(robots.get("hexapod"))._model,
    motor_layer=MotorAbstractionLayer(driver=driver),
)
robot.walk()   # moves physical servos

Roadmap

  • v0.1 — Phase 1: 3–12 leg robots, four gait patterns, analytical IK, balance engine, motor abstraction
  • v0.2 — Phase 2: biped support, dynamic balance, weight shifting, fall recovery
  • v0.3 — Phase 3: arbitrary morphologies, terrain adaptation, path planning

Development

git clone https://github.com/Wafula_Ian01/rlmf
cd rlmf
pip install -e ".[dev]"
pytest

License

MIT — see LICENSE.

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

rlmf-0.1.0.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

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

rlmf-0.1.0-py3-none-any.whl (4.9 kB view details)

Uploaded Python 3

File details

Details for the file rlmf-0.1.0.tar.gz.

File metadata

  • Download URL: rlmf-0.1.0.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for rlmf-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6b6ff1c0f2473b7ff2480d22d94c4e217fbd3c0a66dc8254245e5a48d598a097
MD5 3c371c94aba3be11578c4eb9dd5d0a88
BLAKE2b-256 df3ec8ee755dcb10f504a44a074130de3b1c6bd39409fed9e9cb72981eb6cc6e

See more details on using hashes here.

File details

Details for the file rlmf-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rlmf-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 4.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for rlmf-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1a5fba8ad91f5842f8c394cbe6a3bb24d4d3382fb0ff411e3b07708c621f6464
MD5 7334ce73f0fb9a6b3ff891502bd6c165
BLAKE2b-256 0f09d90b2098047de3bbf1ca26bd77cdac47d3b28e3c2b8d21e7cca946460f61

See more details on using hashes here.

Supported by

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