hard Preview An early lesson: it works, but its text, code or grading may still change. humanoidlocomotiongait

Humanoid Sprint

Make a NAO humanoid walk 10 meters as fast as it can without falling, with a gait you design.

Free. Runs in your browser; you'll be asked to sign in first.

The Humanoid Sprint simulation in Webots

Overview

A NAO humanoid stands behind the start line of a 10 m track. Your controller must make it walk to the finish as fast as it can without falling and without leaving the track. Nothing is pre-recorded: every joint angle is computed in every control step from a few gait parameters, the robot's sensors and a little geometry.

The lesson builds a classic phase-based gait generator in small pieces: a foot trajectory for each leg, the inverse kinematics that turns a foot position into hip, knee and ankle angles, a lateral sway that moves the weight over the stance foot, ankle feedback from the torso's inertial unit that keeps the robot upright, and a heading controller that keeps it running straight in its lane.

Theoretical Background

The gait cycle

Walking is periodic. One gait cycle contains a step of each leg; during it each leg goes through a swing phase (the foot in the air, moving forward) and a stance phase (the foot on the ground, pushing the body forward). When both feet touch the ground at once the robot is in double support, which is where walking differs from running (running has a flight phase instead).

A gait generator describes the cycle with one phase variable that grows with time:

\[\varphi(t) = 2\pi f\,(t - t_0)\]

where \(f\) [Hz] is the step frequency (gait cycles per second) and \(t_0\) the time stepping starts. The right leg uses \(\psi_R = \varphi\) and the left leg \(\psi_L = \varphi + \pi\), half a cycle later, so the legs always alternate. For each leg, \(\psi \in [0, \pi)\) is its swing and \(\psi \in [\pi, 2\pi)\) its stance (angles modulo \(2\pi\)).

graph LR
    A["phi = 0<br/>right swing starts<br/>weight on left"] --> B["phi = pi/2<br/>right foot highest"]
    B --> C["phi = pi<br/>right foot lands<br/>left swing starts"]
    C --> D["phi = 3pi/2<br/>left foot highest"]
    D --> A

Foot trajectory

In the hip's frame each foot follows a closed path: forward in the air, backward on the ground. With step length \(S\), step height \(H\) and a double-support margin \(c \in [0, 1)\):

\[x(\psi) = -\frac{S}{2}\cos\psi \qquad h(\psi) = H\,\frac{\max(0,\ \sin\psi - c)}{1 - c}\]

\(x\) is the foot's forward position relative to the hip and \(h\) its lift. At \(\psi = 0\) the foot is at the back (\(x = -S/2\)), at \(\psi = \pi\) at the front (\(x = +S/2\)). The foot leaves the ground only while \(\sin\psi > c\), so near \(\psi = 0\) and \(\psi = \pi\) both feet are down: \(c\) buys a short double support, which makes the gait much less fragile. During stance the foot moves backward relative to the hip; since it grips the ground, the body moves forward by \(S\) per step. Two steps per cycle give an ideal speed of

\[v_{\text{ideal}} = 2\,S\,f\]

The real speed is lower: feet slip, the legs are compliant, and the gait spends time ramping up.

Leg inverse kinematics

Each NAO leg has a hip, a knee and an ankle pitch joint in the sagittal plane: a planar two-link arm with thigh length \(T = 0.100\) m and tibia length \(L = 0.1029\) m. Given the ankle position \((x, z)\) relative to the hip (\(x\) forward, \(z\) the height of the hip above the ankle), the hip-ankle distance is

\[d = \sqrt{x^2 + z^2} \quad (d \le T + L)\]

The law of cosines in the triangle hip-knee-ankle gives the knee bend and the angle \(\beta\) between the thigh and the hip-ankle line:

\[\theta_{\text{knee}} = \pi - \arccos\frac{T^2 + L^2 - d^2}{2TL} \qquad \beta = \arccos\frac{T^2 + d^2 - L^2}{2Td}\]

With \(\alpha = \operatorname{atan2}(x, z)\), the angle of the hip-ankle line from the vertical, and the NAO's sign convention (negative hip pitch moves the thigh forward):

