A Python simulation and visualization project for a 3-DOF, two-link manipulator with a fixed base in 3D space. The arm executes a simple pick-and-place loop using an analytic inverse kinematics solver and a linear end-effector trajectory.
- Joint 0 (base): revolute yaw about the +Z axis at the origin
(0,0,0). - Joints 1–2 (links): revolute pitch angles defining motion in the arm’s vertical plane (relative to the X–Y plane).
- IK: reduces the 3D target to a 2D planar problem in
(r,z), solves with the law of cosines, and supports elbow-up / elbow-down branches. - Visualization: rendered with raylib (Python bindings), including an overlay panel, editable start/goal inputs, and a suction-tool “ball” pick-and-place animation.
Runtime: Python • Rendering: raylib • IK: Closed-form
- About this repository
- Repository structure
- Robotics: kinematics, dynamics, and inverse kinematics
- Installing dependencies
- Running the simulator
- Repository file guide (full explanation)
- Simulation video
- Troubleshooting
This project simulates a 3-DOF, two-link manipulator mounted on a fixed base at the origin:
- The base joint rotates around the Z axis (yaw).
- The two link joints rotate as pitch angles (relative to the X–Y plane) in the arm’s vertical plane.
- The end-effector (EE) tracks a sequence of target points with analytic inverse kinematics.
- A small “ball” is used to visualize a pick-and-place loop:
- HOME → START
- PICK at START (attach ball)
- START → GOAL
- PLACE at GOAL (detach ball)
- GOAL → HOME
- wait briefly and repeat
User inputs (via the overlay panel):
- START position
(x y z)and GOAL position(x y z) - Click PAUSE to edit points, then click PLAY to start a new simulation using the new points.
- Constraint enforced by IK: z must be ≥ 0
- Reachability enforced by IK:
|p|must be within the arm’s reachable shell.
Manipulator3D_Python/
README.md
requirements.txt
resources/
fonts/
README.txt (optional font assets)
src/
main.py
robot/
robot_arm.py
sim/
trajectory.py
ui/
overlay.py
render/
draw_utils.py- World frame origin is at the center of the base revolute joint: (0,0,0).
- Joint angles:
q0_yaw: rotation about +Z (sets the arm’s radial direction in the X–Y plane)q1_pitch: shoulder elevation angle relative to the X–Y planeq2_pitch: elbow pitch angle (relative bend in the same vertical plane)
We use the radial unit direction in the X–Y plane:
Let link lengths be
- Elbow position:
- End-effector position:
This is implemented in:
robot/robot_arm.py→RobotArm.forward_kinematics()
This manipulator is effectively a 2-link arm in a vertical plane, rotated by yaw. Therefore the reachable radius must satisfy:
The implementation enforces:
target.z >= 0|p|within[min_reach, max_reach]
Given target
Step A — base yaw
Step B — reduce to planar IK in
Now solve a 2-link planar problem for the triangle formed by
Step C — elbow angle from law of cosines
Clamp to
This sign is the elbow-up / elbow-down branch selection.
Step D — shoulder angle
Define:
Then:
This is implemented in:
robot/robot_arm.py→RobotArm.solve_ik()
This repository is primarily a kinematic + trajectory simulator:
- The EE follows a commanded Cartesian trajectory.
- IK converts EE targets into joint angles.
- FK is used for rendering joint/link positions.
However, the code also defines mass and inertia properties for each link (uniform rod approximations):
- About center of mass:
- About the joint at one end:
These are computed in:
robot/robot_arm.py→LinkParams.recompute_inertia()
Currently, those values are used for display/inspection (overlay panel) and as a foundation for extending the project to:
- forward dynamics (torques → accelerations),
- gravity and Coriolis terms,
- joint-space controllers (PD, computed torque, etc.).
- Python 3.10+
- A working OpenGL-capable graphics driver
raylibPython bindings (installed viapip)
From the repository root:
python -m venv .venvActivate:
- Windows (PowerShell):
.\.venv\Scripts\Activate.ps1
- Windows (cmd):
.venv\Scripts\activate
- macOS/Linux:
source .venv/bin/activate
Install dependencies:
pip install -r requirements.txtFrom the repository root:
python src/main.py- Mouse wheel: zoom camera
- F11: toggle fullscreen
- Overlay panel:
- PAUSE while running to edit START/GOAL
- Type
x y zvalues into the boxes - Click PLAY to restart the pick-and-place loop using the new targets
Important rules enforced:
z >= 0|p|must be within the workspace shell
This section explains every important file in the repository and its role.
Installs raylib Python bindings.
Application entry point and runtime loop:
- configures window + camera
- holds the pick-and-place finite-state machine:
- HOME → START → PICK → GOAL → PLACE → HOME → WAIT → LOOP
- generates a linear Cartesian trajectory between targets
- runs IK each frame to get joint angles for the current EE target
- calls FK for rendering joint/link positions
- renders:
- robot geometry, axes, ball, suction tool
- overlay panel (status, parameters, input boxes, play/pause)
Robot model and kinematics:
LinkParams: link length, mass, inertia approximations (rod model)JointAngles: the 3 joint variables (yaw + 2 pitches)RobotArm:solve_ik()forward_kinematics()- reach limits:
min_reach,max_reach
A minimal trajectory generator:
LinearTrajectory:reset(from,to,duration)update(dt)position()finished
Overlay panel and UI logic:
- renders a semi-transparent panel
- shows:
- link lengths, masses, inertias
- workspace bounds
- reachability feedback for START/GOAL
- phase label and runtime error (if any)
- implements:
- PLAY/PAUSE button
- editable START and GOAL text fields (active when paused)
Rendering helpers using raylib primitives:
- text helpers:
draw_text_bold()draw_text_small()
- robot visuals:
- base pedestal
- joint housings
- tapered link cylinders with end caps
- suction tool
Below is a link to the simulation video on YouTube.
- Upgrade packaging tools:
python -m pip install --upgrade pip setuptools wheel
- Try a clean virtual environment.
- If your platform does not have a prebuilt wheel for your Python version, you may need build tooling (C compiler) to compile the extension.
- Update your GPU driver.
- Ensure your system supports the OpenGL version required by the installed raylib build.
- Ensure:
z >= 0|p|is within the workspace shell:[|L1 - L2|, L1 + L2]