screws
Screw-theory robotics in Python, after Lynch and Park, Modern Robotics (MR).
screws is the MR code library reorganised: the same mathematics under
snake_case names, MR's own names kept as aliases, a Robot class, a URDF
loader, robots that ship ready to use, and a bridge to CoppeliaSim.
Install
uv add screws # the mathematics: numpy is the only dependency
uv add "screws[coppelia]" # plus the CoppeliaSim ZMQ remote API client
Four lines
import screws as sc
ur5 = sc.robots.ur5() # M, screw axes, inertias from the textbook's URDF
T = ur5.fk([0.3, -1.2, 0.8, -0.4, 1.1, 0.2]) # a reachable, non-singular pose
result = ur5.ik(T, theta0=[0.1, -1.4, 0.1, 0.1, 1.4, 0.1]) # result.theta, result.converged, result.history
The free functions are the reference implementation and read as the book does:
sc.exp6(sc.vec_to_se3(S * theta)) is $e^{[\mathcal{S}]\theta}$, sc.fk_space(M, S, theta)
is the space form of the product of exponentials, and sc.FKinSpace is the very same
function under MR's name.
Screw-axis lists are 6xn, one axis per column, as MR writes them. Nothing guesses the
orientation (a 6x6 array is ambiguous for a six-axis arm), so hand entry goes through a
sequence of 6-vectors: sc.Robot.from_screw_axes(M, [S1, S2, ...]).
Check your own code against the library
import numpy as np
import screws as sc
def my_exp6(se3mat): ... # your implementation
rng = np.random.default_rng(0)
cases = [sc.vec_to_se3(rng.normal(size=6)) for _ in range(20)]
sc.testing.check(my_exp6, sc.exp6, cases) # raises on the first disagreement
CoppeliaSim
Works with CoppeliaSim 4.9 or later through the ZMQ remote API (0.1 verified on 4.10.0).
from screws.coppelia import Scene
with Scene() as scene: # connects to localhost:23000 in stepping mode
arm = scene.arm("/UR5") # the joints under that tree, base to tip
robot = arm.robot() # a screws.Robot read off the scene at zero
arm.mode("position")
log = scene.run(lambda t, theta, dtheta: theta_desired(t), duration=5.0, arm=arm)
log.plot()
Scene owns the connection and the clock (start, step, stop, time, dt,
frame, show_frame). Arm reads (theta, dtheta, tau, tip_frame) and commands
in one of three modes (position, velocity, torque), or teleports without physics
to animate an IK history. Arm.robot() derives M and the screw axes from the scene's
joint frames (omega is the joint's z axis, v = -omega x q). Scene inertias arrive in 0.2.
Two UR5s
sc.robots.ur5() is built from the URDF the textbook prints in section 4.2: the
manufacturer's lengths and the printed inertias, the closest published match to the
simulator's model. sc.robots.ur5(source="textbook") is the rounded table of MR Figure
4.6 with no inertias. They differ in the third decimal of the $v$ entries, and the course
notes' problems ask why.
Names
| Modern Robotics | screws |
|---|---|
NearZero |
near_zero |
Normalize |
normalize |
RotInv |
rot_inv |
VecToso3 |
vec_to_so3 |
so3ToVec |
so3_to_vec |
AxisAng3 |
axis_angle3 |
MatrixExp3 |
exp3 |
MatrixLog3 |
log3 |
RpToTrans |
rp_to_transform |
TransToRp |
transform_to_rp |
TransInv |
transform_inv |
VecTose3 |
vec_to_se3 |
se3ToVec |
se3_to_vec |
Adjoint |
adjoint |
ScrewToAxis |
screw_axis |
AxisAng6 |
axis_angle6 |
MatrixExp6 |
exp6 |
MatrixLog6 |
log6 |
ProjectToSO3 |
project_so3 |
ProjectToSE3 |
project_se3 |
DistanceToSO3 |
distance_so3 |
DistanceToSE3 |
distance_se3 |
TestIfSO3 |
is_so3 |
TestIfSE3 |
is_se3 |
FKinBody |
fk_body |
FKinSpace |
fk_space |
JacobianBody |
jacobian_body |
JacobianSpace |
jacobian_space |
IKinBody |
ik_body |
IKinSpace |
ik_space |
Where a screws function's signature matches MR's, the alias is that function
(sc.FKinSpace is sc.fk_space). IKinBody and IKinSpace are thin wrappers that return
MR's (thetalist, success) tuple; the primaries return an IKResult with the iteration
history. No deprecation warnings, ever.
Licence
MIT. Portions derived from the Modern Robotics code library, copyright 2018 Huan Weng,
Bill Hunt, Jarvis Schultz and Mikhail Todes, MIT licence; see LICENSE.
Release files for screws 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| screws-0.1.0.tar.gz | 178.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| screws-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 210.6 kB
Release files / screws-0.1.0.tar.gz
| Download URL | screws-0.1.0.tar.gz |
|---|---|
| Size | 178.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2ffd5b395588b00f7c17d86c348024ba38fe055b571cacdc8024dd54d7971e12
|
|
BLAKE2b-256 checksum How to use checksums |
d85c90bfdb041b7e47434248e69773977b51a5a9a66aefb3b334c27bf08ae634
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 27, 2026.
Transparency logRelease files / screws-0.1.0-py3-none-any.whl
| Download URL | screws-0.1.0-py3-none-any.whl |
|---|---|
| Size | 32.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
49b3f0da0dd655e5b3b7f2c7a47f4471d359802106667ea130dcfcac23cc5def
|
|
BLAKE2b-256 checksum How to use checksums |
84a6f69b053659196504960ff5fd10974203dd2dc459657301873f7d7a3a1ec7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 27, 2026.
Transparency log