kick-right-giant-ball

Right-foot kick for a 300 mm, 0.275 kg ball (bigger than the 250 mm duck) from a standing start, with +-1 deg of gear play in every servo. v2 of this repo: v1 plus 3,000 iterations (16,000 to 19,000) with a penalty on the ball's sideways speed (our fork Mjlab-BallKick-Flat-Backlash-Big-Aim-MicroDuck, weight 20), so the kick goes along the way the duck faces; 4096 envs, 62 min on one RTX 5090. Trained in simulation only. Blind to the ball and the goal (the maker's task gives the policy no ball observation), so the ball must sit at the right toe (ball centre 0.205 m ahead in training). On the tests picked before training (giant ball and a goal 1.4 m straight ahead, 15 takes per policy from standing, the duck stays standing): ball in the goal 15 of 15 against 2 of 15 for v1 (one-sided Fisher p < 0.0001), median ball direction 1.5 against 29.5 degrees off straight; ball at least 1.25 m away after 2 s 15 of 15 against 12 of 15 (the goal net stops the ball, so power is kept, not shown to be gained). With the maker's random shoves, 10 takes (reported only): goal 10 of 10 against 3 of 10. One cost: on the stock 70 mm ball it stayed standing and kicked 1 m or more in 7 of 10 takes against 9 of 10 for v1 (two-sided p 0.58, not significant, direction down). Not yet tested on a real Microduck.

A episodic policy for the microduck (61-D observation, 14 actions, 50 Hz). Runs 1.0 s and returns itself to a standing pose.

Run it on a robot

sudo robotctl policy add kick-right-giant-ball witcheer/microduck-kick-right-giant-ball
robotctl robot do kick-right-giant-ball

The observation normalizer is baked into policy.onnx; feed raw observations. manifest.json follows schema 2 of the microduck policy manifest (docs/policy-manifest.md in the daemon repo).

Training

  • repo: pollen-robotics/microduck_rl
  • branch: develop
  • commit: 53b8971b6
  • exported from a checkout with uncommitted changes

Results in simulation (v2, 2026-10-27)

Simulation only. Not yet tested on a real Microduck.

v2 is v1 plus 3,000 training iterations with one change: a penalty on the ball's sideways speed. v1 kicked the 300 mm ball hard but about 30 degrees off to the right, so it rarely reached a goal straight ahead. v2 kicks along the way the duck faces. v1 stays installable as @v1 (see below).

Headline first, on the condition we picked in advance as the test of this run: with a 300 mm ball (0.275 kg, bigger than the 250 mm duck) and a goal 1.4 m straight ahead, 15 takes per policy, the duck stayed standing and the ball ended in the goal in 15 of 15 takes for v2 against 2 of 15 for v1 (one-sided Fisher exact p < 0.0001). The median direction of the ball's displacement at 1.5 s was 1.5 degrees off straight against 29.5 degrees. Both policies stayed standing in all 15 takes.

Power was checked on the same 15 takes and did not drop: the ball was at least 1.25 m from its start after 2 s in 15 of 15 takes for v2 against 12 of 15 for v1 (two-sided p = 0.22, no loss). Median travel after 2 s was 1.40 m against 1.35 m. The goal net stops the ball at about that distance, so read this as the power being kept, not as a stronger kick.

With the maker's play shoves on the giant ball, 10 takes per policy (reported only, no verdict weight): ball in the goal and duck standing 10 of 10 against 3 of 10 (two-sided p = 0.003).

One cost, stated up front: on the stock small ball it is a step back. With the maker's 70 mm ball at a random heading, no shoves, 10 takes per policy, the duck stayed standing and the ball travelled at least 1.0 m in 3 s in 7 of 10 takes for v2 against 9 of 10 for v1 (two-sided p = 0.58, not significant at 10 takes, but the direction is down). All 10 v2 takes kicked; the 3 misses are falls, with resets at 0.58, 0.68 and 0.96 s after the take started (v1 fell once, at 0.42 s). If you want the small ball, use kick-right (the maker's kick), not this repo.

