Planar 2R Manipulator
This example introduces a complete kinematic workflow with moro using a simple planar two-link manipulator.
We will:
define the robot from its Denavit-Hartenberg parameters;
compute its forward kinematics;
extract the end-effector position;
compute the geometric Jacobian;
evaluate the symbolic expressions at a numerical configuration;
visualize the resulting robot pose.
The goal is not to derive the equations manually, but to show how the main kinematic tools in moro fit together in a typical analysis workflow.
Problem
Consider a planar manipulator composed of two revolute joints and two rigid links.
Let
be the joint variables, and
the link lengths.
The robot moves entirely in the (xy)-plane, while all joint rotation axes are parallel to the (z)-axis.
Using the classical Denavit-Hartenberg convention, the robot can be described by:
Link |
(a_i) |
(\alpha_i) |
(d_i) |
(\theta_i) |
Joint |
|---|---|---|---|---|---|
1 |
(l_1) |
(0) |
(0) |
(q_1) |
revolute |
2 |
(l_2) |
(0) |
(0) |
(q_2) |
revolute |
We want to obtain the symbolic kinematics of the manipulator and then evaluate them for a specific configuration.
Robot model
First import the required objects:
from moro import Robot
from moro.abc import q1, q2, l1, l2
The robot is created by passing one DH row per joint:
robot = Robot(
(l1, 0, 0, q1, "r"),
(l2, 0, 0, q2, "r"),
)
The resulting model can be inspected directly:
robot
which returns:
Robot RR
The number of degrees of freedom is:
robot.dof
which returns:
2
The joint variables used by the model are available through:
robot.qs
The DH table can also be inspected with:
robot.dh_table
At this point, the model is fully symbolic. No numerical values have been assigned to the link lengths or joint variables.
Forward kinematics
The complete homogeneous transformation of the end-effector with respect to the base frame is available through:
T = robot.T
T
For this planar 2R manipulator, the transformation has the structure
The transformation of each intermediate frame can also be obtained individually:
T10 = robot.T_i0(1)
T20 = robot.T_i0(2)
Since frame {2} is the end-effector frame,
T20 == robot.T
evaluates to True.
Accessing intermediate transformations is useful when the position or orientation of a specific link frame is also required.
End-effector position
The Cartesian position of the end-effector corresponds to the translation part of the homogeneous transformation:
p = robot.T[:3, 3]
p
For this robot,
The zero third component reflects the fact that the manipulator is planar.
Because this expression remains symbolic, it can be evaluated repeatedly for different geometric parameters and joint configurations without rebuilding the robot model.
Jacobian matrix
The geometric Jacobian of the end-effector is available through:
J = robot.J
J
For a two-degree-of-freedom robot, the result is a (6\times2) matrix.
The first three rows correspond to the linear velocity Jacobian:
Jv = J[:3, :]
Jv
and the last three rows correspond to the angular velocity Jacobian:
Jw = J[3:, :]
Jw
For the planar 2R manipulator, the linear part is
while the angular part is
The Jacobian relates joint velocities to the end-effector linear and angular velocities:
For this mechanism, all angular motion occurs about the (z)-axis.
Numerical evaluation
Now consider the numerical values
and the joint configuration
Create a substitution dictionary:
from sympy import pi
values = {
l1: 1.0,
l2: 0.8,
q1: pi / 4,
q2: -pi / 6,
}
The end-effector transformation can now be evaluated numerically:
T_num = robot.T.subs(values).evalf()
T_num
The corresponding Cartesian position is:
p_num = p.subs(values).evalf()
p_num
Likewise, the Jacobian at the same configuration is:
J_num = robot.J.subs(values).evalf()
J_num
The same symbolic expressions can therefore be reused for any other configuration simply by changing the substitution dictionary.
For example:
another_configuration = {
l1: 1.0,
l2: 0.8,
q1: 0,
q2: pi / 2,
}
robot.T.subs(another_configuration).evalf()
No new Robot instance is required.
Visualization
The same numerical values used in the kinematic evaluation can also be passed directly to the visualization tools.
Create a RobotVisualizer:
from moro.visualization import RobotVisualizer
viz = RobotVisualizer(robot)
Matplotlib
A static Matplotlib visualization can be created with:
fig, ax = viz.plot(
values,
backend="matplotlib",
)
If running in a standard Python script, the figure can be displayed with:
import matplotlib.pyplot as plt
plt.show()
The generated scene includes the robot links, joints, and coordinate frames.
Three.js
For an interactive visualization in a notebook:
viz.plot(
values,
backend="threejs",
)
The Three.js viewer allows the robot to be inspected interactively using orbit controls and includes preset front, top, and isometric views.
Since the robot model is symbolic, the same visualizer can be reused with different configurations:
viz.plot(
{
l1: 1.0,
l2: 0.8,
q1: pi / 2,
q2: -pi / 3,
},
backend="threejs",
)
Discussion
This simple example illustrates the central workflow used throughout moro.
A single symbolic Robot model provides access to both forward and differential kinematics:
robot.T
robot.J
The same model can then be evaluated numerically through standard SymPy substitutions:
robot.T.subs(values)
robot.J.subs(values)
and the same substitution dictionary can be reused by the visualization system:
viz.plot(values)
This separation between symbolic modeling and numerical evaluation is particularly useful in robotics education and analysis. The robot equations can be derived once and then explored at many different parameter values and configurations.
The planar 2R manipulator is intentionally simple, but the workflow remains essentially the same for larger serial manipulators:
define the robot
↓
compute symbolic kinematics
↓
compute differential kinematics
↓
evaluate a configuration
↓
visualize the result
More advanced examples will extend this workflow to spatial manipulators, numerical inverse kinematics, Cartesian trajectories, and dynamic modeling.
See also
User Guide → Robot Modeling — creating serial robot models with DH parameters.
User Guide → Forward Kinematics — frame transformations and Cartesian poses.
User Guide → Jacobians — geometric Jacobians and point Jacobians.
User Guide → Visualization — static plots and robot animations.
Theory → Forward Kinematics — mathematical background.
Theory → Differential Kinematics — Jacobian theory and velocity relationships.