anvil.kinematics
anvil.kinematics
Kinematics of an arm cut from a URDF: poses, forward kinematics, the Jacobian, gravity torque and inverse kinematics.
A Chain is the joints from a URDF's root link to a tip link; Pose is where a frame is; solve_ik finds the joint
positions that put a chain's tip at a pose, tuned by IkParams and answered with an IkSolution. Every call here is
pure computation: nothing moves an arm or needs a runtime.
Classes:
| Name | Description |
|---|---|
Pose |
A rigid-body pose: a position in meters and an orientation as a unit quaternion, x y z w. |
IkParams |
Tuning for |
IkSolution |
What |
Chain |
The driven joints of one URDF from its root link to a tip link: forward kinematics, Jacobian and gravity torque. |
Functions:
| Name | Description |
|---|---|
solve_ik |
Returns the joint positions that put |
Attributes:
| Name | Type | Description |
|---|---|---|
MAX_DOF |
int
|
Most driven joints a chain can have, and the length of |
MAX_DOF
module-attribute
MAX_DOF: int = 8
Most driven joints a chain can have, and the length of IkParams.rest_q.
Pose
Pose(
position: Sequence[float], orientation: Sequence[float]
)
Bases: Struct
A rigid-body pose: a position in meters and an orientation as a unit quaternion, x y z w.
The frame a pose is stated in is named where it is used: a chain's tip pose is in its URDF's root link's frame, the
world frame for a robot's chain. A pose holds any values; one with a component that is not finite, or an
orientation whose norm is more than 0.001 from 1, is refused by the call it is passed to. An orientation and its
negation are the same rotation, and a pose a call returns may carry either sign, so compare orientations with
angle_rad rather than ==.
Builds a pose from a position and an orientation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
position
|
Sequence[float]
|
x, y and z, in meters. |
required |
orientation
|
Sequence[float]
|
The unit quaternion as x, y, z, w, w last, so the identity is |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
A field is a string, or an entry is not a number. |
InvalidArgumentError
|
|
Methods:
| Name | Description |
|---|---|
identity |
Returns the pose with no translation and no rotation: a frame stated in itself. |
compose |
Returns |
inverse |
Returns the pose that undoes this one: where the frame this one is stated in sits relative to it. |
distance_m |
Returns how far apart the two positions are, in meters. |
angle_rad |
Returns the angle of the rotation from one orientation to the other, in radians, from 0 to pi. |
Attributes:
| Name | Type | Description |
|---|---|---|
position |
list[float]
|
Position as x, y, z, in meters. |
orientation |
list[float]
|
Orientation as a unit quaternion, x, y, z, w, w last. |
position
property
writable
position: list[float]
Position as x, y, z, in meters.
Raises:
| Type | Description |
|---|---|
TypeError
|
On assignment, a string, or an entry that is not a number. |
InvalidArgumentError
|
On assignment, a value without exactly 3 entries. |
orientation
property
writable
orientation: list[float]
Orientation as a unit quaternion, x, y, z, w, w last.
Raises:
| Type | Description |
|---|---|
TypeError
|
On assignment, a string, or an entry that is not a number. |
InvalidArgumentError
|
On assignment, a value without exactly 4 entries. |
identity
classmethod
identity() -> Self
Returns the pose with no translation and no rotation: a frame stated in itself.
compose
Returns other, stated relative to this pose, as it is in the frame this pose is stated in.
pose.compose(other=pose.inverse()) is the identity. The result's orientation is normalized.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Pose
|
A pose stated in the frame this one describes. |
required |
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
Either pose has a component that is not finite, or an orientation that is not a unit quaternion. |
inverse
inverse() -> Pose
Returns the pose that undoes this one: where the frame this one is stated in sits relative to it.
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
This pose has a component that is not finite, or an orientation that is not a unit quaternion. |
distance_m
distance_m(other: Pose) -> float
Returns how far apart the two positions are, in meters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Pose
|
The pose to measure to, in the same frame as this one. |
required |
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
Either pose has a component that is not finite, or an orientation that is not a unit quaternion, though only the positions are compared. |
angle_rad
angle_rad(other: Pose) -> float
Returns the angle of the rotation from one orientation to the other, in radians, from 0 to pi.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Pose
|
The pose to measure to, in the same frame as this one. |
required |
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
Either pose has a component that is not finite, or an orientation that is not a unit quaternion. |
IkParams
IkParams(
max_iterations: int | None = None,
residual_m: float | None = None,
residual_rad: float | None = None,
rest_q: Sequence[float] = (),
damping_lambda_sq: float | None = None,
rest_gain: float | None = None,
limit_gain: float | None = None,
)
Bases: Struct
Tuning for solve_ik: when to stop, the rest posture it leans toward, and how hard.
IkParams() holds the solver's own defaults; anvil.workcell.RobotConfig.ik_params gives each arm of a robot the
parameters its description states. Fields are checked when a solve runs, not when they are set: solve_ik refuses a
value no solve can run on, and each field says which.
Builds parameters from the solver's defaults, overriding the fields given.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_iterations
|
int | None
|
Most steps a solve takes; |
None
|
residual_m
|
float | None
|
Tip position error, in meters, at or under which the position counts as reached; |
None
|
residual_rad
|
float | None
|
Tip orientation error, in radians, at or under which the orientation counts as reached;
|
None
|
rest_q
|
Sequence[float]
|
The posture to lean toward, chain order, at most |
()
|
damping_lambda_sq
|
float | None
|
Damping of each step; |
None
|
rest_gain
|
float | None
|
How hard each joint is pulled toward its rest pose; |
None
|
limit_gain
|
float | None
|
How hard a joint past a limit is pushed back inside it; |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|
Attributes:
| Name | Type | Description |
|---|---|---|
max_iterations |
int
|
Most steps a solve takes; |
residual_m |
float
|
Tip position error, in meters, at or under which the position counts as reached. |
residual_rad |
float
|
Tip orientation error, in radians, at or under which the orientation counts as reached. |
rest_q |
list[float]
|
Posture the solve leans toward, |
damping_lambda_sq |
float
|
Damping of each step, the square of lambda; |
rest_gain |
float
|
Pull of each joint toward its rest pose, per unit away from it; |
limit_gain |
float
|
Push of a joint back inside a limit it is past, per span of travel; |
max_iterations
property
writable
max_iterations: int = 50
Most steps a solve takes; solve_ik refuses fewer than 1 or more than 200.
Raises:
| Type | Description |
|---|---|
TypeError
|
On assignment, a value that is not an integer. |
InvalidArgumentError
|
On assignment, a negative value, or one too large to hold. |
residual_m
property
writable
residual_m: float = 0.001
Tip position error, in meters, at or under which the position counts as reached.
solve_ik refuses one that is not finite and positive.
residual_rad
property
writable
residual_rad: float = 0.01
Tip orientation error, in radians, at or under which the orientation counts as reached.
solve_ik refuses one that is not finite and positive.
rest_q
property
writable
rest_q: list[float] = [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
]
Posture the solve leans toward, MAX_DOF positions in chain order, in radians or meters.
Only the first Chain.num_joints entries are used, though solve_ik refuses any that is not finite. The list
writes through: params.rest_q[1] = 0.1 is what the next solve runs with, and a change to its length is
refused.
Raises:
| Type | Description |
|---|---|
TypeError
|
On assignment, a string, or an entry that is not a number. |
InvalidArgumentError
|
On assignment, more than |
damping_lambda_sq
property
writable
damping_lambda_sq: float = 0.36
Damping of each step, the square of lambda; solve_ik refuses less than 1e-6 or a value that is not finite.
Larger takes shorter, steadier steps near a singular configuration; smaller converges faster away from one.
rest_gain
property
writable
rest_gain: float = 0.001
Pull of each joint toward its rest pose, per unit away from it; solve_ik refuses one outside 0 to 1e6.
The pull acts only in the directions that leave the tip where it is.
limit_gain
property
writable
limit_gain: float = 10.0
Push of a joint back inside a limit it is past, per span of travel; solve_ik refuses one outside 0 to 1e6.
Limits only bias the solve, through this push in the directions that leave the tip where it is; they are never
enforced, so IkSolution.q can sit outside them.
IkSolution
IkSolution()
Bases: Counted
What solve_ik found: the joint positions, whether they reach the target, and how close they got.
Get one from solve_ik, never by calling the class.
Attributes:
| Name | Type | Description |
|---|---|---|
q |
list[float]
|
Joint positions, one per joint of the chain in chain order, in radians or meters; possibly outside limits. |
converged |
bool
|
Whether the tip is within both |
iterations |
int
|
Steps taken: 0 from a seed already at the target, |
residual_m |
float
|
Distance from the tip to the target position at |
residual_rad |
float
|
Angle from the tip's orientation to the target's at |
q
property
q: list[float]
Joint positions, one per joint of the chain in chain order, in radians or meters; possibly outside limits.
converged
property
converged: bool
Whether the tip is within both IkParams.residual_m and IkParams.residual_rad of the target at q.
iterations
property
iterations: int
Steps taken: 0 from a seed already at the target, IkParams.max_iterations when the solve ran out.
residual_m
property
residual_m: float
Distance from the tip to the target position at q, in meters.
residual_rad
property
residual_rad: float
Angle from the tip's orientation to the target's at q, in radians.
Chain
Chain()
The driven joints of one URDF from its root link to a tip link: forward kinematics, Jacobian and gravity torque.
One comes from from_urdf_file or from_urdf_text, or for each arm of a robot from
anvil.workcell.RobotConfig.chains. A configuration q is one position per driven joint in chain order, root
first: radians for a revolute joint, meters for a prismatic one. Every pose and position a chain returns is in its
URDF's root link's frame, the root link being the one no joint hangs from; for a robot's chain that is the world
frame, the composed URDF's world link, which every anvil.workcell.Mount is placed in. A q is not checked
against the limits, and one that is not finite gives results that are not finite.
Get one from Chain.from_urdf_file or Chain.from_urdf_text, never by calling the class.
Methods:
| Name | Description |
|---|---|
from_urdf_file |
Reads a URDF file and builds the chain of driven joints from its root link to the link |
from_urdf_text |
Builds the chain from URDF text in hand, as |
fk |
Returns the tip link's pose at configuration |
joint_origins |
Returns where each driven joint's origin is at configuration |
jacobian |
Returns the geometric Jacobian at the tip link's origin at configuration |
gravity_torque |
Returns the torque at each driven joint that holds the chain still under gravity at configuration |
Attributes:
| Name | Type | Description |
|---|---|---|
num_joints |
int
|
Number of driven joints from the root link to the tip, at most |
joint_names |
list[str]
|
URDF names of the driven joints, chain order. |
limits |
tuple[list[float], list[float]]
|
Position limits from the URDF as a |
num_joints
property
num_joints: int
Number of driven joints from the root link to the tip, at most MAX_DOF.
joint_names
property
joint_names: list[str]
URDF names of the driven joints, chain order.
limits
property
limits: tuple[list[float], list[float]]
Position limits from the URDF as a (lower, upper) pair of lists, chain order, in radians or meters.
from_urdf_file
classmethod
from_urdf_file(path: str | Path, tip: str) -> Self
Reads a URDF file and builds the chain of driven joints from its root link to the link tip.
Revolute and prismatic joints are driven; fixed joints on the path are folded into the links around them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
The URDF file. |
required |
tip
|
str
|
The link the chain ends at. The root link itself gives a chain of no joints. |
required |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
There is no file at |
InvalidArgumentError
|
The file is not UTF-8 text or not a URDF; |
OperationError
|
The file could not be read for another reason, such as |
from_urdf_text
classmethod
from_urdf_text(urdf: str, tip: str) -> Self
Builds the chain from URDF text in hand, as from_urdf_file does from a file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
urdf
|
str
|
The URDF's text, such as |
required |
tip
|
str
|
The link the chain ends at. The root link itself gives a chain of no joints. |
required |
Raises:
| Type | Description |
|---|---|
InvalidArgumentError
|
|
fk
fk(q: Sequence[float]) -> Pose
Returns the tip link's pose at configuration q.
In the URDF's root link's frame, the world frame for a robot's chain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Sequence[float]
|
One position per driven joint, chain order. |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|
joint_origins
joint_origins(q: Sequence[float]) -> list[list[float]]
Returns where each driven joint's origin is at configuration q: the elbow's position without a chain to it.
Joint i's origin is the far end of the links the joints before it carry, so between two configurations these
are how far each link's end travels; the tip's own position is fk's.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Sequence[float]
|
One position per driven joint, chain order. |
required |
Returns:
| Type | Description |
|---|---|
list[list[float]]
|
One |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|
jacobian
jacobian(q: Sequence[float]) -> list[list[float]]
Returns the geometric Jacobian at the tip link's origin at configuration q.
In the URDF's root link's frame, the world frame for a robot's chain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Sequence[float]
|
One position per driven joint, chain order. |
required |
Returns:
| Type | Description |
|---|---|
list[list[float]]
|
6 rows of |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|
gravity_torque
gravity_torque(q: Sequence[float]) -> list[float]
Returns the torque at each driven joint that holds the chain still under gravity at configuration q.
Gravity is 9.81 meters per second squared along the negative z of the URDF's root link's frame, the world frame
for a robot's chain, acting on the link masses and centers of mass the URDF states. A URDF with a gripper
grafted on, such as anvil.workcell.RobotConfig.composed_urdf() returns, carries the gripper's mass too. Links
that branch off the chain, such as a gripper's fingers, load the link they hang from, held at their joints'
zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Sequence[float]
|
One position per driven joint, chain order. |
required |
Returns:
| Type | Description |
|---|---|
list[float]
|
One entry per driven joint, chain order: newton meters for a revolute joint, newtons for a prismatic one. |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|
solve_ik
solve_ik(
chain: Chain,
seed: Sequence[float],
target: Pose,
params: IkParams | None = None,
) -> IkSolution
Returns the joint positions that put chain's tip at target, iterating from seed.
Each step is a damped least-squares step toward the target pose, leaning toward IkParams.rest_q and back
inside the joint limits in the directions that leave the tip where it is, and no joint moves more than pi/4 in one
step. It stops when the tip is within both residuals or IkParams.max_iterations steps have been taken, so a solve
that runs out returns its last configuration with IkSolution.converged false rather than raising.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
chain
|
Chain
|
The chain to solve for. |
required |
seed
|
Sequence[float]
|
The configuration to start from, one position per driven joint, chain order. |
required |
target
|
Pose
|
The tip link's pose to reach, in the chain's URDF's root link's frame, the world frame for a robot's chain. |
required |
params
|
IkParams | None
|
The solver's tuning; |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
|
InvalidArgumentError
|
|