Skip to content

fix(crane_physics): FLYINGボールの着地時間計算でpos_zを考慮するよう修正 - #1390

Merged
HansRobo merged 3 commits into
developfrom
fix/physics-ball-flying-landing-time
Sep 25, 2026
Merged

HansRobo merged 3 commits into
developfrom
fix/physics-ball-flying-landing-time

Conversation

@HansRobo

@HansRobo HansRobo commented May 30, 2026 •

Copy link
Copy Markdown
Member

概要

crane_physics の BallPhysicsModel において、FLYING(チップキック飛行中)状態のボールの着地時間計算が現在高度 pos_z を無視していた不具合を修正します。

問題

ball_physics_model.cpp の getStopTime / getMaxDistance の FLYING 分岐では、着地時間を

landing_time = max(0, -2 * vel_z / gravity)

で算出していました。この式は地面(z=0)から打ち上げたボールの滞空時間を表すものであり、現在のボール高度 pos_z を完全に無視しています。

そのため、高所からの落下中(vel_z <= 0)では landing_time が 0 にクランプされ、飛行中の水平移動が一切加算されません。結果として停止時間・最大到達距離(着地位置)の推定が過小評価されていました。

一方で同クラスの predictPosition / predictVelocity は正しく pos_z を考慮した放物運動の根を解いており、関数間で挙動が不整合な状態でした。

原因

地面(z=0)からの打ち上げ滞空時間の式を流用し、getMaxDistance では引数 pos_z を [[maybe_unused]] として無視、getStopTime ではそもそも pos_z を受け取っていませんでした。

修正内容

  • predictPosition / predictVelocity と同一のロジックで着地時間を解く private ヘルパー getFlyingLandingTime(pos_z, vel_z) を新設しました。
    • z(t) = pos_z + vel_z * t + 0.5 * gravity * t^2 = 0(gravity は負値)の大きい方の根(下降して地面に達する時刻)を返します(当初は正の最小根。下記「追加修正」で変更)。
    • 判別式が負、または正の根が存在しない場合は 0 を返すフォールバックを備えます。
  • getStopTime のシグネチャに pos_z を追加し、FLYING 分岐で当該ヘルパーを使用するよう変更しました。
  • getMaxDistance の引数 pos_z の [[maybe_unused]] を外し、FLYING 分岐で当該ヘルパーを使用するよう変更しました。
  • 呼び出し側 ball_info.cpp の Ball::getStopTime() を新シグネチャ(pos_z 受け渡し)に追従させました。

これにより、飛行中の高度を考慮した着地時間・着地位置が算出され、predictPosition / predictVelocity との整合性が取れます。

検証

  • cwm の独立オーバーレイ worktree 上で、colcon build(--no-rdeps)による crane_physics のコンパイルが成功することを確認しました(Build complete.、エラーなし。既存テストコードの警告のみ)。
  • 当該パッケージのユニットテストを実行し、全件パスを確認しました。
    • colcon test --packages-select crane_physics: 1 package finished
    • colcon test-result --verbose: 118 tests, 0 errors, 0 failures, 0 skipped(gtest 10 件含む)

レビュー観点

  • チップキック飛行中(FLYING、vel_z <= 0 を含む高所落下中)における停止時間・最大到達距離(着地位置)推定の妥当性。
  • getFlyingLandingTime の根の選択(大きい方の根)とフォールバック(判別式負・非正根)の妥当性、および predictPosition / predictVelocity との一貫性。
  • getStopTime のシグネチャ変更に伴う呼び出し側の追従漏れがないこと。

本PRはソースコード監査ワークフローで検出・敵対的検証されたバグに対する単一修正です。