\[\theta_{\text{hip}} = -(\alpha + \beta) \qquad \theta_{\text{ankle}} = -(\theta_{\text{hip}} + \theta_{\text{knee}})\]

The last equation keeps the sole parallel to the torso: the three pitch angles add up to zero, so the foot lands flat when the torso is upright. Walking with bent knees (\(z = 0.17\) m instead of the stretched 0.203 m) keeps the leg away from the singular straight-knee pose and leaves room to lift the foot.

Symbol Meaning Value
\(T\), \(L\) thigh and tibia length 0.100 m, 0.1029 m
\(z\) hip-to-ankle height while walking, minus the lift \(h\) 0.17 m
\(S\), \(H\) step length, step height 0.10 m, 0.038 m
\(f\) step frequency 2.2 Hz
\(c\) double-support margin 0.27

Lateral sway and the support polygon

A robot standing still is statically stable while the projection of its centre of mass (CoM) lies inside the support polygon, the convex hull of the feet's contact with the ground. When one foot lifts, the support polygon shrinks to the other foot, so before the right foot lifts the CoM must move over the left foot. The gait does this with a hip roll that rocks the torso from side to side at the gait frequency:

\[\theta_{\text{hip roll}} = -A \sin(\varphi + \delta) \qquad \theta_{\text{ankle roll}} = -\theta_{\text{hip roll}}\]

\(A\) is the sway amplitude and \(\delta\) a phase lead: the body has inertia, so the sway must start a little before the foot lifts. The ankle roll cancels the hip roll at the foot, which keeps the soles flat on the ground. At walking speed the robot is not statically stable all the time; it is dynamically stable: the zero moment point (the point where the ground reaction balances gravity and inertia) stays inside the support polygon over the whole cycle.

Balance feedback

The gait above is open loop: it would play the same angles whether the robot is upright or falling. Feedback from the torso closes the loop at the ankles, the joints closest to the ground and therefore the most effective at moving the centre of pressure. With torso pitch \(\theta\) (positive leaning forward), pitch rate \(\dot\theta\) and roll \(\phi\) (positive leaning right):

\[\Delta\theta_{\text{ankle pitch}} = K_\theta\,\theta + K_{\dot\theta}\,\dot\theta \qquad \Delta\theta_{\text{ankle roll}} = -K_\phi\,\phi\]

A torso falling forward makes the ankles press the toes down, which moves the centre of pressure forward and pushes the body back; the derivative term reacts to the fall's speed and damps the oscillation. The gains are small (\(K_\theta = 0.05\), \(K_{\dot\theta} = 0.08\) s, \(K_\phi = 0.38\)): large ankle corrections make the feet rock and slip.

The NAO's own inertial unit measures only roll and pitch (its yaw axis is disabled), so this world adds a full inertial unit and a 3-axis gyro to the torso through the NAO's bodySlot.

Heading and lane keeping

A walking robot drifts: small asymmetries in each step add up to a turn. The controller keeps the robot in its lane with two nested proportional loops. The lateral offset from the lane centre \(y - y_{\text{lane}}\) sets a heading reference pointing back to the lane, and the heading error sets a turn command:

\[\psi_{\text{ref}} = \operatorname{sat}_{\psi_{\max}}\!\big(-K_y\,(y - y_{\text{lane}})\big) \qquad u = \operatorname{sat}_{u_{\max}}\!\big(K_\psi\,(\psi_{\text{ref}} - \psi)\big)\]

where \(\psi\) is the torso yaw (positive turned left), \(y\) comes from the GPS and \(\operatorname{sat}\) limits a value to \(\pm\) its bound. The turn is made with the hip yaw joints: each leg rotates its foot by \(u \cdot \tfrac{1}{2}(1 - \cos\psi_{\text{leg}})\), which grows from 0 to \(u\) while the leg swings (the foot lands turned) and returns to 0 during stance (the body turns over the planted foot). Changing the step length of one leg would also turn the robot, but it unbalances the gait; rotating the feet does not.

Task Description

Objective

