[Python]PythonRoboticsのダイクストラ法を読んで少し解読してみた

#PythonRobotics：ダイクストラ法
参考文献:PythonRobotics（Atsushi Sakaiさん）
この方のサイトはとてもわかりやすくいつも勉強になっております。
https://github.com/AtsushiSakai/PythonRobotics
ダイクストラ法
https://github.com/AtsushiSakai/PythonRobotics/tree/master/PathPlanning/Dijkstra
Pythonでロボット工学を学ぶ人にとってはとても参考になるサイトだと思います。
今回はその中で、ダイクストラ法について勉強の記録として書きたいと思います。
この行為が著作権とかに触れる様でしたら、すぐさま辞めようと思うのでご教授お願い致します。
まだ内容についても理解度不足なので、ご教授頂ける方がいましたら何卒宜しくお願い致します。
プログラムはこちらから参考にしております。
https://github.com/AtsushiSakai/PythonRobotics/tree/master/PathPlanning/Dijkstra


##メイン文
１．スタート、ゴール地点、グリッド、ロボットサイズを任意に決める。
２．障害物を任意に設置する。
３．dijkstra_planningでダイクストラ法を計算。

```python:MeRT.py
"""
Dijkstra grid based planning
author: Atsushi Sakai(@Atsushi_twi)
"""
def main():
    print(__file__ + " start!!")

    # start and goal position
    sx = 10.0  # [m]
    sy = 10.0  # [m]
    gx = 50.0  # [m]
    gy = 50.0  # [m]
    grid_size = 1.0  # [m]
    robot_size = 1.0  # [m]

    ox = []
    oy = []

    for i in range(60):
        ox.append(i)
        oy.append(0.0)
    for i in range(60):
        ox.append(60.0)
        oy.append(i)
    for i in range(61):
        ox.append(i)
        oy.append(60.0)
    for i in range(61):
        ox.append(0.0)
        oy.append(i)
    for i in range(40):
        ox.append(20.0)
        oy.append(i)
    for i in range(40):
        ox.append(40.0)
        oy.append(60.0 - i)

    if show_animation:
        plt.plot(ox, oy, ".k")
        plt.plot(sx, sy, "xr")
        plt.plot(gx, gy, "xb")
        plt.grid(True)
        plt.axis("equal")

    rx, ry = dijkstra_planning(sx, sy, gx, gy, ox, oy, grid_size, robot_size)

    if show_animation:
        plt.plot(rx, ry, "-r")
        plt.show()
```

##dijkstra_planning関数の説明
resoはgrid_size。rrはrobot_size。を意味する。（文字変わってるのに注意）

```python:MeRT.py
def dijkstra_planning(sx, sy, gx, gy, ox, oy, reso, rr):
    """
    gx: goal x position [m]
    gx: goal x position [m]
    ox: x position list of Obstacles [m]
    oy: y position list of Obstacles [m]
    reso: grid resolution [m]
    rr: robot radius[m]
    """

    nstart = Node(round(sx / reso), round(sy / reso), 0.0, -1)
    ngoal = Node(round(gx / reso), round(gy / reso), 0.0, -1)
    ox = [iox / reso for iox in ox]
    oy = [ioy / reso for ioy in oy]
```

###calc_obstacle_map
calc_obstacle_mapからobmap, minx, miny, maxx, maxy, xw, ywを生成。

```python:MeRT.py
    obmap, minx, miny, maxx, maxy, xw, yw = calc_obstacle_map(ox, oy, reso, rr)
```
calc_obstacle_map
1.最大、最小の障害物のxyを取ってくる。
2.xyの最大最小値を引く。
3.obstacle mapをつくる。
 3-1 minxからmaxxの間で、minyからmaxyの間で、zip(ox, oy)｛これは要素をまとめる｝する。
vrはrrを意味する。（文字変わってるのに注意）



