Skip to content

Humanoid Centroidal Motion Retargeting

Background

Motion retargeting maps a recorded or designed human motion to a robot with different proportions. Scaling positions by leg length gives a useful kinematic reference, but it does not make that reference satisfy the robot's Newton-Euler equations or contact limits.

This example treats the entire known squat-and-reach reference as a preview. It optimizes the planar center-of-mass (CoM) trajectory, body pitch, and both foot contact wrenches over the full horizon. Tracking terms keep the result close to the scaled human motion, while centroidal dynamics, unilateral contact, Coulomb friction, center-of-pressure (CoP), wrench, and wrench-rate constraints make it dynamically consistent within the reduced model.

Geometrically scaled reference

The fixed horizon is \(T=2.4\ \mathrm{s}\). With normalized time \(\tau=t/T\), define the rest-to-rest, \(C^2\) bump

\[ b(t)=64\tau^3(1-\tau)^3. \]

Its first two derivatives are

\[ \dot b(t)=\frac{64}{T} \left(3\tau^2-12\tau^3+15\tau^4-6\tau^5\right), \]
\[ \ddot b(t)=\frac{64}{T^2} \left(6\tau-36\tau^2+60\tau^3-30\tau^4\right). \]

The leg-length scale is

\[ s=\frac{L_{\mathrm{robot}}}{L_{\mathrm{human}}} =\frac{0.82}{0.96}=0.854166\ldots. \]

The desired CoM position, velocity, pitch, and pitch rate are

\[ \boldsymbol c_d(t)= \begin{bmatrix} s(0.085)b(t)\\ 0.84-s(0.19)b(t) \end{bmatrix}, \qquad \boldsymbol v_d(t)=\dot{\boldsymbol c}_d(t), \]
\[ \theta_d(t)=0.13b(t), \qquad \omega_d(t)=0.13\dot b(t). \]

Thus the scaled reference moves forward by \(0.072604\ \mathrm m\), squats by \(0.162292\ \mathrm m\), and reaches \(0.13\ \mathrm{rad}\) pitch at the midpoint. The reference acceleration is used to construct a balanced initial wrench guess; it is not imposed as a trajectory constraint.

State, control, and units

Let \(i\in\{L,R\}\) identify the left and right feet. The state and control are

\[ \boldsymbol x= \begin{bmatrix} c_x&c_z&v_x&v_z&\theta&\omega& f_{Lx}&f_{Lz}&m_L&f_{Rx}&f_{Rz}&m_R \end{bmatrix}^{\mathsf T}, \]
\[ \boldsymbol u= \begin{bmatrix} \dot f_{Lx}&\dot f_{Lz}&\dot m_L& \dot f_{Rx}&\dot f_{Rz}&\dot m_R \end{bmatrix}^{\mathsf T}. \]
Symbol Meaning Unit or value
\(c_x,c_z\) Sagittal CoM position and height m
\(v_x,v_z\) CoM velocity m/s
\(\theta,\omega\) Body pitch and pitch rate rad, rad/s
\(f_{ix},f_{iz}\) Ground-on-robot tangential and normal force N
\(m_i\) Foot contact moment about the out-of-plane axis \(\mathrm{N\,m}\)
\(\dot f_{ix},\dot f_{iz},\dot m_i\) Contact-wrench rates \(\mathrm{N/s}\), \(\mathrm{N\,m/s}\)
\(M\) Robot mass \(62\ \mathrm{kg}\)
\(I_y\) Constant centroidal pitch inertia \(8\ \mathrm{kg\,m^2}\)
\(g\) Gravitational acceleration \(9.81\ \mathrm{m/s^2}\)
\(a\) Foot-center offset; centers are at \(x=\pm a\) \(0.14\ \mathrm m\)
\(\ell\) Foot half-length \(0.10\ \mathrm m\)
\(\mu\) Coulomb friction coefficient \(0.55\)

Centroidal dynamics

The feet are fixed at \((-a,0)\) and \((a,0)\). Translational dynamics are

\[ \dot c_x=v_x, \qquad \dot c_z=v_z, \]
\[ M\dot v_x=f_{Lx}+f_{Rx}, \qquad M\dot v_z=f_{Lz}+f_{Rz}-Mg. \]

Pitch evolves according to

\[ \dot\theta=\omega, \]
\[ I_y\dot\omega= (-a-c_x)f_{Lz}+c_zf_{Lx}+m_L +(a-c_x)f_{Rz}+c_zf_{Rx}+m_R. \]

The six remaining state equations are the wrench integrators

\[ \frac{\mathrm d}{\mathrm dt} \begin{bmatrix}f_{Lx}&f_{Lz}&m_L&f_{Rx}&f_{Rz}&m_R\end{bmatrix}^{\mathsf T} =\boldsymbol u. \]

Tracking and regularization objective

Define the tracking errors and normalization scales as

\[ \begin{aligned} \boldsymbol e_c&=\boldsymbol c-\boldsymbol c_d,& \boldsymbol e_v&=\boldsymbol v-\boldsymbol v_d,\\ F_0&=Mg,&M_0&=Mg\ell. \end{aligned} \]

The normalized contact-wrench vector is

\[ \overline{\boldsymbol w}= \begin{bmatrix} f_{Lx}/F_0\\ (f_{Lz}-F_0/2)/F_0\\ m_L/M_0\\ f_{Rx}/F_0\\ (f_{Rz}-F_0/2)/F_0\\ m_R/M_0 \end{bmatrix}. \]