What changed against v1, in our fork Mjlab-BallKick-Flat-Backlash-Big-Aim-MicroDuck (task file witcheer_ballkick_bigaim_env_cfg.py): one reward term switched on, the ball's speed perpendicular to the kick direction (the duck's heading at reset), absolute value, weight 20. Everything else is v1's task: the ball, the reset offset of 0.205 m, the forward-speed reward, the overshoot penalty, curricula, domain randomisation and the 5 s episodes. The policy is blind to the ball and the goal (the maker's ball task gives the actor no ball observation), so "aim" can only mean "kick along the heading you started with"; it does not see the goal. The goal exists only in the play setup, never in training, and the goal figures are for one fixed goal straight ahead.

The manifest says the checkout had uncommitted changes. Those are our fork registrations in tasks/__init__.py, our height patches for the velocity tasks and the Hub card metadata patch; this ball task uses none of the patches and reads the maker's code unmodified apart from the ball and the aim term.

Training: warm start from v1 (model_16000), 3,000 more iterations (16,000 to 19,000), 4096 envs, 62 min (1.25 s per iteration) on one RTX 5090, one uncut block. Over 100-iteration windows the mean reward was 46.0 at 16,100 (the resume ramp), 70.7 at 17,000, 75.2 at 18,000 and 77.7 at 19,000; it is not comparable with v1's 81.3 because the aim penalty is now part of the reward. The sideways-ball-speed reward term (weight included) went from -5.8 per episode at 16,100 to -1.4 at 19,000, and the fell_over termination rate was 0.143, 0.225, 0.165 and 0.119 per window.

Proof takes with headless_play, 1 env, standing spawn, 6 s each, samples every 0.1 s, a fixed camera, 15 takes per policy on the giant-ball condition (10 on the other two), v1 re-taken with the same settings the same day rather than reused. A take counts as standing when it has no tilt fall and no reset before the 6 s time-out. In the 15 giant-ball takes the trunk stays between 114 and 118 mm from 1.0 s to 5.9 s and is inside 100 to 125 mm from 0.5 s at the latest, with no mid-take reset; the worst tilt during the swing has gravity at -0.87 in the body frame (-1.0 is upright). duration_s is 1.0, the same as v1.

Not tested: any ball size or weight other than 70 mm and 300 mm, ball placement beyond the training noise, the left foot, a goal at any other angle or distance, kicking while walking, a second simulator, and a real robot. Not yet tested on a real Microduck.

Install (the default install is v2 once it is on main):

sudo robotctl policy add kick-right-giant-ball witcheer/microduck-kick-right-giant-ball
robotctl robot do kick-right-giant-ball

Run log: the microduck-skill-tree dataset carries the reward curve, queue item, fork files and take logs. The small-ball version is kick-right; more policies from the same tree appear under witcheer/microduck-*.

v1 (2026-10-26)

v1 is the kick this one was trained from: the maker's backlash kick plus 3,000 iterations on the giant ball, no aim term. On the test picked before training it kept the duck standing with the ball at least 1.25 m away after 2 s in 9 of 15 takes against 0 of 15 for the small-ball kick (one-sided Fisher p = 0.0003), median travel after 2 s 1.29 m against 0.77 m. It aimed worse: the ball reached the goal in 1 of 15 takes against 15 of 15, the ball leaving about 30 degrees off to one side. On the stock small ball it stayed standing in 7 of 10 takes against 10 of 10 (two-sided p = 0.21). The v2 comparison above re-took v1, where it reached the goal in 2 of 15 takes.

Install v1:

sudo robotctl policy add kick-right-giant-ball witcheer/microduck-kick-right-giant-ball@v1
robotctl robot do kick-right-giant-ball

Simulation only.

Downloads last month
41
Video Preview
loading

Collection including witcheer/microduck-kick-right-giant-ball