Skip to main content

moro

PyPI version License

moro is a Python library for symbolic modeling, analysis, numerical simulation, and visualization of serial robot manipulators.

It is designed primarily for robotics education and for workflows where inspecting the underlying kinematic and dynamic expressions is as important as evaluating them numerically.

Features

  • Robot modeling: Define serial manipulators with revolute and prismatic joints using Denavit-Hartenberg parameters.
  • Transformations: Work with SO(3) rotations, SE(3) homogeneous transformations, Euler/Tait-Bryan angles, axis-angle, quaternions, and rotation vectors.
  • Forward kinematics: Compute symbolic end-effector and intermediate-frame transformations.
  • Differential kinematics: Evaluate task Jacobians, Cartesian velocities, velocity IK, singular values, numerical rank, condition number, and manipulability.
  • Inverse kinematics: Solve numerical Cartesian position IK and full-pose IK with Jacobian-based methods; position-only CCD remains available.
  • Trajectory generation: Generate linear, cubic, and quintic point-to-point trajectories in joint or Cartesian position space.
  • Dynamics: Derive symbolic equations of motion, evaluate inverse/forward dynamics numerically, and integrate motion with solve_ivp.
  • Workspace sampling: Approximate reachable Cartesian workspace from finite joint ranges with reproducible joint-space sampling.
  • Visualization: Plot and animate robot configurations using Matplotlib or Three.js, and plot sampled workspaces with Matplotlib.

Installation

Install the latest stable release from PyPI:

pip install moro

To install the current development version from GitHub:

pip install git+https://github.com/JorgeDeLosSantos/moro.git@develop

Moro requires Python 3.11 or newer.

Its main runtime dependencies are SymPy, NumPy, Matplotlib, SciPy, and IPython (for Three.js HTML output).

Quick Start

The following example creates a symbolic planar 2R manipulator and evaluates its forward kinematics and Jacobian at one configuration:

from moro import Robot
from moro.abc import q1, q2, l1, l2

robot = Robot(
    (l1, 0, 0, q1, "r"),
    (l2, 0, 0, q2, "r"),
)

T = robot.T
J = robot.J

values = {
    l1: 1.0,
    l2: 1.0,
    q1: 0.5,
    q2: 0.8,
}

T_num = T.subs(values).evalf()
J_num = J.subs(values).evalf()

The same symbolic model can be visualized:

from moro.visualization import RobotVisualizer

viz = RobotVisualizer(robot)
viz.plot(values)  # interactive Three.js viewer (Jupyter / Colab)

Three.js is the default for plotting and animating configurations. When you need a Matplotlib figure or animation, select it explicitly:

fig, ax = viz.plot(values, backend="matplotlib")

With the default VisualizationStyle(), Three.js displays revolute cylinders and prismatic boxes when the robot's joint metadata is available; Matplotlib retains simple spherical markers. The interactive HTML viewer loads Three.js resources in the browser, so it needs access to its CDN.

Inverse Kinematics

Position IK:

from moro.inverse_kinematics import solve_position_ik

solution = solve_position_ik(
    robot,
    [1.5, 0.5, 0.0],
    q0=[0.1, 0.1],
    parameters={l1: 1.0, l2: 1.0},
)

Full-pose IK is available through:

from moro.inverse_kinematics import solve_pose_ik

solution = solve_pose_ik(
    robot,
    target_transform,
    q0=initial_guess,
    parameters=parameters,
)

Trajectories

Generate a smooth joint-space trajectory with:

import numpy as np
from moro.trajectory import joint_trajectory

traj = joint_trajectory(
    [0.0, 0.0],
    [0.8, -0.4],
    np.linspace(0.0, 2.0, 101),
    method="quintic",
)

The result uses time-major arrays such as traj.q.shape == (N, dof) and can be passed directly to RobotVisualizer.animate().

Dynamics and Simulation

After assigning masses, centers of mass, inertia tensors, and gravity, the symbolic manipulator equation is obtained with:

model = robot.dynamic_model()

In Moro 0.5.0, dynamic_model() returns the matrix-form equation

M(q) qdd + C(q, qd) qd + G(q) = tau

The former per-joint Euler-Lagrange behavior is available as:

equations = robot.euler_lagrange_equations()

Numerical dynamics and simulation live in moro.dynamics:

from moro.dynamics import inverse_dynamics, forward_dynamics, simulate

forces = inverse_dynamics(robot, q, qd, qdd, parameters=parameters)
acceleration = forward_dynamics(robot, q, qd, forces, parameters=parameters)

solution = simulate(
    robot,
    (0.0, 2.0),
    q0,
    qd0=qd0,
    tau=controller,
    parameters=parameters,
)

Workspace Sampling

from moro.workspace import sample_workspace
from moro.visualization import plot_workspace

workspace = sample_workspace(robot, samples=5000, seed=42)
fig, ax = plot_workspace(workspace)

Workspace samples are uniform in joint coordinates, not Cartesian space. The result stores both workspace.configurations and their corresponding Cartesian workspace.points.

Documentation

The complete documentation is available at:

https://jorgedelossantos.github.io/moro/

It includes Getting Started guides, User Guide, worked examples, API Reference, mathematical Theory notes, and contributor documentation.

Roadmap

Want to know what may come next? See the Moro Roadmap Wiki.

Bug Reports and Contributions

If you encounter a bug, have a question, or want to request a feature, please open an issue in the GitHub Issue Tracker.

Contributions are welcome. See the contributor documentation included in the project documentation for the recommended development workflow.

Metadata

Release files for moro 0.6.0

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

Source distribution (sdist)

Source distribution for moro 0.6.0
File Size Uploaded Provenance Actions
moro-0.6.0.tar.gz 150.0 kB With provenance Details for moro-0.6.0.tar.gz

Built distribution (wheel)

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

Total release size: 252.1 kB

Release files / moro-0.6.0.tar.gz

Download URL moro-0.6.0.tar.gz
Size 150.0 kB
Tags Source
SHA-256 checksum
How to use checksums
6bc7af05ef54f8b4dcd00440614212993b22042d2007c15e3ef57374445be504
BLAKE2b-256 checksum
How to use checksums
aafd8acad052c777e8b7c9f19d1c108ba913d3fcd61dde5f8cc087abd58eac02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / moro-0.6.0-py3-none-any.whl

Download URL moro-0.6.0-py3-none-any.whl
Size 102.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
02eb5ee911f9c63ab98edb4ee53a7e99d500d54233d86c8fd9c58c6f41969494
BLAKE2b-256 checksum
How to use checksums
caa1602746a6470e9ce12b60806015daf9eee14d0664074b780941c58aaf7b8a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for moro 0.6.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for moro-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

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