Each component of the normalized rate \(\overline{\boldsymbol u}\) is the corresponding control divided by its rate limit. The objective is

\[ \begin{aligned} J=\int_0^T \big[&2400e_{cx}^2+3200e_{cz}^2 +80e_{vx}^2+100e_{vz}^2\\ &+500(\theta-\theta_d)^2 +35(\omega-\omega_d)^2\\ &+0.025\lVert\overline{\boldsymbol w}\rVert_2^2 +0.004\lVert\overline{\boldsymbol u}\rVert_2^2\big]\,\mathrm dt. \end{aligned} \]

Wrench regularization favors approximately even static support without fixing the force split. Rate regularization produces smooth contact histories.

Contact and path constraints

The normal-force limit is

\[ F_{z,\max}=0.9Mg=547.398\ \mathrm N. \]

For each foot, unilateral contact, the planar Coulomb cone, and the CoP bound are

\[ 0\le f_{iz}\le F_{z,\max}, \qquad |f_{ix}|\le\mu f_{iz}, \qquad |m_i|\le\ell f_{iz}. \]

The last inequality keeps the resultant CoP within the \(0.20\ \mathrm m\) foot support length. Additional component bounds are

\[ |f_{ix}|\le F_{z,\max}, \qquad |m_i|\le\ell F_{z,\max}=54.7398\ \mathrm{N\,m}. \]

The centroidal state bounds are

\[ \begin{gathered} -0.20\le c_x\le0.20\ \mathrm m, \qquad 0.60\le c_z\le0.94\ \mathrm m,\\ |v_x|\le0.55\ \mathrm{m/s}, \qquad |v_z|\le0.70\ \mathrm{m/s},\\ |\theta|\le0.28\ \mathrm{rad}, \qquad |\omega|\le0.80\ \mathrm{rad/s}. \end{gathered} \]

For each foot, wrench-rate bounds are

\[ |\dot f_{ix}|\le900\ \mathrm{N/s}, \qquad |\dot f_{iz}|\le2000\ \mathrm{N/s}, \qquad |\dot m_i|\le220\ \mathrm{N\,m/s}. \]

Boundary conditions

Both endpoints are the same symmetric static-support state:

\[ \boldsymbol c(0)=\boldsymbol c(T)= \begin{bmatrix}0&0.84\end{bmatrix}^{\mathsf T}\ \mathrm m, \]
\[ \boldsymbol v(0)=\boldsymbol v(T)=\boldsymbol0, \qquad \theta(0)=\theta(T)=\omega(0)=\omega(T)=0, \]
\[ f_{Lx}=f_{Rx}=m_L=m_R=0, \qquad f_{Lz}=f_{Rz}=\frac{Mg}{2}=304.11\ \mathrm N \]

at \(t=0\) and \(t=T\).

Numerical method and independent validation

The default problem uses a \(10\times4\) Lobatto mesh. The initial guess follows the scaled reference and distributes the dynamically required wrench between the feet with zero foot moments. Pockit then optimizes all states and wrench rates simultaneously.

After solving, the script reconstructs the trajectory at 4,001 times and checks state, wrench-rate, friction, and CoP constraints. It also fits cubic splines to the optimized wrench rates and independently integrates all 12 continuous states with solve_ivp using \(\mathrm{rtol}=2\times10^{-9}\) and \(\mathrm{atol}=2\times10^{-11}\). Force errors are scaled by \(Mg\), moment errors by \(Mg\ell\), and the first six state errors by their native unit scales before taking the maximum.

Verified result

Quantity Verified value
RMS CoM \(x\) tracking error \(0.012\ \mathrm{mm}\)
RMS CoM \(z\) tracking error \(0.010\ \mathrm{mm}\)
RMS pitch tracking error \(0.0005^\circ\)
Minimum friction margin (\mu f_z- f_x
Minimum CoP margin (\ell f_z- m
Maximum dense state-bound violation \(0\)
Maximum independently integrated scaled mismatch \(4.933\times10^{-4}\)

The strictly positive contact margins show that neither friction nor CoP is active in this local optimum. They do not certify feasibility for a full joint-level humanoid model.

Scaled human reference, retargeted centroidal motion, foot forces, tracking errors, and contact-constraint utilization

Scope and limitations

This example performs planar centroidal preview and retargeting only. It uses fixed feet, a constant pitch inertia, and continuous double support. It does not model joint coordinates or torques, kinematic reachability, self-collision, actuator limits, link inertia variation, contact switching, three-dimensional friction, or balance under disturbances.

The optimized CoM, pitch, and foot-wrench histories must therefore be passed to a downstream whole-body inverse-kinematics or trajectory-optimization stage that enforces the robot's complete multibody and collision constraints.

Run the example

python -m examples.humanoid_motion_retargeting

Save the figure without opening a window:

python -m examples.humanoid_motion_retargeting --save humanoid-motion-retargeting.png --no-show

The optional --quick flag uses a smaller \(8\times3\) mesh for a faster smoke test. The verified values above use the default mesh.

system, phase = build_problem()
guess = initial_guess(phase)
solution = solve_problem(system, guess)
plot_solution(solution)

Source code

See the complete runnable example: examples/humanoid_motion_retargeting.py.