```python:MeRT.py
def calc_obstacle_map(ox, oy, reso, vr):

    minx = round(min(ox))
    miny = round(min(oy))
    maxx = round(max(ox))
    maxy = round(max(oy))
    #  print("minx:", minx)
    #  print("miny:", miny)
    #  print("maxx:", maxx)
    #  print("maxy:", maxy)

    xwidth = round(maxx - minx)
    ywidth = round(maxy - miny)
    #  print("xwidth:", xwidth)
    #  print("ywidth:", ywidth)

    # obstacle map generation
    obmap = [[False for i in range(xwidth)] for i in range(ywidth)]
    for ix in range(xwidth):
        x = ix + minx
        for iy in range(ywidth):
            y = iy + miny
            #  print(x, y)
            for iox, ioy in zip(ox, oy):
                d = math.sqrt((iox - x)**2 + (ioy - y)**2)
                if d <= vr / reso:
                    obmap[ix][iy] = True
                    break

    return obmap, minx, miny, maxx, maxy, xwidth, ywidth
```


###次の行動

```python:MeRT.py
    motion = get_motion_model()
```

現在のノードから次のノードのコスト決め。
移動の仕方とコストの決めている。

```python:MeRT.py

def get_motion_model():
    # dx, dy, cost
    motion = [[1, 0, 1],
              [0, 1, 1],
              [-1, 0, 1],
              [0, -1, 1],
              [-1, -1, math.sqrt(2)],
              [-1, 1, math.sqrt(2)],
              [1, -1, math.sqrt(2)],
              [1, 1, math.sqrt(2)]]

    return motion
```

###openとcloseリスト作成

```python:MeRT.py
def calc_index(node, xwidth, xmin, ymin):
    return (node.y - ymin) * xwidth + (node.x - xmin)
```
calc_indexでスタート
ダイクストラ法の各条件を計算。
ゴールまで計算する。

```python:MeRT.py
    openset, closedset = dict(), dict()
    openset[calc_index(nstart, xw, minx, miny)] = nstart

    while 1:
        c_id = min(openset, key=lambda o: openset[o].cost)
        current = openset[c_id]
        #  print("current", current)

        # show graph
        if show_animation:
            plt.plot(current.x * reso, current.y * reso, "xc")
            if len(closedset.keys()) % 10 == 0:
                plt.pause(0.001)

        if current.x == ngoal.x and current.y == ngoal.y:
            print("Find goal")
            ngoal.pind = current.pind
            ngoal.cost = current.cost
            break

        # Remove the item from the open set
        del openset[c_id]
        # Add it to the closed set
        closedset[c_id] = current

        # expand search grid based on motion model
        for i, _ in enumerate(motion):
            node = Node(current.x + motion[i][0], current.y + motion[i][1],
                        current.cost + motion[i][2], c_id)
            n_id = calc_index(node, xw, minx, miny)

            if not verify_node(node, obmap, minx, miny, maxx, maxy):
                continue

            if n_id in closedset:
                continue
            # Otherwise if it is already in the open set
            if n_id in openset:
                if openset[n_id].cost > node.cost:
                    openset[n_id].cost = node.cost
                    openset[n_id].pind = c_id
            else:
                openset[n_id] = node

    rx, ry = calc_final_path(ngoal, closedset, reso)

    return rx, ry
```


```python:MeRT.py

class Node:

    def __init__(self, x, y, cost, pind):
        self.x = x
        self.y = y
        self.cost = cost
        self.pind = pind

    def __str__(self):
        return str(self.x) + "," + str(self.y) + "," + str(self.cost) + "," + str(self.pind)
```


```python:MeRT.py
def calc_final_path(ngoal, closedset, reso):
    # generate final course
    rx, ry = [ngoal.x * reso], [ngoal.y * reso]
    pind = ngoal.pind
    while pind != -1:
        n = closedset[pind]
        rx.append(n.x * reso)
        ry.append(n.y * reso)
        pind = n.pind

    return rx, ry
```

```python:MeRT.py
def verify_node(node, obmap, minx, miny, maxx, maxy):

    if obmap[node.x][node.y]:
        return False

    if node.x < minx:
        return False
    elif node.y < miny:
        return False
    elif node.x > maxx:
        return False
    elif node.y > maxy:
        return False

    return True
```

大雑把ですが、メモ程度に記録しました。
少しずつ理解度を上げたいと思います。