経路探索アルゴリズムを制限された動きに適応させる方法は?


10

エンティティがダイムをオンにできない車のような動きを想像してみてください。話し合いのために、速度が上がると毎秒90度回転できるとしましょう。これにより、多くの場合、最適パスが変更され、したがってパスファインディングが変更されます。「通常の」パスを通過することがまったく不可能になることさえあります。

これを覚えておくことができるパスファインディングアルゴリズムや移動計画アルゴリズムはありますか、または人気のアルゴリズムを適応させる簡単な方法はありますか?


パスファインディングには速度データも含まれますか?たとえば、AからBにX km / h(またはmph)で移動しますか、それとも一定の速度ですか?また、低速で毎秒90度になると、非常に閉じた回転になる可能性があり、おそらく物理的にも不可能です。(4つのホイールすべてがxDを回している場合を除く)
ブライアンH.

@BrianH。だから私は「スピード」で言った。適切な状況では、最小および最大のしきい値が設定されます。しかし、理想的には、速度の変動を含む可能性のある「理想的な」パスをアルゴリズムで探します。
Weckar E.17年

私はこれが非常に興味深い質問だと思っています。+ 1をもらい、いくつかのきちんとした回答を見るのが待ちきれません:)
Brian H.

2
回転速度が制限された動作計画についての以前の質問がありましたが、これも役立つかもしれません。
DMGregory

私はこれをある種の目に見えない壁だと思います。また、ほとんどのパス資金調達アルゴリズムでは、各パスに「重み」があります(たとえば、水中を歩くのは陸上を歩くよりも遅くなります)。そのため、取得が難しいパスに重みを追加できます。これはすべて、車の速度と方向でのみ知ることができます。
the_lotus

回答:


10

非ホロノミック運動計画の素晴らしい世界へようこそ。ラティスグリッドパスプランナーを使用することをお勧めします。他の代替として、kinodynamic RRT、および軌道の最適化を。非ホロノミックシステムには、車、ボート、一輪車など、車両が目的の方向に移動できないあらゆるものが含まれます。これらのシステムの計画はホロノミックシステムよりもはるかに困難であり、2000年までは学術研究の最前線でした。最近では、適切に機能するアルゴリズムから選択する多くのアルゴリズムがあります。

ここに画像の説明を入力してください

これがどのように機能するかです。

状態

車の構成qは、実際には車のx、y位置その向きtを含む3D状態です。A *アルゴリズムのノードは、実際には3Dベクトルです。

class Node
{
    // The position and orientation of the car.
    float x, y, theta;
}

行動

それで、エッジはどうですか?

あなたの車は実際に無限の数の方法でハンドルを回すことができるので、それは少し難しいです。したがって、車が実行できるアクションの数を離散セットAに制限することで、これをラティスグリッドプランナーにアクセス可能にすることができます。簡単にするために、車は加速せず、速度を瞬時に変更できると仮定します。この場合、Aは次のようになります。

class Action
{
    // The direction of the steering wheel.
    float wheelDirection;

    // The speed to go at in m/s.
    float speed;

    // The time that it takes to complete an action in seconds.
    float dt;
}

これで、車がいつでも実行できる個別のアクションセットを作成できます。たとえば、ガスを0.5秒間完全に押しているときのハードライトは次のようになります。

Action turnRight;
turnRight.speed = 1;
turnRight.wheelDirection = 1;
turnRight.dt = 0.5;

車をリバースに入れてバックアップすると、次のようになります。

Action reverse;
reverse.speed = -1;
reverse.wheelDirection = 0;
reverse.dt = 0.5;

そして、アクションのリストは次のようになります。

List<Action> actions = { turnRight, turnLeft, goStraight, reverse ...}

また、ノードで実行されたアクションが新しいノードになる方法を定義する方法も必要です。これは、システムのフォワードダイナミクスと呼ばれます。

// These forward dynamics are for a dubin's car that can change its
// course instantaneously.
Node forwardIntegrate(Node start, Action action) 
{
    // the speed of the car in theta, x and y.
    float thetaDot = action.wheelDirection * TURNING_RADIUS;

    // the discrete timestep in seconds that we integrate at.
    float timestep = 0.001;

    float x = start.x;
    float y = start.y;
    float theta = start.theta;

    // Discrete Euler integration over the length of the action.
    for (float t = 0; t < action.dt; t += timestep)
    {
       theta += timestep * thetaDot;
       float xDot = action.speed * cos(theta);
       float yDot = action.speed * sin(theta);
       x += timestep * xDot;
       y += timestep * yDot;
    }

    return Node(x, y, theta);
}