Implement the functions marked IMPLEMENT HERE in controllers/sprinter/sprinter.py:

  1. foot_trajectory(phase, step_length, step_height, double_support): the foot's forward position and lift for a leg's phase.
  2. leg_inverse_kinematics(x, z): hip, knee and ankle pitch that put the ankle at \((x, z)\) with the foot flat.
  3. lateral_sway(phase, amplitude, lead): the hip roll that moves the weight over the stance foot.
  4. balance_correction(roll, pitch, pitch_rate): the ankle pitch and roll corrections from the torso's tilt.
  5. heading_command(yaw, y, lane_y): the turn command that keeps the robot running straight in its lane.

The main loop that crouches, ramps the gait up, calls these functions and sets the joints is given. Once everything works, tune the gait constants to run faster.

System Configuration

  • Robot: NAO (Aldebaran/SoftBank), 0.58 m tall, 25 degrees of freedom; 6 per leg (hip yaw-pitch, hip roll, hip pitch, knee pitch, ankle pitch, ankle roll).
  • Sensors:
  • torso imu (InertialUnit, added in the body slot): roll, pitch, yaw [rad].
  • torso gyro (Gyro, added in the body slot): angular velocity about the torso's x, y, z axes [rad/s].
  • gps: torso position [m]; the race runs along \(+x\), the lane is the start \(y\).
  • Actuators: position-controlled joint motors; robot.py clamps each target to the joint's limits (for example knee pitch from -0.09 to 2.11 rad, hip pitch from -1.77 to 0.48 rad).
  • Environment: an 11 m × 3 m track (lanes 1 m wide) on grass, foot-ground friction coefficient 7; control step 20 ms.
  • Supervisor: race_stopwatch (the stopwatch at the finish) reads the NAO's real position, shows the time and ends the run.

Performance Metrics

The supervisor writes metrics.json:

Metric Meaning
success the torso travelled 10 m along \(+x\) from its start position
time race time [s] when it finished (null otherwise); the clock starts with the simulation
distance_m distance covered along the track [m], at most 10
average_speed_mps distance_m divided by the run's duration [m/s]
max_lateral_offset_m largest sideways distance of the torso from its start \(y\) (the lane) [m]
fell the torso dropped below 0.20 m
ended_reason finished, fell, left_track, no_progress (less than 0.2 m in 20 s) or time_limit (90 s)
duration_s simulated time when the run ended [s]

Success means finishing; among successful runs a lower time is better. The reference solution finishes in about 40 s (0.25 m/s) and stays within a few centimetres of its lane.

Suggested Algorithm

At each control step:

  1. Read the torso's roll, pitch and yaw, its pitch rate and its position.
  2. Compute the crouch factor (the first second bends the knees) and the gait ramp (stepping starts at 1.5 s and grows to full size in 2 s, so the robot does not start with a full step).
  3. Compute the gait phase \(\varphi\); for each leg take its phase (\(\varphi\) or \(\varphi + \pi\)), its foot trajectory, and solve the leg's inverse kinematics for \((x, z - h)\).
  4. Compute the lateral sway, the ankle balance corrections and the turn command.
  5. Send the joint targets: hip/knee/ankle pitch (with the ankle correction), hip and ankle roll (sway and correction), hip yaw (the turn), and an arm swing opposite to the legs, which cancels part of the legs' yaw moment.

Validation Checklist

  • In the first second the robot bends its knees and stays upright; stepping begins smoothly.
  • The torso rocks left and right in time with the steps, and each foot lifts while the weight is on the other one.
  • The feet land flat (no stubbing toes, no heel strikes that bounce the robot back).
  • The console's pitch and roll stay within about \(\pm 0.1\) rad; yaw stays near 0.
  • y stays within a few centimetres of its start value for the whole race.
  • The supervisor prints a mark every metre and success: true at the end.

References

Extension Ideas

  • Run faster: raise STEP_FREQUENCY and STEP_LENGTH together, and retune the sway and balance gains so the gait stays stable. Compare the measured speed with \(2Sf\).
  • Use the foot pressure sensors (LFsr, RFsr) to detect touchdown and adapt the phase to the real contact timing.
  • Plot the commanded and measured joint angles of one leg over a gait cycle with Matplotlib, and see how far the motors lag behind the targets at higher frequencies.