hasht's notes

ゲームAIやUnityの話題

RVOによる衝突回避アルゴリズム

衝突回避のアルゴリズムの一つである RVO (Reciprocal Velocity Obstacles) について、日本語の資料が見当たらないので書いておく。

元論文:http://gamma.cs.unc.edu/RVO/icra2008.pdf

背景

先行のアルゴリズムとして VO (Velocity Obstacles) があったが、VOではエージェントの速度が振動する挙動があった。RVOはその問題を解消するものとなっている。

エージェントA,Bが速度  v_A, v_B で位置  p_A, p_B にいるとして、それぞれの位置を基準としたA,B上の点(位置ベクトル)の集合を  R_A, R_B とする。  p_A + R_A = \{ P_A + r_A \ |\ r_A \in R_A \} で現在のA上の点の集合を表すことができる。 時間が  t だけ経過した後は  p_A + t v_A + R_A となるので、A,Bが衝突することは

 \displaystyle
(p_A + t v_A + R_A) \cap (p_B + t v_B + R_B) \neq \emptyset

が成り立つことと言える。これは

 \displaystyle
p_A + t v_A + r_A = p_B + t v_B + r_B

となる  r_A \in R_A, r_B \in R_B がそれぞれ存在することと同値で、

 \displaystyle
p_A + t (v_A - v_B) = p_B + r_B - r_A

と整理できる。つまり  p_A から相対速度  v_A - v_B の方向に延びる半直線(時間は巻き戻らないので  t > 0 )と、  p_B + R_B - R_A (Aの形の情報をBの方に押しつけたもの)が交わるとき、AとBは衝突する。 そのような  v_A の集合を  VO^{A}_{B}(v_B) で表し、各々このVOの外側の速度を選ぶことによる衝突回避がVOによるアルゴリズムである。

f:id:hasht:20180419191215p:plain

振動というのは、例えばA,Bが互いに逆方向に直進したくて向かい合っていると、そのままでは衝突するので互いにVOの外の速度を選び直すが、すると今度は衝突しないので直進に戻し、すると衝突するので……といった形でループが発生するケースが起こる。

f:id:hasht:20180419191926p:plain

アルゴリズム

基本的なアイデアは「互いに同じアルゴリズムを使うのだから、半分だけ避ければよい」というものである。(Game AI Pro 3 p.238)

具体的には、現在の速度  v_A とVO外の速度  v'_A の平均を選ぶようにする。

 \displaystyle
v''_A = \frac{ v_A + v'_A }{ 2 }

これは  2v''_A - v_A = v'_A となるので、  2v''_A - v_A \in VO^{A}_{B}(v_B) が成り立つ  v''_A  RVO^{A}_{B}(v_B, v_A) の要素となる。逆にRVOの外側から速度を選べば、「半分だけ避ける」ことができる。

f:id:hasht:20180419192551p:plain

エージェントが多数の場合は常にRVOの外側を選ぶことはできるとは限らないので、衝突までの時間  tc_A(v'_A) と、期待する速度  v^{\rm pref}_{A} (衝突がない場合に出したい速度)により

 \displaystyle
    penalty_A(v'_A) = w_A \frac{1}{ tc_A(v'_A) } + \| v^{\rm pref}_{A} - v'_A \|

を最小化する  v'_A を選択する(  w_A はどのくらい頑張って衝突回避するかのパラメータ)。

デモ

JavaScriptでの実装:https://jsfiddle.net/86jh1Lva/

f:id:hasht:20180419192631g:plain

黒い点で  v^{\rm pref}_{i} を、実線で実際に選ばれた  v'_i を示している。