離散グリッドセル

ここで、ラティスグリッドを構築するために必要なのは、自動車の状態を個別のグリッドセルにハッシュすることだけです。これにより、A *が後に続く個別のノードに変わります。それ以外の場合、A *は2つの車の状態を比較するために実際に同じかどうかを知る方法がないため、これは非常に重要です。整数のグリッドセル値にハッシュすることで、これは簡単になります。

GridCell hashNode(Node node)
{
    GridCell cell;
    cell.x = round(node.x / X_RESOLUTION);
    cell.y = round(node.y / Y_RESOLUTION);
    cell.theta = round(node.theta / THETA_RESOLUTION);
    return cell; 
}

これで、GridCellがノードであり、アクションがノード間のエッジであり、開始と目標がGridCellで表現されるA *プランを実行できます。2つのGridCell間のヒューリスティックは、xとyの距離にシータの角距離を加えたものです。

パスをたどる

GridCellsとActionsの間のパスができたので、車のパスフォロワーを作成できます。グリッドセルは離散しているため、車はセル間をジャンプします。したがって、パスに沿った車の動きを滑らかにする必要があります。ゲームが物理エンジンを使用している場合、これは、車をできるだけパスに近づけようとするステアリングコントローラーを作成することで実現できます。それ以外の場合は、ベジェカーブを使用するか、パス内の最も近い数点を平均するだけで、パスをアニメーション化できます。


優秀な投稿(そして短いです!私はボートでも同様のことをしています-滑りやすい:-)。大藤、より多くのスペースは、そこにある
Stormwindの

4

ほとんどの経路探索アルゴリズムは、ジオメトリの制限なしに任意のグラフで機能します。

したがって、必要なのは、探索された各ノードに車の向きを追加し、実際に接続されているノードを制限することです。


問題は、車が同じノードに別の方向から近づく可能性があることです。これにより、そこからトラバースできる接続に異なる制限が課されます。
Weckar E.17年

6
@WeckarE。しかし、車は同じノードを訪問しません。同じ場所にあるが方向
ラチェットフリーク

3
@WeckarE。それらを2つの別個のノードとして扱います。物理グラフと論理グラフは完全に同じである必要はありません。
BlueRaja-Danny Pflughoeft 2017年

1

私の考え、それらをテストしていない!

  1. A *を最初から最後まで実行し、パスを返します。
  2. パスをループし、曲がりを検出したら、ベジェアルゴリズム(またはそれに類するもの)を使用します。このアルゴリズムは、シーカーの現在の速度を使用して、スムーズな曲がりを作成するノードを予測します。最も近いパスノードに戻ろうとしていることを確認してください。
  3. ターンができれば、素晴らしいですが、できなければ、より遅い速度で繰り返し、より鋭いターンを行います。
  4. 正しいパスが作成されたら、ターンが始まる前にシーカーの速度を調整するパスに戻り、ターンを開始する前に正しい速度に減速します。
  5. ターンがまったくできない場合は、全体をもう一度実行します。作成できないターンのすべての処理済みノードが閉じたリストにあることを確認してください。そうすると、それらは無視されます。そして、ターンの開始点から開始して、パスの成功部分をスキップできますが、場合によっては、最適なパスとは言えないことがあります。

また、最初にパスを完了しなくても、これを実行できるはずです:ergo:A *の間にターンを処理します。これは、おそらくはるかに最適化されますが、問題がありグリッチであることが判明する可能性もあります。自分でテストする時間はありません。

パスファインディング


0

エージェントが車を完全に制御できる場合は、逆の方法で行います。最初から最初から最後まで線を接続し、次にデニスの答えと同様に、各ターンをナビゲートできる速度を把握します。

ただし、固定点からベジェ曲線を描画しないでください。速度の低下を最小限に抑えるには、ライン全体を移動する必要があるため、まず等間隔で追加のノードを挿入し、次にエネルギーの最小化または同様の戦略のために移動します。詳細については、(できればシムまたはセミシムの)レーシングゲームでAIライン生成を調べる必要があります。

AIラインシステムを実行したら、A *検索を実行し、各パスについて少なくとも1コーナー前に進み、時間の見積もりを与えるAIラインを計算します。これがコスト関数になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.