pusht-simulator / docs /html /human_pushing_analysis.html
desertmouse's picture
pages
473cc8a verified
Raw History Blame Contribute Delete
50.2 kB
<!doctype html><html><head><meta charset='utf-8'><title>How humans push the T: measurements from the Push-T demonstrations</title><style>
body{max-width:980px;margin:2rem auto;padding:0 1.25rem;font:15px/1.55 -apple-system,Segoe UI,Roboto,sans-serif;color:#1c2330;background:#fafbfc}
h1{font-size:1.7rem;border-bottom:2px solid #d8dee8;padding-bottom:.4rem}h2{margin-top:2.2rem;border-bottom:1px solid #e3e8ef;padding-bottom:.25rem}
table{border-collapse:collapse;margin:1rem 0;font-size:13.5px;font-variant-numeric:tabular-nums}th,td{border:1px solid #d8dee8;padding:.35rem .6rem;text-align:left}
th{background:#eef2f7}td:not(:first-child){text-align:right}code{background:#eef2f7;padding:.1rem .3rem;border-radius:3px;font-size:.92em}
pre{background:#1c2330;color:#e6edf5;padding:.8rem 1rem;border-radius:6px;overflow:auto}pre code{background:none;color:inherit}
img{max-width:100%;border:1px solid #d8dee8;border-radius:4px;margin:.5rem 0}blockquote{border-left:3px solid #6aa9ff;margin:0;padding:.2rem 1rem;color:#4b5563}
nav{font-size:13px;margin-bottom:1.5rem}nav a{margin-right:1rem}
</style></head><body><nav><a href="index.html">index</a> <a href="brain3_vs_3a_events.html">brain3 vs 3a events</a> <a href="contact_friction_study.html">contact friction study</a> <a href="convergence_study.html">convergence study</a> <a href="dataset_definition.html">dataset definition</a> <a href="ds08_distribution_at_1000.html">ds08 distribution at 1000</a> <a href="ds_distribution_at_1000.html">ds distribution at 1000</a> <a href="ds_distribution_report.html">ds distribution report</a> <a href="ds_mu03_brain3b_distribution.html">ds mu03 brain3b distribution</a> <a href="episode_store.html">episode store</a> <a href="human_pushing_analysis.html">human pushing analysis</a> <a href="lewm_parity.html">lewm parity</a> <a href="reference_parity.html">reference parity</a> <a href="session_fidelity_and_behaviour.html">session fidelity and behaviour</a></nav><h1 id="how-humans-push-the-t-measurements-from-the-push-t-demonstrations">How humans push the T: measurements from the Push-T demonstrations</h1>
<p>Generated by <code>scripts/analyze_human_pushing.py</code> from <code>kp_file0.parquet</code>; every number and figure below is that script's output. Reproduce with:</p>
<pre><code>.venv/bin/python scripts/analyze_human_pushing.py /tmp/kp_file0.parquet
</code></pre>
<h2 id="data-and-provenance">Data and provenance</h2>
<ul>
<li>Source: LeRobot <code>pusht_keypoints</code>, file 0: 206 episodes, 25650 frames at 10 Hz. Columns used: <code>observation.state</code> (agent centre), <code>observation.environment_state</code> (8 block keypoints), <code>next.reward</code>, <code>next.success</code>.</li>
<li>These are the original human teleoperation demonstrations (mouse-driven pusher, Diffusion Policy's Push-T). The LeWM paper's dataset (<code>galilai-group/lewm-pusht</code>) is the DINO-WM Push-T set, which is these same demonstrations replayed with action noise (DINO-WM App. A.1, LeWM App. E). Velocity, acceleration and jerk must therefore be measured on the clean demonstrations, as done here; the noised replays would corrupt them.</li>
<li>Block pose per frame is recovered by a rigid fit of the 8 keypoints to the local vertices (bar <code>(-60,0) (60,0) (60,30) (-60,30)</code>, stem <code>(-15,30) (15,30) (15,120) (-15,120)</code>); max fit residual over the file: 3.8e-05 px.</li>
<li>Reward check: <code>next.reward[t]</code> equals <code>clip(coverage[t+1] / 0.95, 0, 1)</code> with coverage computed by <code>pusht_sim.envs.geometry.coverage</code> from the recovered pose; max deviation over the analysed episodes 2.2e-07. "Final coverage" below is <code>0.95 x next.reward</code> of the last frame, i.e. the coverage of the terminal state.</li>
<li><code>next.success</code> is never True in this file: no demonstration reaches 0.95 coverage before it ends (max terminal coverage 0.901).</li>
</ul>
<h2 id="definitions">Definitions</h2>
<ul>
<li><strong>Frames.</strong> World: 512 x 512 px, origin top-left. Block vertex frame: x along the bar, y from the bar's outer (top) edge (y = 0) through the bar (0..30) to the stem tip (y = 120); CoG at (0, 45); R = +x side, L = -x side. Goal pose (256, 256, 45 deg).</li>
<li><strong>Contact.</strong> <code>gap = dist(agent centre, T outline) - 15</code> (negative when the centre is inside the outline). Contact iff <code>gap &lt;= 1.0 px</code>. The gap histogram over all 25650 frames has a spike in (-1, 0.5] px (Chipmunk's collision slop) and a flat tail beyond, so the threshold is not sensitive between 0.5 and 1.5 px.</li>
<li><strong>Contact point / edge / normal.</strong> Nearest point of the outline to the agent centre, in the vertex frame; the edge is the nearest of the 8 outline segments (<code>bar_top</code> y=0, <code>bar_end_R/L</code> x=+-60, <code>bar_bottom_R/L</code> y=30 beside the stem, <code>stem_R/L</code> x=+-15, <code>stem_tip</code> y=120); the outward normal is the unit vector from that point to the agent centre (at corners this is the corner-to-centre direction).</li>
<li><strong>Kinematics.</strong> Forward differences at DT = 0.1 s: <code>v[t] = (p[t+1]-p[t])/DT</code>, <code>a[t] = (v[t+1]-v[t])/DT</code>, <code>j[t] = (a[t+1]-a[t])/DT</code>; the report uses <code>|a|</code> and <code>|j|</code>. Block CoG velocity and rotation rate <code>omega</code> likewise from the recovered pose. Units px/s, px/s^2, px/s^3, rad/s (deg/s in tables).</li>
<li><strong>Roles (per frame).</strong> Let <code>v_n = -v . n_out</code> (speed into the block) and <code>v_t = |v . tangent|</code> at the nearest outline point; <code>dgap = (gap[t+1]-gap[t])/DT</code>.</li>
<li><code>TOUCH</code>: first frame of a contact bout (<code>contact[t] and not contact[t-1]</code>).</li>
<li><code>PUSH</code>: in contact, not TOUCH, <code>speed &gt;= 10</code> px/s and <code>v_n &gt;= v_t</code> (moving into the block, within 45 deg of the inward normal).</li>
<li><code>HOLD</code>: in contact, not TOUCH, <code>speed &lt; 10</code> px/s (pausing while touching; kept separate so PUSH/SLIDE speeds are not diluted).</li>
<li><code>RETREAT</code> (release step): in contact, not TOUCH, <code>speed &gt;= 10</code> px/s and <code>-v_n &gt;= v_t</code> (moving away from the block faster than along it: this is the step that breaks contact).</li>
<li><code>SLIDE</code>: in contact, not TOUCH, <code>speed &gt;= 10</code> px/s and <code>v_t &gt; |v_n|</code> (moving along the outline).</li>
<li><code>APPROACH</code>: no contact, <code>speed &gt;= 10</code> px/s and closing speed <code>-dgap &gt;= sqrt(speed^2 - dgap^2)</code>, i.e. heading within 45 deg of the nearest outline point. The step that makes contact (<code>contact[t+1]</code>) is always APPROACH: contact resolution shortens its normal component, so its heading is not meaningful.</li>
<li><code>RETREAT</code>: no contact, <code>speed &gt;= 10</code> px/s and <code>dgap &gt;= sqrt(speed^2 - dgap^2)</code>, i.e. heading within 45 deg of straight away from the outline.</li>
<li><code>REPLAN/IDLE</code>: no contact and either <code>speed &lt; 10</code> px/s (idle) or heading 45..135 deg off the outline direction (orbiting the block at roughly constant range to reach another edge). The same 45-deg normal-vs-tangential split is used in and out of contact.</li>
<li>The heading of no-contact motion (angle between the velocity and the direction to the nearest outline point) is unimodal, so any split is a convention; its distribution is reported in section 2 so the reader can re-cut it.</li>
<li>The last frame of an episode has no forward difference; it inherits the previous label (HOLD if that was TOUCH) or REPLAN/IDLE if not in contact.</li>
<li><strong>Bouts.</strong> Maximal runs of contact frames. A touch is <em>deliberate</em> if it starts the episode's first bout or follows &gt;= 5 non-contact frames; otherwise it is a <em>re-contact</em> (chatter within one push).</li>
<li><strong>Errors.</strong> Position error = |goal CoG - block CoG| (px); angle error = wrap(goal angle - block angle) in (-180, 180] deg, positive = block must rotate in the +angle direction of the pose. Direction to goal is expressed in the block frame (<code>phi_g</code>, 0 deg = +x bar end, 90 = stem tip, -90 = bar top).</li>
<li><strong>Dominant error.</strong> Angle-dominant when <code>|angle error (rad)| x 60 px &gt; position error</code>, i.e. the angle error moves the bar ends farther than the CoG is off; position-dominant otherwise.</li>
<li><strong>Lever arm.</strong> <code>l = (q - CoG) x (-n_out)</code> at the contact point q: the perpendicular offset of an inward-normal push from the CoG, px; sign = sign of the torque it produces. <code>|l| &lt;= 15</code> px (one pusher radius) counts as a push through the CoG. A velocity-based variant uses the agent's velocity direction instead of the normal.</li>
<li><strong>Bearings.</strong> <code>bearing_block</code>: angle of the agent about the CoG in the block frame (same convention as <code>phi_g</code>). <code>bearing_goal</code>: signed angle between the goal-&gt;block axis and the CoG-&gt;agent vector; 0 = the agent is directly behind the block as seen from the goal (the pushing position), +-180 = between block and goal.</li>
</ul>
<h2 id="1-episode-selection">1. Episode selection</h2>
<p>206 of 206 episodes contain at least one contact frame; all analysis below uses the first 50 qualifying episodes by <code>episode_index</code> (0..49); the remaining 156 qualifying episodes are used only as an external hold-out for the contact-selection rule (section 6). No stratification by success is possible because <code>next.success</code> is never true.</p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>episode length (frames)</td>
<td>50</td>
<td>125</td>
<td>126</td>
<td>83</td>
<td>159</td>
</tr>
<tr>
<td>final coverage</td>
<td>50</td>
<td>0.849</td>
<td>0.854</td>
<td>0.821</td>
<td>0.874</td>
</tr>
<tr>
<td>max coverage seen in episode</td>
<td>50</td>
<td>0.850</td>
<td>0.855</td>
<td>0.821</td>
<td>0.875</td>
</tr>
<tr>
<td>initial position error (px)</td>
<td>50</td>
<td>118.6</td>
<td>122.4</td>
<td>49.5</td>
<td>175.4</td>
</tr>
<tr>
<td>initial</td>
<td>angle error</td>
<td>(deg)</td>
<td>50</td>
<td>89.2</td>
<td>88.6</td>
</tr>
<tr>
<td>contact bouts per episode</td>
<td>50</td>
<td>3.1</td>
<td>3.0</td>
<td>2.0</td>
<td>5.0</td>
</tr>
<tr>
<td>contact frames per episode</td>
<td>50</td>
<td>62.4</td>
<td>60.0</td>
<td>40.0</td>
<td>90.3</td>
</tr>
</tbody>
</table>
<p><img alt="episodes" src="../figures/human_pushing/episode_overview.png" /></p>
<p>Per episode:</p>
<table>
<thead>
<tr>
<th>episode</th>
<th>frames</th>
<th>success</th>
<th>final coverage</th>
<th>bouts</th>
<th>role sequence (run-length compressed)</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>161</td>
<td>no</td>
<td>0.830</td>
<td>3</td>
<td>R-I-A-T-P-S-P-S-I-R-I-A-T-P-H-P-H-P-H-S-I-A-T-P</td>
</tr>
<tr>
<td>1</td>
<td>118</td>
<td>no</td>
<td>0.855</td>
<td>2</td>
<td>I-A-T-P-S-P-S-P-S-P-H-S-I-R-I-A-T-H</td>
</tr>
<tr>
<td>2</td>
<td>141</td>
<td>no</td>
<td>0.860</td>
<td>2</td>
<td>R-I-A-T-P-S-P-S-P-S-P-S-P-S-H-S-I-A-T-P-S-R-I-A-I</td>
</tr>
<tr>
<td>3</td>
<td>159</td>
<td>no</td>
<td>0.874</td>
<td>3</td>
<td>R-I-A-T-P-S-I-R-I-A-T-P-S-R-I-A-T-P-S-P-S-P</td>
</tr>
<tr>
<td>4</td>
<td>159</td>
<td>no</td>
<td>0.864</td>
<td>4</td>
<td>I-R-I-A-T-P-H-P-H-R-I-A-T-P-R-I-A-I-A-T-P-H-S-I-A-T-P</td>
</tr>
<tr>
<td>5</td>
<td>157</td>
<td>no</td>
<td>0.853</td>
<td>2</td>
<td>I-A-T-P-S-P-R-I-A-I-A-T-S-P-H-R-I-A-I</td>
</tr>
<tr>
<td>6</td>
<td>69</td>
<td>no</td>
<td>0.845</td>
<td>2</td>
<td>I-A-T-P-S-R-I-A-T</td>
</tr>
<tr>
<td>7</td>
<td>169</td>
<td>no</td>
<td>0.854</td>
<td>6</td>
<td>R-I-A-T-P-S-I-A-T-I-A-T-P-S-H-S-I-A-T-P-S-R-I-A-T-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>8</td>
<td>80</td>
<td>no</td>
<td>0.831</td>
<td>3</td>
<td>I-A-I-A-T-P-H-R-I-A-T-P-S-P-S-I-R-I-A-T</td>
</tr>
<tr>
<td>9</td>
<td>134</td>
<td>no</td>
<td>0.866</td>
<td>3</td>
<td>I-A-I-A-I-A-T-P-S-P-S-I-A-T-P-H-S-R-I-A-I-A-T-P</td>
</tr>
<tr>
<td>10</td>
<td>188</td>
<td>no</td>
<td>0.873</td>
<td>4</td>
<td>I-A-I-A-T-P-S-P-H-S-I-A-T-P-H-S-P-S-I-R-I-A-T-P-H-R-I-A-T-P</td>
</tr>
<tr>
<td>11</td>
<td>149</td>
<td>no</td>
<td>0.863</td>
<td>2</td>
<td>A-I-R-I-A-I-A-I-A-T-P-S-P-S-P-S-P-S-P-S-P-S-P-H-S-I-A-T-P</td>
</tr>
<tr>
<td>12</td>
<td>140</td>
<td>no</td>
<td>0.855</td>
<td>5</td>
<td>I-R-I-A-T-P-S-I-A-T-P-S-I-A-T-P-S-R-I-A-T-S-P-H-R-I-A-T-H</td>
</tr>
<tr>
<td>13</td>
<td>125</td>
<td>no</td>
<td>0.864</td>
<td>3</td>
<td>I-R-I-A-T-P-R-I-A-T-P-S-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>14</td>
<td>107</td>
<td>no</td>
<td>0.834</td>
<td>3</td>
<td>A-I-R-I-A-I-A-T-P-S-P-H-S-I-A-T-P-S-I-A-T</td>
</tr>
<tr>
<td>15</td>
<td>153</td>
<td>no</td>
<td>0.797</td>
<td>6</td>
<td>A-I-A-T-P-S-I-A-T-P-S-R-I-A-T-P-R-I-A-T-P-S-R-I-A-T-P-H-P-S-I-R-I-A-I-A-T</td>
</tr>
<tr>
<td>16</td>
<td>126</td>
<td>no</td>
<td>0.841</td>
<td>3</td>
<td>I-A-T-P-S-I-R-I-A-T-P-H-R-I-A-T-P-S-P-S-P</td>
</tr>
<tr>
<td>17</td>
<td>102</td>
<td>no</td>
<td>0.827</td>
<td>2</td>
<td>I-A-T-S-P-S-P-S-P-R-I-A-T-P-S-P-S-H-P</td>
</tr>
<tr>
<td>18</td>
<td>86</td>
<td>no</td>
<td>0.860</td>
<td>2</td>
<td>I-A-I-A-T-P-S-P-S-I-A-T-P-H-P-S-P</td>
</tr>
<tr>
<td>19</td>
<td>75</td>
<td>no</td>
<td>0.836</td>
<td>1</td>
<td>A-I-A-T-P-S-P-S-P</td>
</tr>
<tr>
<td>20</td>
<td>142</td>
<td>no</td>
<td>0.867</td>
<td>3</td>
<td>I-R-I-A-T-P-S-P-S-P-H-P-S-I-R-I-A-I-A-T-P-R-I-A-T</td>
</tr>
<tr>
<td>21</td>
<td>115</td>
<td>no</td>
<td>0.875</td>
<td>2</td>
<td>I-A-T-P-H-P-R-I-A-T-P</td>
</tr>
<tr>
<td>22</td>
<td>109</td>
<td>no</td>
<td>0.875</td>
<td>4</td>
<td>R-I-A-T-P-S-I-A-T-P-S-I-A-T-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>23</td>
<td>110</td>
<td>no</td>
<td>0.843</td>
<td>3</td>
<td>I-A-T-P-S-R-I-A-T-P-H-S-R-I-A-T-P</td>
</tr>
<tr>
<td>24</td>
<td>98</td>
<td>no</td>
<td>0.835</td>
<td>3</td>
<td>I-A-I-A-T-P-S-R-I-A-T-P-H-P-S-I-A-T-P</td>
</tr>
<tr>
<td>25</td>
<td>133</td>
<td>no</td>
<td>0.870</td>
<td>2</td>
<td>A-R-I-A-T-P-S-P-S-P-S-I-A-T-P</td>
</tr>
<tr>
<td>26</td>
<td>158</td>
<td>no</td>
<td>0.845</td>
<td>5</td>
<td>I-A-I-A-T-P-S-P-S-R-I-A-T-S-P-S-A-T-P-S-R-I-A-T-P-H-R-I-A-T</td>
</tr>
<tr>
<td>27</td>
<td>112</td>
<td>no</td>
<td>0.820</td>
<td>3</td>
<td>I-A-I-A-I-A-T-P-H-P-S-I-A-I-A-T-P-H-P-S-I-R-I-A-T-P</td>
</tr>
<tr>
<td>28</td>
<td>107</td>
<td>no</td>
<td>0.847</td>
<td>2</td>
<td>I-A-T-P-H-P-R-I-A-T-P</td>
</tr>
<tr>
<td>29</td>
<td>115</td>
<td>no</td>
<td>0.821</td>
<td>2</td>
<td>I-A-I-A-T-S-P-S-P-S-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>30</td>
<td>84</td>
<td>no</td>
<td>0.842</td>
<td>2</td>
<td>I-A-T-P-S-P-R-I-A-T-P</td>
</tr>
<tr>
<td>31</td>
<td>95</td>
<td>no</td>
<td>0.892</td>
<td>3</td>
<td>I-R-I-A-T-P-S-I-A-T-S-P-S-P-S-P-S-P-H-S-I-A-T-P</td>
</tr>
<tr>
<td>32</td>
<td>148</td>
<td>no</td>
<td>0.901</td>
<td>4</td>
<td>A-I-A-I-A-T-P-S-P-S-R-I-A-T-P-H-S-I-A-T-P-S-I-A-T-H</td>
</tr>
<tr>
<td>33</td>
<td>120</td>
<td>no</td>
<td>0.866</td>
<td>3</td>
<td>A-R-A-I-A-T-P-H-R-I-A-T-P-S-I-A-T-P</td>
</tr>
<tr>
<td>34</td>
<td>142</td>
<td>no</td>
<td>0.855</td>
<td>4</td>
<td>I-A-I-A-T-P-S-P-S-P-S-R-I-A-T-P-S-I-R-I-A-I-A-T-P-S-R-I-A-T</td>
</tr>
<tr>
<td>35</td>
<td>143</td>
<td>no</td>
<td>0.852</td>
<td>2</td>
<td>R-I-A-I-A-T-S-P-S-P-S-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>36</td>
<td>142</td>
<td>no</td>
<td>0.861</td>
<td>3</td>
<td>A-I-A-T-P-S-P-H-S-I-R-I-A-I-A-I-A-T-P-R-I-A-T-P-H</td>
</tr>
<tr>
<td>37</td>
<td>121</td>
<td>no</td>
<td>0.831</td>
<td>3</td>
<td>I-A-I-A-T-P-S-P-S-I-A-T-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>38</td>
<td>186</td>
<td>no</td>
<td>0.859</td>
<td>7</td>
<td>I-R-I-A-I-A-I-A-T-P-S-I-A-T-P-S-I-A-T-P-S-P-S-R-I-A-T-P-H-P-H-R-I-A-T-P-S-I-A-T-P-R-I-A-T-P</td>
</tr>
<tr>
<td>39</td>
<td>99</td>
<td>no</td>
<td>0.838</td>
<td>2</td>
<td>R-I-A-I-A-T-P-S-P-S-P-S-P-S-P-S-P-S-R-I-A-T-P</td>
</tr>
<tr>
<td>40</td>
<td>139</td>
<td>no</td>
<td>0.870</td>
<td>3</td>
<td>I-A-I-A-T-P-S-P-S-P-S-P-S-P-S-R-I-A-T-P-S-P-H-R-I-A-T-S-P</td>
</tr>
<tr>
<td>41</td>
<td>73</td>
<td>no</td>
<td>0.835</td>
<td>2</td>
<td>R-A-T-P-H-P-H-P-R-I-A-T-P</td>
</tr>
<tr>
<td>42</td>
<td>136</td>
<td>no</td>
<td>0.782</td>
<td>4</td>
<td>I-A-I-A-T-P-H-R-I-A-T-P-S-P-S-R-I-A-T-P-S-I-A-T</td>
</tr>
<tr>
<td>43</td>
<td>118</td>
<td>no</td>
<td>0.888</td>
<td>6</td>
<td>T-P-S-I-R-I-A-T-S-I-A-T-P-R-I-A-T-I-A-T-P-S-P-S-P-S-P-S-P-S-I-A-I-A-T-P</td>
</tr>
<tr>
<td>44</td>
<td>127</td>
<td>no</td>
<td>0.866</td>
<td>3</td>
<td>I-A-T-P-S-R-I-A-I-A-T-P-S-H-S-P-H-S-I-A-T-P</td>
</tr>
<tr>
<td>45</td>
<td>152</td>
<td>no</td>
<td>0.790</td>
<td>4</td>
<td>I-A-T-P-S-I-R-I-A-T-P-H-S-I-A-I-A-T-P-H-P-R-I-A-T-H</td>
</tr>
<tr>
<td>46</td>
<td>83</td>
<td>no</td>
<td>0.862</td>
<td>2</td>
<td>I-R-I-A-T-P-S-P-S-P-S-P-S-P-S-P-S-P-S-I-A-T-P</td>
</tr>
<tr>
<td>47</td>
<td>109</td>
<td>no</td>
<td>0.855</td>
<td>2</td>
<td>I-A-I-A-I-A-T-P-S-P-R-I-A-T-P-S-P-S-P</td>
</tr>
<tr>
<td>48</td>
<td>138</td>
<td>no</td>
<td>0.838</td>
<td>3</td>
<td>I-R-I-A-I-A-T-S-P-S-I-A-T-S-P-S-P-R-S-I-A-T-P</td>
</tr>
<tr>
<td>49</td>
<td>83</td>
<td>no</td>
<td>0.796</td>
<td>2</td>
<td>I-A-I-A-T-P-S-R-I-A-T-P</td>
</tr>
</tbody>
</table>
<h2 id="2-phase-segmentation">2. Phase segmentation</h2>
<p>Per-frame labels are in <code>figures/human_pushing/frame_labels.csv</code>. Frame shares and run lengths (a run = maximal sequence of one role):</p>
<table>
<thead>
<tr>
<th>role</th>
<th>frames</th>
<th>share</th>
<th>runs</th>
<th>mean run (frames)</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>829</td>
<td>13.3%</td>
<td>202</td>
<td>4.1</td>
<td>4</td>
<td>1</td>
<td>8</td>
</tr>
<tr>
<td>TOUCH</td>
<td>154</td>
<td>2.5%</td>
<td>154</td>
<td>1.0</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>PUSH</td>
<td>2404</td>
<td>38.6%</td>
<td>232</td>
<td>10.4</td>
<td>7</td>
<td>2</td>
<td>25</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>6.7%</td>
<td>169</td>
<td>2.5</td>
<td>2</td>
<td>1</td>
<td>5</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>2.7%</td>
<td>88</td>
<td>1.9</td>
<td>2</td>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2156</td>
<td>34.6%</td>
<td>216</td>
<td>10.0</td>
<td>8</td>
<td>2</td>
<td>19</td>
</tr>
<tr>
<td>HOLD</td>
<td>106</td>
<td>1.7%</td>
<td>49</td>
<td>2.2</td>
<td>1</td>
<td>1</td>
<td>4</td>
</tr>
</tbody>
</table>
<ul>
<li>REPLAN/IDLE splits into 19 idle frames (speed &lt; 10 px/s) and 2137 orbiting frames (moving around the block at 45..135 deg to the outline direction).</li>
<li>Heading of no-contact motion relative to the nearest outline point (n = 3093 frames at &gt;= 10 px/s): median 74 deg, p10 18, p90 119; 24% within 45 deg of the block (APPROACH), 72% tangential (orbit), 4% within 45 deg of straight away (RETREAT).</li>
<li>The block is moving (CoG &gt;= 5 px/s or |omega| &gt;= 2 deg/s) in 98.5% of PUSH frames and 74.8% of SLIDE frames; it is rotating in 64.7% of SLIDE frames.</li>
<li>Contact bouts per episode: mean 3.08, median 3, p10 2, p90 5. Bout length (frames): median 17, p10 3, p90 40. Time between bouts (non-contact frames): median 16, p10 7, p90 25 (n = 104); 5 of these gaps are shorter than 5 frames (re-contacts).</li>
<li>Frames before the first touch: median 27, p10 14, p90 42.</li>
</ul>
<p>Transitions between consecutive runs (row = from, column = to, row-normalised %):</p>
<table>
<thead>
<tr>
<th>from \ to</th>
<th>APPROACH</th>
<th>TOUCH</th>
<th>PUSH</th>
<th>SLIDE</th>
<th>RETREAT</th>
<th>REPLAN/IDLE</th>
<th>HOLD</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH (n=202)</td>
<td>0</td>
<td>76</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>23</td>
<td>0</td>
</tr>
<tr>
<td>TOUCH (n=146)</td>
<td>0</td>
<td>0</td>
<td>88</td>
<td>8</td>
<td>0</td>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>PUSH (n=197)</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>71</td>
<td>8</td>
<td>0</td>
<td>21</td>
</tr>
<tr>
<td>SLIDE (n=169)</td>
<td>1</td>
<td>0</td>
<td>51</td>
<td>0</td>
<td>17</td>
<td>29</td>
<td>2</td>
</tr>
<tr>
<td>RETREAT (n=88)</td>
<td>2</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>97</td>
<td>0</td>
</tr>
<tr>
<td>REPLAN/IDLE (n=214)</td>
<td>89</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>11</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>HOLD (n=44)</td>
<td>0</td>
<td>0</td>
<td>36</td>
<td>39</td>
<td>25</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>Most frequent run trigrams (A=APPROACH, T=TOUCH, P=PUSH, S=SLIDE, R=RETREAT, I=REPLAN/IDLE, H=HOLD):</p>
<table>
<thead>
<tr>
<th>trigram</th>
<th>count</th>
</tr>
</thead>
<tbody>
<tr>
<td>I-A-T</td>
<td>151</td>
</tr>
<tr>
<td>A-T-P</td>
<td>128</td>
</tr>
<tr>
<td>R-I-A</td>
<td>85</td>
</tr>
<tr>
<td>P-S-P</td>
<td>75</td>
</tr>
<tr>
<td>T-P-S</td>
<td>69</td>
</tr>
<tr>
<td>S-P-S</td>
<td>65</td>
</tr>
<tr>
<td>A-I-A</td>
<td>43</td>
</tr>
<tr>
<td>I-A-I</td>
<td>40</td>
</tr>
<tr>
<td>S-I-A</td>
<td>36</td>
</tr>
<tr>
<td>P-S-I</td>
<td>34</td>
</tr>
<tr>
<td>S-R-I</td>
<td>28</td>
</tr>
<tr>
<td>P-S-R</td>
<td>26</td>
</tr>
</tbody>
</table>
<p>Within a bout, the first frame after TOUCH is PUSH in 90% of bouts longer than one frame, SLIDE in 8%. A bout contains PUSH in 90% of cases and SLIDE in 60%. 48 of the 154 bouts run to the end of the episode; for the 106 bouts that end in a release, the release step is SLIDE 61%, RETREAT 37%, TOUCH 2% (heading of the release step median 124 deg off the inward normal), and the first frame after release is REPLAN/IDLE 58%, RETREAT 41%, APPROACH 1%. The block is already at rest when contact is broken: block speed on the release step median 0.4 px/s, p90 2.2, below 5 px/s in 97% of releases; one frame later it is 0.0 px/s (median), so the block does not coast after release.</p>
<p><img alt="timeline" src="../figures/human_pushing/role_timeline.png" /></p>
<p><img alt="durations" src="../figures/human_pushing/role_durations.png" /></p>
<h2 id="3-kinematics-per-role">3. Kinematics per role</h2>
<p><strong>distance agent-outline minus radius (px)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>829</td>
<td>38.1</td>
<td>20.0</td>
<td>3.7</td>
<td>110.7</td>
</tr>
<tr>
<td>TOUCH</td>
<td>154</td>
<td>-0.2</td>
<td>-0.1</td>
<td>-0.5</td>
<td>0.6</td>
</tr>
<tr>
<td>PUSH</td>
<td>2404</td>
<td>-0.2</td>
<td>-0.1</td>
<td>-0.3</td>
<td>-0.0</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>-0.1</td>
<td>-0.1</td>
<td>-0.2</td>
<td>0.0</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>31.2</td>
<td>10.4</td>
<td>-0.0</td>
<td>87.1</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2156</td>
<td>46.8</td>
<td>36.8</td>
<td>10.5</td>
<td>92.8</td>
</tr>
<tr>
<td>HOLD</td>
<td>106</td>
<td>-0.0</td>
<td>-0.0</td>
<td>-0.1</td>
<td>-0.0</td>
</tr>
</tbody>
</table>
<p><img alt="gap" src="../figures/human_pushing/kin_gap.png" /></p>
<p><strong>heading relative to the block (deg; 0 = straight into the nearest outline point / inward normal, 90 = along it, 180 = straight away)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>829</td>
<td>26.2</td>
<td>24.5</td>
<td>4.1</td>
<td>44.7</td>
</tr>
<tr>
<td>TOUCH</td>
<td>144</td>
<td>20.8</td>
<td>15.6</td>
<td>3.3</td>
<td>51.3</td>
</tr>
<tr>
<td>PUSH</td>
<td>2369</td>
<td>18.3</td>
<td>16.1</td>
<td>2.9</td>
<td>36.7</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>70.7</td>
<td>63.6</td>
<td>47.3</td>
<td>103.2</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>150.7</td>
<td>147.7</td>
<td>137.1</td>
<td>168.7</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2135</td>
<td>84.7</td>
<td>82.9</td>
<td>55.8</td>
<td>116.7</td>
</tr>
<tr>
<td>HOLD</td>
<td>0</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
</tbody>
</table>
<p><img alt="heading" src="../figures/human_pushing/kin_heading.png" /></p>
<p><strong>bearing of agent about the CoG, block frame (deg; 0=+x bar end, 90=stem tip, -90=bar top)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>829</td>
<td>9.6</td>
<td>29.5</td>
<td>-155.3</td>
<td>146.7</td>
</tr>
<tr>
<td>TOUCH</td>
<td>154</td>
<td>3.8</td>
<td>17.0</td>
<td>-153.9</td>
<td>113.9</td>
</tr>
<tr>
<td>PUSH</td>
<td>2404</td>
<td>-21.8</td>
<td>-16.3</td>
<td>-179.4</td>
<td>115.1</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>-25.8</td>
<td>-17.0</td>
<td>-179.7</td>
<td>114.4</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>19.9</td>
<td>43.3</td>
<td>-140.3</td>
<td>150.5</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2156</td>
<td>-1.3</td>
<td>-2.7</td>
<td>-151.8</td>
<td>150.8</td>
</tr>
<tr>
<td>HOLD</td>
<td>106</td>
<td>-20.6</td>
<td>-0.1</td>
<td>-180.0</td>
<td>119.2</td>
</tr>
</tbody>
</table>
<p><img alt="bearing_block" src="../figures/human_pushing/kin_bearing_block.png" /></p>
<p><strong>bearing of agent off the goal-&gt;block axis (deg; 0=behind block, opposite the goal)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>829</td>
<td>10.0</td>
<td>3.6</td>
<td>-59.9</td>
<td>114.2</td>
</tr>
<tr>
<td>TOUCH</td>
<td>154</td>
<td>0.2</td>
<td>-0.1</td>
<td>-55.6</td>
<td>47.1</td>
</tr>
<tr>
<td>PUSH</td>
<td>2404</td>
<td>7.3</td>
<td>4.2</td>
<td>-72.0</td>
<td>89.3</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>5.3</td>
<td>8.0</td>
<td>-84.8</td>
<td>94.0</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>30.9</td>
<td>52.6</td>
<td>-117.6</td>
<td>158.5</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2156</td>
<td>7.9</td>
<td>10.8</td>
<td>-114.6</td>
<td>122.9</td>
</tr>
<tr>
<td>HOLD</td>
<td>106</td>
<td>44.1</td>
<td>68.7</td>
<td>-91.8</td>
<td>155.4</td>
</tr>
</tbody>
</table>
<p><img alt="bearing_goal" src="../figures/human_pushing/kin_bearing_goal.png" /></p>
<p><strong>agent speed (px/s)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>829</td>
<td>83.7</td>
<td>69.3</td>
<td>32.1</td>
<td>151.0</td>
</tr>
<tr>
<td>TOUCH</td>
<td>146</td>
<td>59.5</td>
<td>57.3</td>
<td>25.6</td>
<td>90.4</td>
</tr>
<tr>
<td>PUSH</td>
<td>2369</td>
<td>52.9</td>
<td>47.9</td>
<td>19.9</td>
<td>89.4</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>58.2</td>
<td>49.6</td>
<td>18.4</td>
<td>106.0</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>126.8</td>
<td>105.7</td>
<td>32.2</td>
<td>250.4</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2154</td>
<td>128.7</td>
<td>121.6</td>
<td>54.6</td>
<td>208.5</td>
</tr>
<tr>
<td>HOLD</td>
<td>101</td>
<td>6.4</td>
<td>6.5</td>
<td>2.9</td>
<td>9.1</td>
</tr>
</tbody>
</table>
<p><img alt="speed" src="../figures/human_pushing/kin_speed.png" /></p>
<p><strong>agent |acceleration| (px/s^2)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>819</td>
<td>194</td>
<td>147</td>
<td>50</td>
<td>362</td>
</tr>
<tr>
<td>TOUCH</td>
<td>142</td>
<td>120</td>
<td>104</td>
<td>40</td>
<td>207</td>
</tr>
<tr>
<td>PUSH</td>
<td>2334</td>
<td>121</td>
<td>88</td>
<td>29</td>
<td>230</td>
</tr>
<tr>
<td>SLIDE</td>
<td>416</td>
<td>280</td>
<td>145</td>
<td>43</td>
<td>730</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>706</td>
<td>567</td>
<td>224</td>
<td>1244</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2154</td>
<td>360</td>
<td>305</td>
<td>105</td>
<td>682</td>
</tr>
<tr>
<td>HOLD</td>
<td>100</td>
<td>216</td>
<td>47</td>
<td>15</td>
<td>764</td>
</tr>
</tbody>
</table>
<p><img alt="accel" src="../figures/human_pushing/kin_accel.png" /></p>
<p><strong>agent |jerk| (px/s^3)</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH</td>
<td>806</td>
<td>1592</td>
<td>1097</td>
<td>331</td>
<td>3105</td>
</tr>
<tr>
<td>TOUCH</td>
<td>141</td>
<td>1055</td>
<td>828</td>
<td>268</td>
<td>1896</td>
</tr>
<tr>
<td>PUSH</td>
<td>2302</td>
<td>1311</td>
<td>798</td>
<td>252</td>
<td>2625</td>
</tr>
<tr>
<td>SLIDE</td>
<td>415</td>
<td>2801</td>
<td>1316</td>
<td>313</td>
<td>7583</td>
</tr>
<tr>
<td>RETREAT</td>
<td>170</td>
<td>6032</td>
<td>4054</td>
<td>1727</td>
<td>12127</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>2153</td>
<td>2444</td>
<td>1778</td>
<td>533</td>
<td>5131</td>
</tr>
<tr>
<td>HOLD</td>
<td>98</td>
<td>2481</td>
<td>708</td>
<td>144</td>
<td>6606</td>
</tr>
</tbody>
</table>
<p><img alt="jerk" src="../figures/human_pushing/kin_jerk.png" /></p>
<p>Block motion per role (block CoG speed px/s, |rotation rate| deg/s):</p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>APPROACH block speed</td>
<td>829</td>
<td>2.0</td>
<td>0.0</td>
<td>0.0</td>
<td>4.8</td>
</tr>
<tr>
<td>TOUCH block speed</td>
<td>146</td>
<td>37.6</td>
<td>34.4</td>
<td>12.9</td>
<td>67.1</td>
</tr>
<tr>
<td>PUSH block speed</td>
<td>2369</td>
<td>35.8</td>
<td>32.4</td>
<td>13.7</td>
<td>60.6</td>
</tr>
<tr>
<td>SLIDE block speed</td>
<td>416</td>
<td>17.2</td>
<td>12.0</td>
<td>0.1</td>
<td>43.9</td>
</tr>
<tr>
<td>RETREAT block speed</td>
<td>170</td>
<td>0.2</td>
<td>0.0</td>
<td>0.0</td>
<td>0.6</td>
</tr>
<tr>
<td>REPLAN/IDLE block speed</td>
<td>2154</td>
<td>0.0</td>
<td>0.0</td>
<td>0.0</td>
<td>0.0</td>
</tr>
<tr>
<td>HOLD block speed</td>
<td>101</td>
<td>4.2</td>
<td>4.0</td>
<td>1.2</td>
<td>7.6</td>
</tr>
<tr>
<td>APPROACH</td>
<td>omega</td>
<td></td>
<td>829</td>
<td>1.0</td>
<td>0.0</td>
</tr>
<tr>
<td>TOUCH</td>
<td>omega</td>
<td></td>
<td>146</td>
<td>17.7</td>
<td>11.9</td>
</tr>
<tr>
<td>PUSH</td>
<td>omega</td>
<td></td>
<td>2369</td>
<td>18.1</td>
<td>15.4</td>
</tr>
<tr>
<td>SLIDE</td>
<td>omega</td>
<td></td>
<td>416</td>
<td>7.6</td>
<td>4.5</td>
</tr>
<tr>
<td>RETREAT</td>
<td>omega</td>
<td></td>
<td>170</td>
<td>0.1</td>
<td>0.0</td>
</tr>
<tr>
<td>REPLAN/IDLE</td>
<td>omega</td>
<td></td>
<td>2154</td>
<td>0.0</td>
<td>0.0</td>
</tr>
<tr>
<td>HOLD</td>
<td>omega</td>
<td></td>
<td>101</td>
<td>1.8</td>
<td>1.7</td>
</tr>
</tbody>
</table>
<h2 id="4-approach-geometry-at-touch">4. Approach geometry at TOUCH</h2>
<p>154 touches in the 50 episodes, 149 deliberate (first bout or &gt;= 5 non-contact frames before) and 5 re-contacts. Statistics below are over deliberate touches; the approach velocity at touch is the last free-flight step before the contact step, <code>(p[t-1]-p[t-2])/DT</code> (the contact step itself is shortened along the normal by contact resolution and would bias the incidence towards glancing), and the incidence angle is measured between it and the inward normal at the contact point (0 = head-on, 90 = glancing).</p>
<table>
<thead>
<tr>
<th>edge</th>
<th>touches</th>
<th>share</th>
</tr>
</thead>
<tbody>
<tr>
<td>bar_top</td>
<td>39</td>
<td>26.2%</td>
</tr>
<tr>
<td>bar_end_R</td>
<td>7</td>
<td>4.7%</td>
</tr>
<tr>
<td>bar_bottom_R</td>
<td>4</td>
<td>2.7%</td>
</tr>
<tr>
<td>stem_R</td>
<td>25</td>
<td>16.8%</td>
</tr>
<tr>
<td>stem_tip</td>
<td>33</td>
<td>22.1%</td>
</tr>
<tr>
<td>stem_L</td>
<td>20</td>
<td>13.4%</td>
</tr>
<tr>
<td>bar_bottom_L</td>
<td>9</td>
<td>6.0%</td>
</tr>
<tr>
<td>bar_end_L</td>
<td>12</td>
<td>8.1%</td>
</tr>
<tr>
<td><em>stem_side</em> (L+R)</td>
<td>45</td>
<td>30.2%</td>
</tr>
<tr>
<td><em>bar_top</em> (L+R)</td>
<td>39</td>
<td>26.2%</td>
</tr>
<tr>
<td><em>stem_tip</em> (L+R)</td>
<td>33</td>
<td>22.1%</td>
</tr>
<tr>
<td><em>bar_end</em> (L+R)</td>
<td>19</td>
<td>12.8%</td>
</tr>
<tr>
<td><em>bar_bottom</em> (L+R)</td>
<td>13</td>
<td>8.7%</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>incidence angle (deg)</td>
<td>149</td>
<td>23.6</td>
<td>17.1</td>
<td>2.0</td>
<td>51.3</td>
</tr>
<tr>
<td>approach speed at touch (px/s)</td>
<td>149</td>
<td>68.0</td>
<td>67.0</td>
<td>29.2</td>
<td>105.9</td>
</tr>
<tr>
<td>APPROACH run length before touch (frames)</td>
<td>149</td>
<td>4</td>
<td>4</td>
<td>1</td>
<td>8</td>
</tr>
<tr>
<td>standoff before re-approach: max gap between bouts (px)</td>
<td>99</td>
<td>42.0</td>
<td>38.8</td>
<td>16.7</td>
<td>70.1</td>
</tr>
<tr>
<td>bearing change around block, last contact -&gt; next touch (deg)</td>
<td>99</td>
<td>-25.5</td>
<td>-28.4</td>
<td>-130.6</td>
<td>104.3</td>
</tr>
<tr>
<td></td>
<td>bearing change</td>
<td>(deg)</td>
<td>99</td>
<td>81.8</td>
<td>88.6</td>
</tr>
<tr>
<td>non-contact frames before touch (bouts after the first)</td>
<td>99</td>
<td>17</td>
<td>16</td>
<td>9</td>
<td>25</td>
</tr>
<tr>
<td></td>
<td>agent bearing off goal-&gt;block axis</td>
<td>at touch (deg, all bouts)</td>
<td>154</td>
<td>31.9</td>
<td>24.4</td>
</tr>
<tr>
<td></td>
<td>agent bearing off goal-&gt;block axis</td>
<td>at release (deg, released bouts)</td>
<td>106</td>
<td>85.4</td>
<td>85.5</td>
</tr>
</tbody>
</table>
<p>Head-on share (incidence &lt;= 30 deg): 72%; glancing share (incidence &gt;= 60 deg): 7%. The edge touched is the one nearest the agent at the previous release (or at the episode start) in 9% of deliberate touches (11% by edge type): the pusher usually travels to a different edge rather than touching the nearest one. Perimeter distance travelled around the outline from the previous release point to the next touch point: median 98 px, p10 25, p90 182 (perimeter 480 px). Gap at the start of the final APPROACH run: median 23 px, p10 3, p90 54.</p>
<p><img alt="touch" src="../figures/human_pushing/touch_geometry.png" /></p>
<p><img alt="overlay" src="../figures/human_pushing/contact_points_overlay.png" /></p>
<h2 id="5-push-dynamics">5. Push dynamics</h2>
<p>Over PUSH frames with a defined rotation rate (n = 2369): Pearson correlation between the inward-normal lever arm and the block rotation rate r = 0.869 (velocity-direction lever arm: r = 0.854); least-squares slope 0.562 deg/s per px of lever arm; the sign of the lever arm matches the sign of the rotation in 100% of PUSH frames where the block rotates faster than 2 deg/s.</p>
<p>| PUSH frames by dominant error | n | median |lever| (px) | through CoG (|l| &lt;= 15 px) | corrective torque sign | median block speed (px/s) | median |omega| (deg/s) |
|---|---|---|---|---|---|---|
| position-dominant | 1883 | 25.2 | 40.4 | 78.5 | 31.4 | 11.5 |
| angle-dominant | 486 | 42.5 | 11.5 | 99.4 | 35.5 | 26.1 |
| all PUSH | 2369 | 30.1 | 34.4 | 82.8 | 32.4 | 15.4 |</p>
<p>| |angle error| bin (deg) | PUSH frames | median |lever| (px) | lever sign corrective | rotation sign corrective | median |omega| (deg/s) |
|---|---|---|---|---|---|
| 0-5 | 652 | 5.7 | 56.7 | 57.5 | 3.9 |
| 5-10 | 286 | 11.8 | 79.4 | 80.4 | 6.4 |
| 10-20 | 275 | 33.9 | 92.0 | 93.8 | 15.2 |
| 20-30 | 191 | 37.8 | 92.7 | 92.7 | 19.4 |
| 30-45 | 197 | 42.5 | 99.0 | 99.5 | 29.0 |
| 45-60 | 197 | 42.7 | 92.9 | 93.4 | 25.4 |
| 60-90 | 266 | 43.3 | 96.2 | 96.2 | 28.6 |
| 90-180 | 305 | 36.5 | 98.7 | 98.4 | 27.5 |</p>
<p>Per bout (all bouts, n = 154):</p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>block CoG displacement per bout (px)</td>
<td>154</td>
<td>57.4</td>
<td>44.0</td>
<td>4.4</td>
<td>125.1</td>
</tr>
<tr>
<td>displacement toward goal per bout (px)</td>
<td>154</td>
<td>49.0</td>
<td>35.0</td>
<td>0.0</td>
<td>115.5</td>
</tr>
<tr>
<td>efficiency = toward-goal / total displacement</td>
<td>154</td>
<td>0.72</td>
<td>0.95</td>
<td>0.00</td>
<td>1.00</td>
</tr>
<tr>
<td>block rotation per bout (deg)</td>
<td>154</td>
<td>-0.0</td>
<td>0.0</td>
<td>-62.8</td>
<td>60.1</td>
</tr>
<tr>
<td></td>
<td>rotation</td>
<td>per bout (deg)</td>
<td>154</td>
<td>30.3</td>
<td>9.4</td>
</tr>
<tr>
<td>position error reduced per bout (px)</td>
<td>154</td>
<td>35.7</td>
<td>19.9</td>
<td>-1.0</td>
<td>102.1</td>
</tr>
<tr>
<td></td>
<td>angle error</td>
<td>reduced per bout (deg)</td>
<td>154</td>
<td>27.7</td>
<td>5.5</td>
</tr>
<tr>
<td>bout length (frames)</td>
<td>154</td>
<td>20</td>
<td>17</td>
<td>3</td>
<td>40</td>
</tr>
<tr>
<td>block speed on the release step (px/s, released bouts)</td>
<td>106</td>
<td>1.0</td>
<td>0.4</td>
<td>0.0</td>
<td>2.2</td>
</tr>
<tr>
<td>agent speed on the release step (px/s)</td>
<td>106</td>
<td>90.7</td>
<td>75.9</td>
<td>30.0</td>
<td>183.3</td>
</tr>
</tbody>
</table>
<p>What a bout achieves and when it is released (106 released bouts; the 48 bouts that run to the end of the episode are listed separately). <em>Push alignment</em> is the angle between the inward normal at the contact point (the push direction) and the CoG-&gt;goal direction.</p>
<table>
<thead>
<tr>
<th></th>
<th>n</th>
<th>mean</th>
<th>median</th>
<th>p10</th>
<th>p90</th>
</tr>
</thead>
<tbody>
<tr>
<td>push alignment at touch (deg, all bouts)</td>
<td>154</td>
<td>39.1</td>
<td>26.5</td>
<td>2.5</td>
<td>87.2</td>
</tr>
<tr>
<td>push alignment at release (deg)</td>
<td>106</td>
<td>92.1</td>
<td>88.8</td>
<td>47.6</td>
<td>152.0</td>
</tr>
<tr>
<td>push alignment at episode end (deg, final bouts)</td>
<td>48</td>
<td>22.2</td>
<td>13.9</td>
<td>2.8</td>
<td>53.2</td>
</tr>
<tr>
<td>position error at touch (px)</td>
<td>106</td>
<td>92.1</td>
<td>95.6</td>
<td>21.7</td>
<td>159.9</td>
</tr>
<tr>
<td>position error at release (px)</td>
<td>106</td>
<td>56.4</td>
<td>48.3</td>
<td>9.4</td>
<td>115.9</td>
</tr>
<tr>
<td></td>
<td>angle error</td>
<td>at touch (deg)</td>
<td>106</td>
<td>57.9</td>
<td>53.3</td>
</tr>
<tr>
<td></td>
<td>angle error</td>
<td>at release (deg)</td>
<td>106</td>
<td>18.7</td>
<td>5.3</td>
</tr>
<tr>
<td>position error at episode end (px, final bouts)</td>
<td>48</td>
<td>6.4</td>
<td>6.2</td>
<td>4.8</td>
<td>8.2</td>
</tr>
<tr>
<td></td>
<td>angle error</td>
<td>at episode end (deg, final bouts)</td>
<td>48</td>
<td>2.2</td>
<td>1.8</td>
</tr>
</tbody>
</table>
<p>Release happens with the push alignment above 45 deg in 91% of released bouts (above 60 deg in 83%), versus 34% of touches made with alignment above 45 deg. By release the bout has reduced the position error by more than 5 px in 71% of cases and the |angle error| by more than 5 deg in 70% (both 50%, neither 9%); the angle error changes sign during 24% of released bouts (overshoot).</p>
<p><img alt="push" src="../figures/human_pushing/push_dynamics.png" /></p>
<p><img alt="bouts" src="../figures/human_pushing/bout_release.png" /></p>
<h2 id="6-contact-selection-vs-error">6. Contact selection vs error</h2>
<p>Edge type chosen at deliberate touches, split by dominant error:</p>
<table>
<thead>
<tr>
<th>dominant error</th>
<th>touches</th>
<th>bar_top</th>
<th>bar_end</th>
<th>bar_bottom</th>
<th>stem_side</th>
<th>stem_tip</th>
</tr>
</thead>
<tbody>
<tr>
<td>position-dominant</td>
<td>120</td>
<td>28%</td>
<td>13%</td>
<td>7%</td>
<td>28%</td>
<td>24%</td>
</tr>
<tr>
<td>angle-dominant</td>
<td>29</td>
<td>21%</td>
<td>10%</td>
<td>17%</td>
<td>38%</td>
<td>14%</td>
</tr>
</tbody>
</table>
<p>Decision table fitted on all 149 deliberate touches of the 50 episodes. Events are mirrored across the stem axis so the goal is on the +x side (angle error and edge L/R flip with it); rows = direction to goal in the block frame, columns = angle error; cell = majority edge and its share:</p>
<p>| goal direction phi_g (deg) \ angle error (deg) | &lt; -15 | |ang| &lt;= 15 | &gt; 15 |
|---|---|---|---|
| -90..-45 (bar-top side) | stem_L 4/7 | stem_tip 25/31 | stem_R 6/15 |
| -45..0 | stem_L 5/7 | stem_L 9/15 | bar_bottom_L 4/12 |
| 0..45 | bar_top 6/9 | stem_L 4/9 | stem_tip 1/2 |
| 45..90 (stem-tip side) | bar_top 5/8 | bar_top 20/25 | bar_top 5/9 |</p>
<p>Contact-point model: every candidate point q on the perimeter (every 5 px) gets a score <code>w1 * (-n_out . g) + w2 * (l/60) * angle_err + w3 * (-|l|/60)</code> where g is the unit direction to the goal in the block frame, l the lever arm of an inward push at q and angle_err in radians; the chosen point is a softmax draw (conditional logit) and the prediction is the argmax. <code>goal-normal</code> is the unfitted rule w = (1, 0, ~0): push where the inward normal points at the goal, as close to the CoG line as possible.</p>
<p>Fitted weights on all deliberate touches: w = (1.79, 2.97, 1.92).</p>
<table>
<thead>
<tr>
<th>rule</th>
<th>edge accuracy % (5-fold CV by episode, 50 eps)</th>
<th>edge accuracy % (external hold-out, 156 eps, 540 touches)</th>
<th>edge-type accuracy % (CV)</th>
<th>median perimeter error px (CV)</th>
</tr>
</thead>
<tbody>
<tr>
<td>majority edge</td>
<td>26.8</td>
<td>23.3</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>goal-normal (unfitted)</td>
<td>57.1</td>
<td>48.7</td>
<td>58.3</td>
<td>32.5</td>
</tr>
<tr>
<td>decision table (fitted)</td>
<td>54.5</td>
<td>56.3</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>contact-point logit (fitted)</td>
<td>56.4</td>
<td>50.7</td>
<td>56.4</td>
<td>24.5</td>
</tr>
</tbody>
</table>
<p>External hold-out for the logit: edge-type accuracy 51.1%, median perimeter error 45.0 px, p90 170.5 px. Chance level for 8 edges is 12.5%.</p>
<p><img alt="edge" src="../figures/human_pushing/edge_choice_vs_error.png" /></p>
<h2 id="7-design-implications-for-a-scripted-controller">7. Design implications for a scripted controller</h2>
<p>Each statement is read off the tables above (medians unless stated; p10-p90 in brackets). Speeds are agent-centre speeds at 10 Hz.</p>
<ol>
<li><strong>Approach speed and standoff.</strong> Do not back off and come in radially: 72% of no-contact motion is tangential (heading 45-135 deg to the outline). Orbit the block to the chosen edge at 123 px/s [57-210] with |acceleration| 305 px/s^2 [106-678], keeping a gap of 37 px [10-93] to the outline (max standoff between bouts 39 px [17-70]). The final radial APPROACH run is 4 frames [1-8] long, starts from a gap of 23 px [3-54], runs at 69 px/s [32-151] and arrives at 67 px/s [29-106]. The whole release-to-touch interval is 16 frames [7-25] and covers 98 px [25-182] of the 480 px perimeter.</li>
<li><strong>Contact normal alignment.</strong> Arrive along the inward normal: incidence 17 deg [2-51], 72% of touches within 30 deg, 7% glancing. Arrive behind the block as seen from the goal: bearing off the goal-&gt;block axis 24 deg [3-74] at touch, push alignment (push normal vs CoG-&gt;goal) 26 deg [3-87]. The edge is chosen by the goal geometry (item 7), not by proximity: the edge nearest the pusher at the previous release is touched only 9% of the time.</li>
<li><strong>Push depth and speed.</strong> Drive into the block at 48 px/s [20-89] (|acceleration| 88 px/s^2 [29-230], |jerk| 798 px/s^3 [252-2625]); the block follows at 32 px/s. One bout lasts 17 frames [3-40], displaces the CoG 44 px [4-125] with 0.95 of it along the goal direction, and rotates the block 9 deg [0-94]; it takes the position error from 96 to 48 px and the |angle error| from 53 to 5 deg (medians, released bouts). Keep the pushing bearing within 40 deg [4-107] of the goal-&gt;block axis during the push.</li>
<li><strong>Through the CoG or off-centre.</strong> Rotation follows the lever arm (slope 0.56 deg/s per px, r = 0.87, sign right in 100% of rotating PUSH frames). With |angle error| below 5 deg the human pushes through the CoG (median |lever| 5.7 px); at 10-20 deg the lever is 33.9 px and at 30-45 deg 42.5 px, with the corrective sign in 92.0% and 99.0% of frames. Split by dominant error: position-dominant pushes have median |lever| 25.2 px (40.4% within 15 px of the CoG line), angle-dominant pushes 42.5 px (11.5% through the CoG, 99.4% corrective). Rule: offset the contact point about 42.5 px from the CoG line on the side whose torque reduces the angle error once |angle error| exceeds ~10 deg; below 5 deg push through the CoG.</li>
<li><strong>Slide vs retreat.</strong> Slides are short in-contact re-aims: 2 frames [1-5] at 50 px/s [18-106], heading 64 deg off the inward normal, present in 60% of bouts; a PUSH run is followed by a SLIDE 71% of the time and a SLIDE returns to PUSH 51% of the time, so slide to re-aim while the push direction still points near the goal. Break contact when the push direction has rotated away from the goal: push alignment at release is 89 deg [48-152] (above 45 deg in 91% of releases) versus 26 deg at touch, typically after the |angle error| has been driven to 5 deg. Stop the block before leaving: block speed on the release step is 0.4 px/s (p90 2.2); the release step itself is taken at 76 px/s heading 124 deg off the inward normal (tangential in 61% of releases, straight out in 37%).</li>
<li><strong>Retreat distance.</strong> Retreat steps run at 106 px/s [32-250] but are few (170 frames, 2.7% of all): the pusher opens a gap of only 39 px [17-70] and then swings 89 deg [25-132] around the block (bearing change about the CoG, last contact -&gt; next touch) before touching again 16 frames later.</li>
<li><strong>Choosing the next contact edge.</strong> Push where the inward normal points at the goal: the unfitted goal-normal rule picks the human's edge in 57% of held-out touches (CV) and 49% on the external hold-out (540 touches), against 27% / 23% for the majority edge and 12.5% chance. The fitted contact-point rule (w = 1.79, 2.97, 1.92: alignment, torque x angle error, off-centre penalty) reaches 56% / 51% and the mirrored decision table 54% / 56%; the torque term does not change which edge is chosen but moves the point along it (median perimeter error 24 px vs 32 px for goal-normal, CV). Read off the decision table (goal mirrored to the +x side, majority edge and its count): goal at -90..-45 (bar-top side) deg -&gt; stem_L (4/7) for angle error &lt; -15 deg, stem_tip (25/31) for |angle error| &lt;= 15 deg, stem_R (6/15) for angle error &gt; 15 deg; goal at -45..0 deg -&gt; stem_L (5/7) for angle error &lt; -15 deg, stem_L (9/15) for |angle error| &lt;= 15 deg, bar_bottom_L (4/12) for angle error &gt; 15 deg; goal at 0..45 deg -&gt; bar_top (6/9) for angle error &lt; -15 deg, stem_L (4/9) for |angle error| &lt;= 15 deg, stem_tip (1/2) for angle error &gt; 15 deg; goal at 45..90 (stem-tip side) deg -&gt; bar_top (5/8) for angle error &lt; -15 deg, bar_top (20/25) for |angle error| &lt;= 15 deg, bar_top (5/9) for angle error &gt; 15 deg. Position-dominant errors are served mostly by stem_side (28%) and bar_top (28%), angle-dominant errors by stem_side (38%) and bar_top (21%).</li>
</ol>
<p>Figures: <code>figures/human_pushing/</code>. Per-touch table: <code>figures/human_pushing/touch_events.csv</code>.</p>
<h2 id="8-which-findings-are-physics-and-which-are-the-human">8. Which findings are physics and which are the human</h2>
<p>The environment is a deterministic function of the action stream, so the split can be measured. Re-simulating the PD law (k_p=100, k_v=20, dt=0.01, 10 substeps) in free space from each recorded start, driven only by the recorded actions, reproduces the recorded agent path to 0.00 px (median and p90) on 3065 no-contact frames <strong>and on 3120 in-contact frames</strong>: the pusher is kinematic, the block never acts on it, and the whole agent trajectory is PD(mouse). The mouse stream is the only human quantity; everything else is a filter or a rigid-body response.</p>
<p><strong>Physics, fixed by the reference (would change on any other engine):</strong></p>
<ul>
<li>PD step response to a 100 px command: 29.6 / 61.6 / 80.8 / 95.6 px after 1-4 control steps, no overshoot, peak 320 px/s. A one-step lag and a ~10 px lead (median |target - agent| 10.1 px) are intrinsic, not chosen.</li>
<li>Smoothness: the PD halves the human's acceleration (mouse |accel| medians 224 push / 300 approach / 500 orbit / 1153 retreat px/s^2 vs agent 88 / 147 / 305 / 567) and quarters the jerk. About half of the "gentle" look is filter.</li>
<li>Push depth carries no force: the block is displaced by a moving wall. "Push at 48 px/s, block follows at 32" is kinematic slip, not contact mechanics.</li>
<li>Rotation vs lever arm (r = 0.87, 0.56 deg/s per px, sign correct in 100%) is rigid-body kinematics under the reference's understated moment (3000 vs 7875 geometric); the slope is a property of that typo and of damping = 0.</li>
<li>The block stopping on the release step (0.4 px/s) is damping = 0 annihilating velocity every substep.</li>
</ul>
<p><strong>Human, portable across engines (the decisions):</strong></p>
<table>
<thead>
<tr>
<th>decision</th>
<th>evidence</th>
</tr>
</thead>
<tbody>
<tr>
<td>speed by phase: slow in contact, fast when free</td>
<td>mouse speed medians 45 (push) / 41 (touch) / 51 (slide) vs 114 (orbit) / 184 (retreat) px/s; agent follows the mouse exactly (cos = 1.00 in every role)</td>
</tr>
<tr>
<td>orbit rather than retreat</td>
<td>72% of free motion tangential, retreat 2.7% of frames, standoff 37 px</td>
</tr>
<tr>
<td>head-on incidence</td>
<td>17 deg to the inward normal, 72% within 30 deg</td>
</tr>
<tr>
<td>edge selection by goal geometry</td>
<td>goal-normal rule 57% CV / 49% hold-out vs 9% nearest-edge</td>
</tr>
<tr>
<td>lever offset chosen by angle error</td>
<td>5.7 px at &lt; 5 deg, 42.5 px at 30-45 deg, corrective sign 99%</td>
</tr>
<tr>
<td>release on geometry, not distance</td>
<td>push alignment 26 deg at touch, 89 deg at release</td>
</tr>
<tr>
<td>bout pacing</td>
<td>3 bouts of ~17 frames, 16 frames between</td>
</tr>
</tbody>
</table>
<p><strong>Consequences for the controller.</strong> Section 7's speeds are agent speeds; on a kinematic pusher the controller should emit <em>target-stream</em> speeds (the mouse numbers above) or it double-filters, and on a dynamic pusher the mapping differs again. The rotation gain is reference-only: close the loop on measured angle error instead of feeding forward 0.56 deg/s per px. The edge, lever, orbit, incidence and release rules are the transferable content of this analysis.</p></body></html>