Skip to main content
πŸ€–AI-generated documentation☐ curatedAI Generated
This page was drafted by an AI assistant and may contain inaccuracies.
About content generation types
πŸ€–
AI Generated β€” Page drafted entirely by AI from codebase or prompt instructions.
(e.g., docs generated from codebase analysis)
← this page
βœ‹β†’πŸ€–
AI Transformatted β€” Human provided raw material; AI restructured it into a different format.
(e.g., livestream β†’ blog post, meeting notes β†’ docs)
βœ‹
Human Generated β€” Page written entirely by a human author.
(e.g., hand-written tutorial)
More info about content generation types β†—

Module Architecture

Goal​

One coherent module that owns "the kinematic and inertial state of a rigid body / the whole body," reusable by both pipelines, with clean boundaries so each piece can be understood and tested on its own.

Provenance: the bs kinematics_core ontology​

The bs client repo (clients/bs/python_code/kinematics_core) already contains a well-designed, purely kinematic ontology that we will pull into freemocap and refactor (⏳ planned for Phase 3, when per-segment orientation first needs it β€” not required for the Phase 1 point-mass ellipsoid, so not yet ported):

  • ReferenceGeometry + CoordinateFrameDefinition β€” build a body-fixed coordinate frame from named keypoints (origin + one exact axis + one approximate axis, third by cross product, Gram-Schmidt orthonormalized).
  • RigidBodyState β€” full per-instant state (position, velocity, orientation, angular velocity, accelerations).
  • RigidBodyKinematics β€” a pose trajectory that lazily computes velocity, acceleration, and angular velocity (global + local) by quaternion finite-differencing.
  • Quaternion / quaternion-trajectory + vectorized derivative helpers.

What it does not have is any notion of mass, inertia, or momentum. That is precisely the layer this proposal adds on top.

Proposed layout​

freemocap/core/kinematics/
β”œβ”€β”€ reference_geometry.py # ⏳ ported: ReferenceGeometry, CoordinateFrameDefinition, StaticPose
β”œβ”€β”€ rigid_body_state.py # ⏳ ported: RigidBodyState (per-instant)
β”œβ”€β”€ rigid_body_kinematics.py # ⏳ ported: RigidBodyKinematics (trajectory; lazy derivatives)
β”œβ”€β”€ quaternion.py # ⏳ ported: Quaternion (+ trajectory)
β”œβ”€β”€ derivatives.py # ⏳ ported: finite-difference helpers
β”‚
β”œβ”€β”€ inertial/ # NEW β€” the layer bs does not have
β”‚ β”œβ”€β”€ anthropometry.py # βœ… de Leva 1996 table (mass, CoM, radii); F + M + mean default
β”‚ β”œβ”€β”€ segment_inertia.py # ⏳ per-segment inertia tensor Jα΅’ from anthropometry + bone length
β”‚ β”œβ”€β”€ composite_inertia.py # βœ… I_G (parallel-axis sum) + eigh + equimomental semi-axes
β”‚ β”œβ”€β”€ centroidal_momentum.py # ⏳ H_G (orbital + spin), Ο‰ = I_G⁻¹ H_G
β”‚ └── ground_reference.py # βœ… CoP (CoM projection), XCoM = capture point, CMP
β”‚
β”œβ”€β”€ body_kinematics_state.py # βœ… the unified per-frame bundle (the public output)
└── online/ # βœ… realtime per-frame adapter (rolling history)
└── streaming_kinematics.py# βœ… per-frame I_G + ground-refs, 3-deep CoM history

Legend: βœ… built (Phase 1) Β· ⏳ planned (Phase 2/3). The ontology files at the top are not yet ported β€” the point-mass ellipsoid and ground references need no orientation.

Shared core, two consumers​

The math, the anthropometric tables, and the data structures are shared. The source of derivatives differs by pipeline:

ConcernRealtime (built first)Posthoc (later)
Velocities / angular velocityper-frame finite differences over a small rolling history (the pattern already used for prev_com in the aggregator)RigidBodyKinematics lazy whole-array derivatives (cleaner, less noisy)
Entry pointonline/streaming_kinematics.pytrajectory ontology directly
Sharedinertial/* math, anthropometry, BodyKinematicsStatesame

This keeps a single source of truth for the physics while letting each pipeline use the derivative method that suits it.

Per-segment orientation strategy​

The spin term of H_G (and a fully faithful inertia ellipsoid) needs each segment's orientation. Locked decision:

  • Limb segments (upper/lower arm, thigh, shank, foot): treat as rods aligned with the bone vector. A rod is axisymmetric, so its inertia about the long axis is negligible and spin about that axis contributes little β€” we need only the bone direction and its angular velocity (from the bone vector's rotation across frames).
  • Trunk / pelvis / head: not rod-like, so build a real body frame with ReferenceGeometry (shoulders + hips define the trunk frame; this is exactly what the ported ontology is for).

A full per-segment Kabsch/Procrustes pose fit is the heavier alternative we can adopt later if higher fidelity is needed; the rod+frame approach is the pragmatic default.

Anthropometric data β€” the one new asset​

The CoM calculation today uses only segment mass fractions and CoM locations (skellyforge's SegmentCenterOfMassDefinition). The inertia ellipsoid additionally needs radii of gyration. βœ… anthropometry.py now holds the de Leva 1996 Table 4 values (8 primary segments; female + male tables; mean used by default) giving per-segment (k_sagittal, k_transverse, k_longitudinal) as fractions of segment length, so:

Jα΅’ = mα΅’ Β· diag( (k_sagΒ·Lα΅’)Β², (k_transΒ·Lα΅’)Β², (k_longΒ·Lα΅’)Β² ) # about segment CoM, segment frame

This was the only genuinely new data the proposal required, and it has landed (mass fractions verified to sum to 1.0). Phase 1 still ships the point-mass ellipsoid (Jα΅’ = 0); Phase 2 feeds these radii in via segment_inertia.py.

Boundaries & testability​

Each unit has one job and a clear interface:

  • βœ… composite_inertia: composite_centroidal_inertia(...) β†’ I_G, principal_axes_and_moments(I_G) β†’ (moments, axes), equimomental_semi_axes(...) β†’ semi-axes. Pure functions; unit-tested against analytic cases (two masses β†’ diag(0,2,2); uniform sphere β†’ semi-axes = R).
  • ⏳ centroidal_momentum (Phase 2): H_G (orbital + spin) and Ο‰ = I_G⁻¹ H_G. Will be tested against conservation cases (free-fall β†’ constant H_G).
  • βœ… ground_reference: center_of_pressure_ground_projection, extrapolated_center_of_mass, centroidal_moment_pivot. Pure functions; unit-tested incl. the point-mass limit (zero CoM acceleration β†’ CMP = CoP).

The realtime adapter and the trajectory ontology both call these same pure functions.