Skip to content

IKPy v4.2.0

Choose a tag to compare

@Phylliade Phylliade released this 26 Oct 09:50
· 17 commits to master since this release
v4.2.0
c49cb1e

What's new in v4.2.0

🦴 BVH motion capture files

IKPy now reads BVH (Biovision Hierarchy) files, the common format of motion capture data. Any path of the skeleton becomes a chain, and the motion of the file can be replayed on it:

from ikpy.chain import Chain
from ikpy.bvh import BVH

# From the hips to the left hand; the joints in between are filled in automatically
chain = Chain.from_bvh_file("walk.bvh", base_elements=["Hips", "LeftHand"], scale=0.01)

trajectory, frame_time = BVH.get_bvh_motion("walk.bvh", base_elements=["Hips", "LeftHand"], scale=0.01)
hand_frames = [chain.forward_kinematics(joints) for joints in trajectory]

Each channel of a joint becomes one link (Hips_Zrotation, Hips_Xrotation...), so the rotation order of every joint is reproduced exactly, whatever the exporter. Position channels are supported on any joint, as in Mixamo exports, and the zero joint vector is the rest pose of the skeleton. BVH files have no unit: scale converts them to meters. The implementation was checked against pybvh's forward kinematics on CMU, Mixamo, mocapbank, MakeHuman and SnapMoGen captures. Closes #91, requested by @gemlongman.

🔄 URDF continuous joints

A continuous joint is a revolute joint without limits, and IKPy now loads it as such instead of raising Unknown joint type. This unblocks TIAGo, ABB and many ROS robots. Thanks to @smoltafet (#181), closes #134.

📐 Default joint axis

A revolute or prismatic joint whose <axis> element is absent now uses the URDF default (1, 0, 0), like urdfdom, instead of failing in validation. An <axis> without its xyz attribute gets the same default with a warning. Thanks to @smoltafet (#182), closes #180.

🧭 Orientation conversions

ikpy.utils.geometry converts the rotation part of a frame to and from the representations of ROS, Unity and Blender:

from ikpy.utils import geometry

frame = chain.forward_kinematics(joints)
quaternion = geometry.rotation_matrix_to_quaternion(frame)                      # (x, y, z, w)
quaternion = geometry.rotation_matrix_to_quaternion(frame, scalar_first=True)   # (w, x, y, z)
roll, pitch, yaw = geometry.rotation_matrix_to_rpy(frame)                       # URDF convention

target_orientation = geometry.quaternion_to_rotation_matrix(quaternion)
joints = chain.inverse_kinematics(target_position, target_orientation, orientation_mode="all")

rotation_matrix_to_euler / euler_to_rotation_matrix handle any axis sequence. Closes #103.

📏 Denavit-Hartenberg links

DHLink accepts convention="modified" (Craig's convention, Rx(alpha) Tx(a) Rz(theta) Tz(d)) next to the classic one. It also keeps its name now: it used to be overwritten by use_symbolic_matrix. Closes #55 and #149.

🔧 Fixes

  • MJCF: a multi-body base_elements path such as ["base", "right_arm"] produced a chain with only the origin link. Thanks to @YaoxinHuang (#179).
  • URDF: when a link or joint of base_elements is not found, the error lists the available names and points at base_elements. Closes #156.
  • tutorials.md links the notebooks from the current tree, and says that the two Poppy notebooks need pypot and a simulator (#146).

⚠️ Known issue

The JAX backend silently treats DHLink as a fixed joint (#183). Use backend="numpy" for DH chains until it is fixed.