追加修正(レビュー反映)

  • 着地時刻は大きい方の根にした(245a9a53e): gravity < 0 で z(t) は上に凸なので、z(t)=0 の大きい方の根が下降して地面に達する時刻です。当初の「正の最小根」は pos_z < 0 かつ vel_z > 0(トラッカーの z が僅かに負のまま打ち上がった直後など)で上昇中の地面通過を着地としていました。pos_z >= 0 では最小根と同じ値になります。
  • 着地時刻の計算を 1 か所にまとめた(245a9a53e): predictPosition / predictVelocity が持っていた同じ解の公式のコピーを getFlyingLandingTime の呼び出しに置き換えました。これで予測位置・速度が空中から転がりへ切り替わる時刻と、getStopTime / getMaxDistance の着地時刻が一致します。
  • 単位と基準をコメントに明記した: pos_z は接地面を 0 とする高さ [m](上向き正。checkStateTransition も z <= 0 を着地とみなします)、gravity は負値 [m/s²] です(Config の既定値と erforce_ball_physics.yaml / kicker_physics.yaml / calibrated_ball_physics.yaml はすべて -9.81)。
  • Ball::ParabolicPhysics の根の選び方も揃えた(1df8195e8): getGroundIntersection / getGroundPoint も正の最小根を選んでいました。getTimeToReachDistance などは BallPhysicsModel の停止時刻と getGroundIntersection の着地時刻を併用するため、同じく大きい方の根に揃えました。
  • テストを追加した(test_ball_model.cpp): 高所から下降中・地面から上昇中・負の高度から上昇中・判別式が負の 4 ケースの着地時刻と、予測位置・速度が停止時刻・最大到達距離と整合することを固定しました。getGroundIntersection / getGroundPoint の負の高度から上昇するケースも固定しています。
    • 旧式(pos_z を無視する -2 vel_z / gravity)に戻すと 3 件(下降中・負の高度から上昇中・判別式負)が落ちます。地面から上昇中のケースは旧式と同じ値なので落ちません。
    • 最小根に戻すと、負の高度から上昇中のケースが落ちます(BallPhysicsModel と ParabolicPhysics のそれぞれ)。

未対応の関連事項(本 PR の範囲外)

getGroundIntersection には、BallPhysicsModel と食い違う挙動がまだ 3 つあります。どれも既存テスト(GetGroundPointAlreadyOnGround / GetGroundPointNoGroundImpact)で固定された挙動なので、この PR では変えていません。

  • |z0| < 1e-6 なら上昇中でも着地時刻 0 を返す。BallPhysicsModel は 2 vel_z / |g| を返す。
  • 判別式が負のとき最高点の時刻を返す。BallPhysicsModel は 0 を返す。
  • 重力が -9.81 固定で、config_.gravity を見ない。

これにより、FLYING の getTimeToReachDistance では z≈0 で上昇中のとき、飛行区間の上限(getGroundIntersection 由来)と探索上限の t_max(getStopTime 由来)がずれます。

検証(追加分)

各コミットで verify(colcon build・全パッケージの colcon test・差分ファイルへの pre-commit)を実行し、origin/develop に対する失敗集合の差分は空でした。

@HansRobo

Copy link
Copy Markdown
Member Author

LGTM

着地時刻の計算が getFlyingLandingTime と predictPosition / predictVelocity の
3 箇所に重複しており、いずれも z(t)=0 の正の最小根を選んでいた。pos_z < 0 かつ
vel_z > 0 のとき最小根は上昇中の地面通過であり、着地ではない。

- getFlyingLandingTime を大きい方の根(下降して地面に達する時刻)を返すよう変更
  (pos_z >= 0 の場合は従来と同じ値)
- predictPosition / predictVelocity も同じヘルパーを使い、停止時刻・最大到達距離と
  空中→転がりの境目を一致させる
- pos_z は接地面を 0 とする高さ、gravity は負値 [m/s²] であることをコメントで明記
- 高所から下降中・地面から上昇中・負の高度から上昇中・判別式が負のケースと、
  予測位置・速度と停止時刻・最大到達距離の整合をテストで固定
Ball::ParabolicPhysics::getGroundIntersection / getGroundPoint も z(t)=0 の正の最小根を
選んでおり、z0 < 0 かつ vz0 > 0 では上昇中の地面通過を着地としていた。
getTimeToReachDistance などは BallPhysicsModel の停止時刻と getGroundIntersection の
着地時刻を併用するため、BallPhysicsModel::getFlyingLandingTime と同じく大きい方の根
(下降して地面に達する時刻)に揃える。z0 >= 0 では従来と同じ値になる。

z0≈0 で 0 を返す分岐・判別式が負で最高点を返す分岐・重力 -9.81 固定は既存テストで
固定された挙動なので変えていない。負の高度から上昇するケースをテストで固定した。
@HansRobo
HansRobo force-pushed the fix/physics-ball-flying-landing-time branch from 1df8195 to 04b32f6 Compare September 25, 2026 17:37
@HansRobo
HansRobo merged commit e51881a into develop Sep 25, 2026
7 of 8 checks passed
@HansRobo
HansRobo deleted the fix/physics-ball-flying-landing-time branch September 25, 2026 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant