Robot Locomotion & Morphology Framework — universal legged-robot API
Project description
rlmf — Robot Locomotion & Morphology Framework
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b6ff1c0f2473b7ff2480d22d94c4e217fbd3c0a66dc8254245e5a48d598a097
|
|
| MD5 |
3c371c94aba3be11578c4eb9dd5d0a88
|
|
| BLAKE2b-256 |
df3ec8ee755dcb10f504a44a074130de3b1c6bd39409fed9e9cb72981eb6cc6e
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a5fba8ad91f5842f8c394cbe6a3bb24d4d3382fb0ff411e3b07708c621f6464
|
|
| MD5 |
7334ce73f0fb9a6b3ff891502bd6c165
|
|
| BLAKE2b-256 |
0f09d90b2098047de3bbf1ca26bd77cdac47d3b28e3c2b8d21e7cca946460f61
|